Loading drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ obj-$(CONFIG_SPECTRA_CAMERA) += top_tpg/ ifdef CONFIG_SPECTRA_CAMERA_TFE obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ ppi_hw/ endif ifdef CONFIG_SPECTRA_CAMERA_IFE Loading drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile 0 → 100644 +14 −0 Original line number Diff line number Diff line # 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_cdm/ 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_csid_ppi_dev.o cam_csid_ppi_core.o cam_csid_ppi100.o drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c 0 → 100644 +50 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include "cam_csid_ppi_core.h" #include "cam_csid_ppi100.h" #include "cam_csid_ppi_dev.h" #define CAM_PPI_DRV_NAME "ppi_100" #define CAM_PPI_VERSION_V100 0x10000000 static struct cam_csid_ppi_hw_info cam_csid_ppi100_hw_info = { .ppi_reg = &cam_csid_ppi_100_reg_offset, }; static const struct of_device_id cam_csid_ppi100_dt_match[] = { { .compatible = "qcom,ppi100", .data = &cam_csid_ppi100_hw_info, }, {} }; MODULE_DEVICE_TABLE(of, cam_csid_ppi100_dt_match); static struct platform_driver cam_csid_ppi100_driver = { .probe = cam_csid_ppi_probe, .remove = cam_csid_ppi_remove, .driver = { .name = CAM_PPI_DRV_NAME, .of_match_table = cam_csid_ppi100_dt_match, .suppress_bind_attrs = true, }, }; static int __init cam_csid_ppi100_init_module(void) { return platform_driver_register(&cam_csid_ppi100_driver); } static void __exit cam_csid_ppi100_exit_module(void) { platform_driver_unregister(&cam_csid_ppi100_driver); } module_init(cam_csid_ppi100_init_module); MODULE_DESCRIPTION("CAM CSID_PPI100 driver"); MODULE_LICENSE("GPL v2"); drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h 0 → 100644 +25 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSID_PPI_100_H_ #define _CAM_CSID_PPI_100_H_ #include "cam_csid_ppi_core.h" static struct cam_csid_ppi_reg_offset cam_csid_ppi_100_reg_offset = { .ppi_hw_version_addr = 0, .ppi_module_cfg_addr = 0x60, .ppi_irq_status_addr = 0x68, .ppi_irq_mask_addr = 0x6c, .ppi_irq_set_addr = 0x70, .ppi_irq_clear_addr = 0x74, .ppi_irq_cmd_addr = 0x78, .ppi_rst_cmd_addr = 0x7c, .ppi_test_bus_ctrl_addr = 0x1f4, .ppi_debug_addr = 0x1f8, .ppi_spare_addr = 0x1fc, }; #endif /*_CAM_CSID_PPI_100_H_ */ drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c 0 → 100644 +392 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #include <linux/iopoll.h> #include <linux/slab.h> #include <media/cam_defs.h> #include "cam_csid_ppi_core.h" #include "cam_csid_ppi_dev.h" #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_io_util.h" static int cam_csid_ppi_reset(struct cam_csid_ppi_hw *ppi_hw) { struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; int rc = 0; uint32_t status; soc_info = &ppi_hw->hw_info->soc_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; CAM_DBG(CAM_ISP, "PPI:%d reset", ppi_hw->hw_intf->hw_idx); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_set_addr); cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_rst_cmd_addr); cam_io_w_mb(PPI_IRQ_CMD_SET, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_status_addr, status, (status & 0x1) == 0x1, 1000, 500000); CAM_DBG(CAM_ISP, "PPI:%d reset status %d", ppi_hw->hw_intf->hw_idx, status); if (rc < 0) { CAM_ERR(CAM_ISP, "PPI:%d ppi_reset fail rc = %d status = %d", ppi_hw->hw_intf->hw_idx, rc, status); return rc; } cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); return 0; } static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) { int rc = 0; int32_t i; uint64_t val; const struct cam_csid_ppi_reg_offset *ppi_reg; struct cam_hw_soc_info *soc_info; uint32_t err_irq_mask; ppi_reg = ppi_hw->ppi_info->ppi_reg; soc_info = &ppi_hw->hw_info->soc_info; CAM_DBG(CAM_ISP, "PPI:%d init PPI HW", ppi_hw->hw_intf->hw_idx); ppi_hw->hw_info->open_count++; if (ppi_hw->hw_info->open_count > 1) { CAM_DBG(CAM_ISP, "PPI:%d dual vfe already enabled", ppi_hw->hw_intf->hw_idx); return 0; } for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_clk_enable(soc_info->clk[i], soc_info->clk_name[i], 0); if (rc) goto clk_disable; } rc = cam_csid_ppi_reset(ppi_hw); if (rc) goto clk_disable; err_irq_mask = PPI_IRQ_FIFO0_OVERFLOW | PPI_IRQ_FIFO1_OVERFLOW | PPI_IRQ_FIFO2_OVERFLOW; cam_io_w_mb(err_irq_mask, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); rc = cam_soc_util_irq_enable(soc_info); if (rc) goto clk_disable; cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_hw_version_addr); CAM_DBG(CAM_ISP, "PPI:%d PPI HW version: 0x%x", ppi_hw->hw_intf->hw_idx, val); ppi_hw->device_enabled = 1; return 0; clk_disable: for (--i; i >= 0; i--) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); ppi_hw->hw_info->open_count--; return rc; } static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw) { int rc = 0; int i; struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; uint64_t ppi_cfg_val = 0; CAM_DBG(CAM_ISP, "PPI:%d De-init PPI HW", ppi_hw->hw_intf->hw_idx); if (!ppi_hw->hw_info->open_count) { CAM_WARN(CAM_ISP, "ppi[%d] unbalanced disable hw", ppi_hw->hw_intf->hw_idx); return -EINVAL; } ppi_hw->hw_info->open_count--; if (ppi_hw->hw_info->open_count) return rc; soc_info = &ppi_hw->hw_info->soc_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; CAM_DBG(CAM_ISP, "Calling PPI Reset"); cam_csid_ppi_reset(ppi_hw); CAM_DBG(CAM_ISP, "PPI Reset Done"); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); cam_soc_util_irq_disable(soc_info); for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); ppi_hw->device_enabled = 0; for (i = 0; i < soc_info->num_clk; i++) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); return rc; } static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, uint32_t arg_size) { int i, rc = 0; uint32_t num_lanes; uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; uint32_t cphy; bool dl0, dl1; uint32_t ppi_cfg_val = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; const struct cam_csid_ppi_reg_offset *ppi_reg; struct cam_hw_soc_info *soc_info; struct cam_csid_ppi_cfg ppi_cfg; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_csid_ppi_cfg))) { CAM_ERR(CAM_ISP, "PPI: Invalid args"); rc = -EINVAL; goto end; } dl0 = dl1 = false; ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; ppi_cfg = *((struct cam_csid_ppi_cfg *)init_args); rc = cam_csid_ppi_enable_hw(ppi_hw); if (rc) goto end; num_lanes = ppi_cfg.lane_num; cphy = ppi_cfg.lane_type; CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", ppi_cfg.lane_cfg, num_lanes, cphy); for (i = 0; i < num_lanes; i++) { lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); } if (num_lanes) { if (cphy) { for (i = 0; i < num_lanes; i++) { ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); } } else { if (dl0) ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); if (dl1) ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); } } else { CAM_ERR(CAM_ISP, "Number of lanes to enable is cannot be zero"); rc = -1; goto end; } CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); soc_info = &ppi_hw->hw_info->soc_info; cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); CAM_DBG(CAM_ISP, "ppi cfg 0x%x", cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr)); end: return rc; } static int cam_csid_ppi_deinit_hw(void *hw_priv, void *deinit_args, uint32_t arg_size) { int rc = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; CAM_DBG(CAM_ISP, "Enter"); if (!hw_priv) { CAM_ERR(CAM_ISP, "PPI:Invalid arguments"); rc = -EINVAL; goto end; } ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; CAM_DBG(CAM_ISP, "Disabling PPI Hw"); rc = cam_csid_ppi_disable_hw(ppi_hw); if (rc < 0) CAM_DBG(CAM_ISP, "Exit with %d", rc); end: return rc; } int cam_csid_ppi_hw_probe_init(struct cam_hw_intf *ppi_hw_intf, uint32_t ppi_idx) { int rc = -EINVAL; struct cam_hw_info *ppi_hw_info; struct cam_csid_ppi_hw *csid_ppi_hw = NULL; if (ppi_idx >= CAM_CSID_PPI_HW_MAX) { CAM_ERR(CAM_ISP, "Invalid ppi index:%d", ppi_idx); goto err; } ppi_hw_info = (struct cam_hw_info *) ppi_hw_intf->hw_priv; csid_ppi_hw = (struct cam_csid_ppi_hw *) ppi_hw_info->core_info; csid_ppi_hw->hw_intf = ppi_hw_intf; csid_ppi_hw->hw_info = ppi_hw_info; CAM_DBG(CAM_ISP, "type %d index %d", csid_ppi_hw->hw_intf->hw_type, ppi_idx); rc = cam_csid_ppi_init_soc_resources(&csid_ppi_hw->hw_info->soc_info, cam_csid_ppi_irq, csid_ppi_hw); if (rc < 0) { CAM_ERR(CAM_ISP, "PPI:%d Failed to init_soc", ppi_idx); goto err; } csid_ppi_hw->hw_intf->hw_ops.init = cam_csid_ppi_init_hw; csid_ppi_hw->hw_intf->hw_ops.deinit = cam_csid_ppi_deinit_hw; return 0; err: return rc; } int cam_csid_ppi_init_soc_resources(struct cam_hw_soc_info *soc_info, irq_handler_t ppi_irq_handler, void *irq_data) { int rc = 0; rc = cam_soc_util_get_dt_properties(soc_info); if (rc) { CAM_ERR(CAM_ISP, "PPI: Failed to get dt properties"); goto end; } rc = cam_soc_util_request_platform_resource(soc_info, ppi_irq_handler, irq_data); if (rc) { CAM_ERR(CAM_ISP, "PPI: Error Request platform resources failed rc=%d", rc); goto err; } end: return rc; err: cam_soc_util_release_platform_resource(soc_info); return rc; } irqreturn_t cam_csid_ppi_irq(int irq_num, void *data) { uint32_t irq_status = 0; uint32_t i, ppi_cfg_val = 0; bool fatal_err_detected = false; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; if (!data) { CAM_ERR(CAM_ISP, "PPI: Invalid arguments"); return IRQ_HANDLED; } ppi_hw = (struct cam_csid_ppi_hw *)data; ppi_reg = ppi_hw->ppi_info->ppi_reg; soc_info = &ppi_hw->hw_info->soc_info; if (ppi_hw->device_enabled != 1) goto ret; irq_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_status_addr); cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); CAM_DBG(CAM_ISP, "PPI %d irq status 0x%x", ppi_hw->hw_intf->hw_idx, irq_status); if (irq_status & PPI_IRQ_RST_DONE) { CAM_DBG(CAM_ISP, "PPI Reset Done"); goto ret; } if ((irq_status & PPI_IRQ_FIFO0_OVERFLOW) || (irq_status & PPI_IRQ_FIFO1_OVERFLOW) || (irq_status & PPI_IRQ_FIFO2_OVERFLOW)) { fatal_err_detected = true; goto handle_fatal_error; } handle_fatal_error: if (fatal_err_detected) { CAM_ERR(CAM_ISP, "PPI: %d irq_status:0x%x", ppi_hw->hw_intf->hw_idx, irq_status); for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); } ret: CAM_DBG(CAM_ISP, "IRQ Handling exit"); return IRQ_HANDLED; } int cam_csid_ppi_hw_deinit(struct cam_csid_ppi_hw *csid_ppi_hw) { if (!csid_ppi_hw) { CAM_ERR(CAM_ISP, "Invalid param"); return -EINVAL; } return cam_soc_util_release_platform_resource( &csid_ppi_hw->hw_info->soc_info); } Loading
drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ obj-$(CONFIG_SPECTRA_CAMERA) += top_tpg/ ifdef CONFIG_SPECTRA_CAMERA_TFE obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ obj-$(CONFIG_SPECTRA_CAMERA) += tfe_csid_hw/ tfe_hw/ ppi_hw/ endif ifdef CONFIG_SPECTRA_CAMERA_IFE Loading
drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/Makefile 0 → 100644 +14 −0 Original line number Diff line number Diff line # 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_cdm/ 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_csid_ppi_dev.o cam_csid_ppi_core.o cam_csid_ppi100.o
drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.c 0 → 100644 +50 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include "cam_csid_ppi_core.h" #include "cam_csid_ppi100.h" #include "cam_csid_ppi_dev.h" #define CAM_PPI_DRV_NAME "ppi_100" #define CAM_PPI_VERSION_V100 0x10000000 static struct cam_csid_ppi_hw_info cam_csid_ppi100_hw_info = { .ppi_reg = &cam_csid_ppi_100_reg_offset, }; static const struct of_device_id cam_csid_ppi100_dt_match[] = { { .compatible = "qcom,ppi100", .data = &cam_csid_ppi100_hw_info, }, {} }; MODULE_DEVICE_TABLE(of, cam_csid_ppi100_dt_match); static struct platform_driver cam_csid_ppi100_driver = { .probe = cam_csid_ppi_probe, .remove = cam_csid_ppi_remove, .driver = { .name = CAM_PPI_DRV_NAME, .of_match_table = cam_csid_ppi100_dt_match, .suppress_bind_attrs = true, }, }; static int __init cam_csid_ppi100_init_module(void) { return platform_driver_register(&cam_csid_ppi100_driver); } static void __exit cam_csid_ppi100_exit_module(void) { platform_driver_unregister(&cam_csid_ppi100_driver); } module_init(cam_csid_ppi100_init_module); MODULE_DESCRIPTION("CAM CSID_PPI100 driver"); MODULE_LICENSE("GPL v2");
drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi100.h 0 → 100644 +25 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CSID_PPI_100_H_ #define _CAM_CSID_PPI_100_H_ #include "cam_csid_ppi_core.h" static struct cam_csid_ppi_reg_offset cam_csid_ppi_100_reg_offset = { .ppi_hw_version_addr = 0, .ppi_module_cfg_addr = 0x60, .ppi_irq_status_addr = 0x68, .ppi_irq_mask_addr = 0x6c, .ppi_irq_set_addr = 0x70, .ppi_irq_clear_addr = 0x74, .ppi_irq_cmd_addr = 0x78, .ppi_rst_cmd_addr = 0x7c, .ppi_test_bus_ctrl_addr = 0x1f4, .ppi_debug_addr = 0x1f8, .ppi_spare_addr = 0x1fc, }; #endif /*_CAM_CSID_PPI_100_H_ */
drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c 0 → 100644 +392 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. */ #include <linux/iopoll.h> #include <linux/slab.h> #include <media/cam_defs.h> #include "cam_csid_ppi_core.h" #include "cam_csid_ppi_dev.h" #include "cam_soc_util.h" #include "cam_debug_util.h" #include "cam_io_util.h" static int cam_csid_ppi_reset(struct cam_csid_ppi_hw *ppi_hw) { struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; int rc = 0; uint32_t status; soc_info = &ppi_hw->hw_info->soc_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; CAM_DBG(CAM_ISP, "PPI:%d reset", ppi_hw->hw_intf->hw_idx); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_set_addr); cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_rst_cmd_addr); cam_io_w_mb(PPI_IRQ_CMD_SET, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_status_addr, status, (status & 0x1) == 0x1, 1000, 500000); CAM_DBG(CAM_ISP, "PPI:%d reset status %d", ppi_hw->hw_intf->hw_idx, status); if (rc < 0) { CAM_ERR(CAM_ISP, "PPI:%d ppi_reset fail rc = %d status = %d", ppi_hw->hw_intf->hw_idx, rc, status); return rc; } cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); return 0; } static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) { int rc = 0; int32_t i; uint64_t val; const struct cam_csid_ppi_reg_offset *ppi_reg; struct cam_hw_soc_info *soc_info; uint32_t err_irq_mask; ppi_reg = ppi_hw->ppi_info->ppi_reg; soc_info = &ppi_hw->hw_info->soc_info; CAM_DBG(CAM_ISP, "PPI:%d init PPI HW", ppi_hw->hw_intf->hw_idx); ppi_hw->hw_info->open_count++; if (ppi_hw->hw_info->open_count > 1) { CAM_DBG(CAM_ISP, "PPI:%d dual vfe already enabled", ppi_hw->hw_intf->hw_idx); return 0; } for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_clk_enable(soc_info->clk[i], soc_info->clk_name[i], 0); if (rc) goto clk_disable; } rc = cam_csid_ppi_reset(ppi_hw); if (rc) goto clk_disable; err_irq_mask = PPI_IRQ_FIFO0_OVERFLOW | PPI_IRQ_FIFO1_OVERFLOW | PPI_IRQ_FIFO2_OVERFLOW; cam_io_w_mb(err_irq_mask, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); rc = cam_soc_util_irq_enable(soc_info); if (rc) goto clk_disable; cam_io_w_mb(PPI_RST_CONTROL, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); val = cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_hw_version_addr); CAM_DBG(CAM_ISP, "PPI:%d PPI HW version: 0x%x", ppi_hw->hw_intf->hw_idx, val); ppi_hw->device_enabled = 1; return 0; clk_disable: for (--i; i >= 0; i--) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); ppi_hw->hw_info->open_count--; return rc; } static int cam_csid_ppi_disable_hw(struct cam_csid_ppi_hw *ppi_hw) { int rc = 0; int i; struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; uint64_t ppi_cfg_val = 0; CAM_DBG(CAM_ISP, "PPI:%d De-init PPI HW", ppi_hw->hw_intf->hw_idx); if (!ppi_hw->hw_info->open_count) { CAM_WARN(CAM_ISP, "ppi[%d] unbalanced disable hw", ppi_hw->hw_intf->hw_idx); return -EINVAL; } ppi_hw->hw_info->open_count--; if (ppi_hw->hw_info->open_count) return rc; soc_info = &ppi_hw->hw_info->soc_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; CAM_DBG(CAM_ISP, "Calling PPI Reset"); cam_csid_ppi_reset(ppi_hw); CAM_DBG(CAM_ISP, "PPI Reset Done"); cam_io_w_mb(0, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_mask_addr); cam_soc_util_irq_disable(soc_info); for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); ppi_hw->device_enabled = 0; for (i = 0; i < soc_info->num_clk; i++) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); return rc; } static int cam_csid_ppi_init_hw(void *hw_priv, void *init_args, uint32_t arg_size) { int i, rc = 0; uint32_t num_lanes; uint32_t lanes[CAM_CSID_PPI_HW_MAX] = {0, 0, 0, 0}; uint32_t cphy; bool dl0, dl1; uint32_t ppi_cfg_val = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; const struct cam_csid_ppi_reg_offset *ppi_reg; struct cam_hw_soc_info *soc_info; struct cam_csid_ppi_cfg ppi_cfg; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_csid_ppi_cfg))) { CAM_ERR(CAM_ISP, "PPI: Invalid args"); rc = -EINVAL; goto end; } dl0 = dl1 = false; ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; ppi_reg = ppi_hw->ppi_info->ppi_reg; ppi_cfg = *((struct cam_csid_ppi_cfg *)init_args); rc = cam_csid_ppi_enable_hw(ppi_hw); if (rc) goto end; num_lanes = ppi_cfg.lane_num; cphy = ppi_cfg.lane_type; CAM_DBG(CAM_ISP, "lane_cfg 0x%x | num_lanes 0x%x | lane_type 0x%x", ppi_cfg.lane_cfg, num_lanes, cphy); for (i = 0; i < num_lanes; i++) { lanes[i] = ppi_cfg.lane_cfg & (0x3 << (4 * i)); (lanes[i] < 2) ? (dl0 = true) : (dl1 = true); CAM_DBG(CAM_ISP, "lanes[%d] %d", i, lanes[i]); } if (num_lanes) { if (cphy) { for (i = 0; i < num_lanes; i++) { ppi_cfg_val |= PPI_CFG_CPHY_DLX_SEL(lanes[i]); ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(lanes[i]); } } else { if (dl0) ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(0); if (dl1) ppi_cfg_val |= PPI_CFG_CPHY_DLX_EN(1); } } else { CAM_ERR(CAM_ISP, "Number of lanes to enable is cannot be zero"); rc = -1; goto end; } CAM_DBG(CAM_ISP, "ppi_cfg_val 0x%x", ppi_cfg_val); soc_info = &ppi_hw->hw_info->soc_info; cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); CAM_DBG(CAM_ISP, "ppi cfg 0x%x", cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr)); end: return rc; } static int cam_csid_ppi_deinit_hw(void *hw_priv, void *deinit_args, uint32_t arg_size) { int rc = 0; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_info *ppi_hw_info; CAM_DBG(CAM_ISP, "Enter"); if (!hw_priv) { CAM_ERR(CAM_ISP, "PPI:Invalid arguments"); rc = -EINVAL; goto end; } ppi_hw_info = (struct cam_hw_info *)hw_priv; ppi_hw = (struct cam_csid_ppi_hw *)ppi_hw_info->core_info; CAM_DBG(CAM_ISP, "Disabling PPI Hw"); rc = cam_csid_ppi_disable_hw(ppi_hw); if (rc < 0) CAM_DBG(CAM_ISP, "Exit with %d", rc); end: return rc; } int cam_csid_ppi_hw_probe_init(struct cam_hw_intf *ppi_hw_intf, uint32_t ppi_idx) { int rc = -EINVAL; struct cam_hw_info *ppi_hw_info; struct cam_csid_ppi_hw *csid_ppi_hw = NULL; if (ppi_idx >= CAM_CSID_PPI_HW_MAX) { CAM_ERR(CAM_ISP, "Invalid ppi index:%d", ppi_idx); goto err; } ppi_hw_info = (struct cam_hw_info *) ppi_hw_intf->hw_priv; csid_ppi_hw = (struct cam_csid_ppi_hw *) ppi_hw_info->core_info; csid_ppi_hw->hw_intf = ppi_hw_intf; csid_ppi_hw->hw_info = ppi_hw_info; CAM_DBG(CAM_ISP, "type %d index %d", csid_ppi_hw->hw_intf->hw_type, ppi_idx); rc = cam_csid_ppi_init_soc_resources(&csid_ppi_hw->hw_info->soc_info, cam_csid_ppi_irq, csid_ppi_hw); if (rc < 0) { CAM_ERR(CAM_ISP, "PPI:%d Failed to init_soc", ppi_idx); goto err; } csid_ppi_hw->hw_intf->hw_ops.init = cam_csid_ppi_init_hw; csid_ppi_hw->hw_intf->hw_ops.deinit = cam_csid_ppi_deinit_hw; return 0; err: return rc; } int cam_csid_ppi_init_soc_resources(struct cam_hw_soc_info *soc_info, irq_handler_t ppi_irq_handler, void *irq_data) { int rc = 0; rc = cam_soc_util_get_dt_properties(soc_info); if (rc) { CAM_ERR(CAM_ISP, "PPI: Failed to get dt properties"); goto end; } rc = cam_soc_util_request_platform_resource(soc_info, ppi_irq_handler, irq_data); if (rc) { CAM_ERR(CAM_ISP, "PPI: Error Request platform resources failed rc=%d", rc); goto err; } end: return rc; err: cam_soc_util_release_platform_resource(soc_info); return rc; } irqreturn_t cam_csid_ppi_irq(int irq_num, void *data) { uint32_t irq_status = 0; uint32_t i, ppi_cfg_val = 0; bool fatal_err_detected = false; struct cam_csid_ppi_hw *ppi_hw; struct cam_hw_soc_info *soc_info; const struct cam_csid_ppi_reg_offset *ppi_reg; if (!data) { CAM_ERR(CAM_ISP, "PPI: Invalid arguments"); return IRQ_HANDLED; } ppi_hw = (struct cam_csid_ppi_hw *)data; ppi_reg = ppi_hw->ppi_info->ppi_reg; soc_info = &ppi_hw->hw_info->soc_info; if (ppi_hw->device_enabled != 1) goto ret; irq_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_status_addr); cam_io_w_mb(irq_status, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_clear_addr); cam_io_w_mb(PPI_IRQ_CMD_CLEAR, soc_info->reg_map[0].mem_base + ppi_reg->ppi_irq_cmd_addr); CAM_DBG(CAM_ISP, "PPI %d irq status 0x%x", ppi_hw->hw_intf->hw_idx, irq_status); if (irq_status & PPI_IRQ_RST_DONE) { CAM_DBG(CAM_ISP, "PPI Reset Done"); goto ret; } if ((irq_status & PPI_IRQ_FIFO0_OVERFLOW) || (irq_status & PPI_IRQ_FIFO1_OVERFLOW) || (irq_status & PPI_IRQ_FIFO2_OVERFLOW)) { fatal_err_detected = true; goto handle_fatal_error; } handle_fatal_error: if (fatal_err_detected) { CAM_ERR(CAM_ISP, "PPI: %d irq_status:0x%x", ppi_hw->hw_intf->hw_idx, irq_status); for (i = 0; i < CAM_CSID_PPI_LANES_MAX; i++) ppi_cfg_val &= ~PPI_CFG_CPHY_DLX_EN(i); cam_io_w_mb(ppi_cfg_val, soc_info->reg_map[0].mem_base + ppi_reg->ppi_module_cfg_addr); } ret: CAM_DBG(CAM_ISP, "IRQ Handling exit"); return IRQ_HANDLED; } int cam_csid_ppi_hw_deinit(struct cam_csid_ppi_hw *csid_ppi_hw) { if (!csid_ppi_hw) { CAM_ERR(CAM_ISP, "Invalid param"); return -EINVAL; } return cam_soc_util_release_platform_resource( &csid_ppi_hw->hw_info->soc_info); }