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 9fd46a2f3f8a..f0ea6fe8fb24 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 @@ -323,6 +323,41 @@ static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id) return rc; } +static int cam_ife_hw_mgr_dump_hw_src_clock(uint8_t hw_idx, + enum cam_isp_hw_type hw_type) +{ + + struct cam_isp_hw_intf_data *hw_intf_data = NULL; + struct cam_hw_intf *hw_intf = NULL; + uint8_t dummy_args; + + switch (hw_type) { + case CAM_ISP_HW_TYPE_VFE: + if (!g_ife_hw_mgr.ife_devices[hw_idx]) { + CAM_ERR(CAM_ISP, "No vfe device added yet"); + return -ENODEV; + } + + hw_intf_data = g_ife_hw_mgr.ife_devices[hw_idx]; + if (!hw_intf_data->hw_intf) { + CAM_ERR(CAM_ISP, "hw_intf is null"); + return -EINVAL; + } + + hw_intf = hw_intf_data->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE, + (void *)&dummy_args, sizeof(uint8_t)); + } + break; + default: + CAM_ERR(CAM_ISP, "Unsupported HW Type: %u", hw_type); + } + + return 0; +} + static int cam_ife_hw_mgr_reset_csid_res( struct cam_isp_hw_mgr_res *isp_hw_res) { @@ -7664,15 +7699,14 @@ static int cam_ife_hw_mgr_handle_hw_dump_info( 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_isp_hw_error_event_data error_event_data = {0}; struct cam_ife_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: { - + case CAM_ISP_HW_ERROR_CSID_FATAL: if (!g_ife_hw_mgr.debug_cfg.enable_csid_recovery) break; @@ -7681,7 +7715,12 @@ static int cam_ife_hw_mgr_handle_csid_event( event_info->hw_idx, &recovery_data); break; - } + case CAM_ISP_HW_ERROR_CSID_OVERFLOW: + if (cam_ife_hw_mgr_dump_hw_src_clock(event_info->hw_idx, + CAM_ISP_HW_TYPE_VFE)) + CAM_ERR_RATE_LIMIT(CAM_ISP, + "VFE%d src_clk_rate dump failed"); + break; default: break; } @@ -7692,12 +7731,12 @@ 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; - struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx; + 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_ife_hw_event_recovery_data recovery_data = {0}; - int rc = -EINVAL; + int rc = -EINVAL; if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; @@ -7707,7 +7746,8 @@ static int cam_ife_hw_mgr_handle_hw_err( 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) { + if ((event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) || + (event_info->err_type == CAM_ISP_HW_ERROR_CSID_OVERFLOW)) { rc = cam_ife_hw_mgr_handle_csid_event(event_info); spin_unlock(&g_ife_hw_mgr.ctx_lock); return rc; 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 cfac2f5b68ca..1e1ac79be6fd 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_ @@ -53,13 +53,13 @@ enum cam_isp_hw_event_type { * 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_CSID_FATAL, - CAM_ISP_HW_ERROR_MAX, + CAM_ISP_HW_ERROR_NONE = 0x0001, + CAM_ISP_HW_ERROR_OVERFLOW = 0x0002, + CAM_ISP_HW_ERROR_P2I_ERROR = 0x0004, + CAM_ISP_HW_ERROR_VIOLATION = 0x0008, + CAM_ISP_HW_ERROR_BUSIF_OVERFLOW = 0x0010, + CAM_ISP_HW_ERROR_CSID_FATAL = 0x0020, + CAM_ISP_HW_ERROR_CSID_OVERFLOW = 0x0040, }; /** 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 ef50a1ab51eb..6efeb80bbdb5 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 @@ -4663,7 +4663,6 @@ static int cam_csid_evt_bottom_half_handler( 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; const struct cam_ife_csid_reg_offset *csid_reg; int udi_start_idx = CAM_IFE_CSID_IRQ_REG_UDI_0; @@ -4697,7 +4696,10 @@ static int cam_csid_evt_bottom_half_handler( goto end; } - if (csid_hw->sof_irq_triggered && (evt_payload->evt_type == + CAM_DBG(CAM_ISP, "CSID[%d] error type 0x%x", csid_hw->hw_intf->hw_idx, + evt_payload->evt_type); + + if (csid_hw->sof_irq_triggered && (evt_payload->evt_type & CAM_ISP_HW_ERROR_NONE)) { if (evt_payload->irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & CSID_PATH_INFO_INPUT_SOF) { @@ -4728,9 +4730,12 @@ static int cam_csid_evt_bottom_half_handler( "CSID:%d UDI:%d SOF received", csid_hw->hw_intf->hw_idx, i); } - } else { + } + + if ((evt_payload->evt_type & CAM_ISP_HW_ERROR_CSID_FATAL) || + (evt_payload->evt_type & CAM_ISP_HW_ERROR_CSID_OVERFLOW)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID %d err %d phy %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x PPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x RDI3: 0x%x UDI0: 0x%x UDI1: 0x%x UDI2: 0x%x", + "CSID %d err 0x%x phy %d irq status TOP: 0x%x RX: 0x%x IPP: 0x%x PPP: 0x%x RDI0: 0x%x RDI1: 0x%x RDI2: 0x%x RDI3: 0x%x UDI0: 0x%x UDI1: 0x%x UDI2: 0x%x", csid_hw->hw_intf->hw_idx, evt_payload->evt_type, csid_hw->csi2_rx_cfg.phy_sel, @@ -4747,32 +4752,28 @@ static int cam_csid_evt_bottom_half_handler( evt_payload->irq_status[CAM_IFE_CSID_IRQ_REG_UDI_2]); } - if (evt_payload->evt_type == CAM_ISP_HW_ERROR_CSID_FATAL) - cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, - CAM_SUBDEV_MESSAGE_IRQ_ERR, - csid_hw->csi2_rx_cfg.phy_sel); - /* 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 (evt_payload->evt_type & CAM_ISP_HW_ERROR_CSID_FATAL) { + cam_subdev_notify_message(CAM_CSIPHY_DEVICE_TYPE, + CAM_SUBDEV_MESSAGE_IRQ_ERR, + csid_hw->csi2_rx_cfg.phy_sel); if (csid_hw->fatal_err_detected) - break; + goto end; csid_hw->fatal_err_detected = true; - rc = csid_hw->event_cb(NULL, + event_info.err_type = CAM_ISP_HW_ERROR_CSID_FATAL; + csid_hw->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); - break; + } - default: - CAM_DBG(CAM_ISP, "CSID[%d] error type %d", - csid_hw->hw_intf->hw_idx, - evt_payload->evt_type); - break; + if (evt_payload->evt_type & CAM_ISP_HW_ERROR_CSID_OVERFLOW) { + event_info.err_type = CAM_ISP_HW_ERROR_CSID_OVERFLOW; + csid_hw->event_cb(NULL, + CAM_ISP_HW_EVENT_ERROR, (void *)&event_info); } end: cam_csid_put_evt_payload(csid_hw, &evt_payload); @@ -4781,7 +4782,7 @@ end: static int cam_csid_handle_hw_err_irq( struct cam_ife_csid_hw *csid_hw, - int evt_type, + uint32_t evt_type, uint32_t *irq_status) { int rc = 0; @@ -4789,7 +4790,7 @@ static int cam_csid_handle_hw_err_irq( void *bh_cmd = NULL; struct cam_csid_evt_payload *evt_payload; - CAM_DBG(CAM_ISP, "CSID[%d] error %d", + CAM_DBG(CAM_ISP, "CSID[%d] error 0x%x", csid_hw->hw_intf->hw_idx, evt_type); rc = cam_csid_get_evt_payload(csid_hw, &evt_payload); @@ -4803,7 +4804,7 @@ static int cam_csid_handle_hw_err_irq( 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[%d] Can not get cmd for tasklet, evt_type 0x%x", csid_hw->hw_intf->hw_idx, evt_type); cam_csid_put_evt_payload(csid_hw, &evt_payload); @@ -4832,11 +4833,12 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) 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 irq_status[CAM_IFE_CSID_IRQ_REG_MAX] = {0}; - uint32_t i, val, val2; - bool fatal_err_detected = false; - uint32_t sof_irq_debug_en = 0, log_en = 0; - unsigned long flags; + uint32_t irq_status[CAM_IFE_CSID_IRQ_REG_MAX] = {0}; + uint32_t i, val, val2; + bool fatal_err_detected = false; + uint32_t sof_irq_debug_en = 0; + uint32_t event_type = 0; + unsigned long flags; csid_hw = (struct cam_ife_csid_hw *)data; @@ -4966,76 +4968,94 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) if (csid_hw->device_enabled == 1) { 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RX_ERROR_LANE0_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz", + csid_hw->hw_intf->hw_idx, + soc_info->applied_src_clk_rate); fatal_err_detected = true; goto handle_fatal_error; } 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RX_ERROR_LANE1_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz", + csid_hw->hw_intf->hw_idx, + soc_info->applied_src_clk_rate); fatal_err_detected = true; goto handle_fatal_error; } 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RX_ERROR_LANE2_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz", + csid_hw->hw_intf->hw_idx, + soc_info->applied_src_clk_rate); fatal_err_detected = true; goto handle_fatal_error; } 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RX_ERROR_LANE3_FIFO_OVERFLOW: Skew/Less Data on lanes/ Slow csid clock:%luHz", + csid_hw->hw_intf->hw_idx, + soc_info->applied_src_clk_rate); fatal_err_detected = true; goto handle_fatal_error; } 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", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RX_ERROR_TPG_FIFO_OVERFLOW: Backpressure from IFE", csid_hw->hw_intf->hw_idx); fatal_err_detected = true; + event_type |= CAM_ISP_HW_ERROR_CSID_OVERFLOW; goto handle_fatal_error; } if ((irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) && (!csid_hw->epd_supported)) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d CPHY_EOT_RECEPTION", + "CSID:%d CPHY_EOT_RECEPTION: No EOT on lane/s", csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } 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:%d CPHY_SOT_RECEPTION: Less SOTs on lane/s", csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } 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", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_PH_CRC CPHY: Pkt Hdr CRC mismatch", 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", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_CRC CPHY: Long pkt payload CRC mismatch", 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", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_ECC: Dphy pkt hdr errors unrecoverable", 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) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - 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_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d MMAPPED_VC_DT: VC:%d DT:%d mapped to more than 1 csid paths", + csid_hw->hw_intf->hw_idx, (val >> 22), + ((val >> 16) & 0x3F), (val & 0xFFFF)); } if ((irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_UNMAPPED_VC_DT) && @@ -5046,21 +5066,25 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csi2_reg->csid_csi2_rx_captured_long_pkt_0_addr); CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d UNMAPPED_VC_DT. VC: %d DT: %d WC: %d", + "CSID:%d UNMAPPED_VC_DT: VC:%d DT:%d WC:%d not mapped to any csid paths", csid_hw->hw_intf->hw_idx, (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); csid_hw->error_irq_count++; } if (irq_status[CAM_IFE_CSID_IRQ_REG_RX] & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_0_addr); + CAM_ERR_RATE_LIMIT(CAM_ISP, - "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); + "CSID:%d ERROR_STREAM_UNDERFLOW: Fewer bytes rcvd than WC:%d in pkt hdr", + csid_hw->hw_intf->hw_idx, (val & 0xFFFF)); csid_hw->error_irq_count++; } 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", + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d UNBOUNDED_FRAME: Frame started with EOF or No EOF", csid_hw->hw_intf->hw_idx); csid_hw->error_irq_count++; } @@ -5078,7 +5102,8 @@ 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); + (event_type | CAM_ISP_HW_ERROR_CSID_FATAL), irq_status); + event_type = 0; } if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { @@ -5206,7 +5231,7 @@ handle_fatal_error: "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); else - log_en = 1; + event_type |= CAM_ISP_HW_ERROR_NONE; if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; @@ -5221,24 +5246,25 @@ handle_fatal_error: 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:%d IPP_PATH_ERROR_CCIF_VIOLATION: Bad frame timings", csid_hw->hw_intf->hw_idx); 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:%d IPP_PATH_OVERFLOW_RECOVERY: Back pressure/output fifo ovrfl", csid_hw->hw_intf->hw_idx); 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); /* 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP_PATH_ERROR_O/P_FIFO_OVERFLOW: Slow IFE read", + csid_hw->hw_intf->hw_idx); + event_type |= CAM_ISP_HW_ERROR_CSID_OVERFLOW; } if ((irq_status[CAM_IFE_CSID_IRQ_REG_IPP] & @@ -5289,7 +5315,7 @@ handle_fatal_error: "CSID:%d IPP SOF received", csid_hw->hw_intf->hw_idx); else - log_en = 1; + event_type |= CAM_ISP_HW_ERROR_NONE; if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; @@ -5304,24 +5330,25 @@ handle_fatal_error: 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:%d PPP_PATH_ERROR_CCIF_VIOLATION: Bad frame timings", csid_hw->hw_intf->hw_idx); 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:%d PPP_PATH_OVERFLOW_RECOVERY: Back pressure/output fifo ovrfl", csid_hw->hw_intf->hw_idx); 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); /* 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP_PATH_ERROR_O/P_FIFO_OVERFLOW: Slow IFE read", + csid_hw->hw_intf->hw_idx); + event_type |= CAM_ISP_HW_ERROR_CSID_OVERFLOW; } if ((irq_status[CAM_IFE_CSID_IRQ_REG_PPP] & @@ -5369,7 +5396,7 @@ handle_fatal_error: "CSID:%d RDI:%d SOF received", csid_hw->hw_intf->hw_idx, i); else - log_en = 1; + event_type |= CAM_ISP_HW_ERROR_NONE; if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; @@ -5383,22 +5410,24 @@ handle_fatal_error: if ((irq_status[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d RDI :%d CCIF violation", + "CSID:%d RDI :%d PATH_ERROR_CCIF_VIOLATION: Bad frame timings", csid_hw->hw_intf->hw_idx, i); if ((irq_status[i] & CSID_PATH_OVERFLOW_RECOVERY)) CAM_INFO_RATE_LIMIT(CAM_ISP, - "CSID:%d RDI :%d Overflow due to back pressure", + "CSID:%d RDI :%d PATH_OVERFLOW_RECOVERY: Back pressure/output fifo ovrfl", csid_hw->hw_intf->hw_idx, i); 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); /* 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RDI_PATH_ERROR_O/P_FIFO_OVERFLOW: Slow IFE read", + csid_hw->hw_intf->hw_idx); + + event_type |= CAM_ISP_HW_ERROR_CSID_OVERFLOW; } if ((irq_status[i] & CSID_PATH_ERROR_PIX_COUNT) || @@ -5443,7 +5472,7 @@ handle_fatal_error: "CSID:%d UDI:%d SOF received", csid_hw->hw_intf->hw_idx, i); else - log_en = 1; + event_type |= CAM_ISP_HW_ERROR_NONE; if (csid_hw->sof_irq_triggered) csid_hw->irq_debug_cnt++; @@ -5459,30 +5488,30 @@ handle_fatal_error: if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & CSID_PATH_ERROR_CCIF_VIOLATION)) CAM_WARN_RATE_LIMIT(CAM_ISP, - "CSID:%d UDI :%d CCIF violation", + "CSID:%d UDI :%d PATH_ERROR_CCIF_VIOLATION: Bad frame timings", csid_hw->hw_intf->hw_idx, i); if ((irq_status[CAM_IFE_CSID_IRQ_REG_UDI_0 + i] & CSID_PATH_OVERFLOW_RECOVERY)) CAM_WARN_RATE_LIMIT(CAM_ISP, - "CSID:%d UDI :%d Overflow due to back pressure", + "CSID:%d UDI :%d PATH_OVERFLOW_RECOVERY: Back pressure/output fifo ovrfl", csid_hw->hw_intf->hw_idx, i); 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); /* 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); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d UDI_PATH_ERROR_O/P_FIFO_OVERFLOW: Slow ife read", + csid_hw->hw_intf->hw_idx); + event_type |= CAM_ISP_HW_ERROR_CSID_OVERFLOW; } } - if (log_en) - cam_csid_handle_hw_err_irq(csid_hw, - CAM_ISP_HW_ERROR_NONE, irq_status); + if (event_type) + cam_csid_handle_hw_err_irq(csid_hw, event_type, irq_status); 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); 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 55d23566060a..b2096b454395 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-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_IFE_CSID_HW_H_ @@ -599,7 +599,7 @@ struct cam_csid_evt_payload { * @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 + * @clk_rate Current 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. 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 64b6cd3ed253..ad5d25abe7fc 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_ @@ -137,6 +137,7 @@ enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_QUERY_BUS_CAP, CAM_ISP_HW_CMD_GET_CLOCK_RATE, CAM_ISP_HW_CMD_DYNAMIC_CLOCK_UPDATE, + CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c index 21316b09f29f..42a84af64e24 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/ppi_hw/cam_csid_ppi_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, The Linux Foundation. All rights reserved. */ #include @@ -75,7 +75,7 @@ static int cam_csid_ppi_enable_hw(struct cam_csid_ppi_hw *ppi_hw) 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); + soc_info->clk_name[i], 0, NULL); if (rc) goto clk_disable; } diff --git a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c index a28144a2a51d..39760807288c 100644 --- a/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.c +++ b/drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_soc.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 @@ -199,7 +199,7 @@ int cam_tfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, if (strcmp(clk_name, CAM_TFE_DSP_CLK_NAME) == 0) { rc = cam_soc_util_clk_enable(soc_private->dsp_clk, - CAM_TFE_DSP_CLK_NAME, soc_private->dsp_clk_rate); + CAM_TFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL); if (rc) CAM_ERR(CAM_ISP, "Error enable dsp clk failed rc=%d", rc); 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 6b0b2113bfe1..17580dca5079 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 @@ -601,6 +601,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, case CAM_ISP_HW_CMD_ADD_WAIT: case CAM_ISP_HW_CMD_ADD_WAIT_TRIGGER: case CAM_ISP_HW_CMD_CAMIF_DATA: + case CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE: case CAM_ISP_HW_CMD_BLANKING_UPDATE: rc = core_info->vfe_top->hw_ops.process_cmd( core_info->vfe_top->top_priv, cmd_type, cmd_args, 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 d684f27f3989..0138ace0b39f 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 @@ -307,7 +307,7 @@ int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, } rc = cam_soc_util_clk_enable(soc_private->dsp_clk, - CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate); + CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate, NULL); if (rc) CAM_ERR(CAM_ISP, "Error enable dsp clk failed rc=%d", 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 index 1e5f66df4c1c..44edd50295de 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 @@ -169,6 +169,29 @@ static int cam_vfe_top_clock_update( return rc; } +static int cam_vfe_top_dump_info( + struct cam_vfe_top_ver2_priv *top_priv, uint32_t cmd_type) +{ + struct cam_hw_soc_info *soc_info = top_priv->common_data.soc_info; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Null soc_info"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE: + CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE%d src_clk_rate:%luHz", + soc_info->index, soc_info->applied_src_clk_rate); + break; + default: + CAM_ERR(CAM_ISP, "cmd_type: %u not supported", cmd_type); + break; + } + + return 0; +} + static int cam_vfe_top_blanking_update(uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -794,6 +817,9 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE: + rc = cam_vfe_top_dump_info(top_priv, cmd_type); + break; case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: rc = cam_vfe_top_fs_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 3b0b1f5f072c..279fbc845df0 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 @@ -190,6 +190,30 @@ static int cam_vfe_top_ver3_clock_update( return rc; } +static int cam_vfe_top_ver3_dump_info( + struct cam_vfe_top_ver3_priv *top_priv, uint32_t cmd_type) +{ + struct cam_hw_soc_info *soc_info = top_priv->common_data.soc_info; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Null soc_info"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE: + CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE%d src_clk_rate:%luHz", + soc_info->index, soc_info->applied_src_clk_rate); + break; + default: + CAM_ERR(CAM_ISP, "cmd_type: %u not supported", cmd_type); + break; + } + + return 0; +} + + static int cam_vfe_top_ver3_blanking_update(uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -731,6 +755,9 @@ int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_DUMP_HW_SRC_CLK_RATE: + rc = cam_vfe_top_ver3_dump_info(top_priv, cmd_type); + break; case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: rc = cam_vfe_top_fs_update(top_priv, cmd_args, arg_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 68770d526c31..7dc0128940b7 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-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include "cam_csiphy_soc.h" @@ -130,8 +130,6 @@ 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, int32_t index) { 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 e965049730a7..4dde033a2fbd 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-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -2098,7 +2098,8 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, 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]); + soc_info->clk_rate[0][j], + NULL); if (rc) break; } diff --git a/drivers/cam_utils/cam_soc_util.c b/drivers/cam_utils/cam_soc_util.c index 474c7c34d9b1..8b648c4bf446 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-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #include @@ -378,19 +378,20 @@ long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, /** * cam_soc_util_set_clk_rate() * - * @brief: Sets the given rate for the clk requested for + * @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 + * @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 + * @applied_clk_rate: Final clock rate set to the clk * * @return: Success or failure */ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, - int64_t clk_rate) + int64_t clk_rate, unsigned long *applied_clk_rate) { int rc = 0; - long clk_rate_round; + long clk_rate_round = -1; if (!clk || !clk_name) return -EINVAL; @@ -427,6 +428,9 @@ static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, } } + if (applied_clk_rate) + *applied_clk_rate = clk_rate_round; + return rc; } @@ -475,7 +479,8 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, } rc = cam_soc_util_set_clk_rate(clk, - soc_info->clk_name[src_clk_idx], clk_rate); + soc_info->clk_name[src_clk_idx], clk_rate, + &soc_info->applied_src_clk_rate); if (rc) { CAM_ERR(CAM_UTIL, "SET_RATE Failed: src clk: %s, rate %lld, dev_name = %s rc: %d", @@ -495,7 +500,8 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, 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]); + soc_info->clk_rate[apply_level][scl_clk_idx], + NULL); if (rc) { CAM_WARN(CAM_UTIL, "SET_RATE Failed: scl clk: %s, rate %d dev_name = %s, rc: %d", @@ -602,14 +608,15 @@ int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info, } int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, - int32_t clk_rate) + int32_t clk_rate, unsigned long *applied_clock_rate) { int rc = 0; if (!clk || !clk_name) return -EINVAL; - rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate); + rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate, + applied_clock_rate); if (rc) return rc; @@ -647,8 +654,9 @@ int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name) 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; + int i, rc = 0; + enum cam_vote_level apply_level; + unsigned long applied_clk_rate; if ((soc_info->num_clk == 0) || (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { @@ -668,9 +676,14 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, 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]); + soc_info->clk_rate[apply_level][i], + &applied_clk_rate); if (rc) goto clk_disable; + + if (i == soc_info->src_clk_idx) + soc_info->applied_src_clk_rate = applied_clk_rate; + if (soc_info->cam_cx_ipeak_enable) { CAM_DBG(CAM_UTIL, "dev name = %s clk name = %s idx = %d\n" @@ -928,6 +941,7 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, { int i, rc = 0; enum cam_vote_level apply_level; + unsigned long applied_clk_rate; if ((soc_info->num_clk == 0) || (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { @@ -957,7 +971,8 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, rc = cam_soc_util_set_clk_rate(soc_info->clk[i], soc_info->clk_name[i], - soc_info->clk_rate[apply_level][i]); + soc_info->clk_rate[apply_level][i], + &applied_clk_rate); if (rc < 0) { CAM_DBG(CAM_UTIL, "dev name = %s clk_name = %s idx = %d\n" @@ -968,6 +983,9 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); break; } + + if (i == soc_info->src_clk_idx) + soc_info->applied_src_clk_rate = applied_clk_rate; } return rc; diff --git a/drivers/cam_utils/cam_soc_util.h b/drivers/cam_utils/cam_soc_util.h index aea1a396e4fd..8db6f1869cf8 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-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #ifndef _CAM_SOC_UTIL_H_ @@ -160,6 +160,7 @@ struct cam_soc_gpio_data { * @clk_level_valid: Indicates whether corresponding level is valid * @scl_clk_count: Number of scalable clocks present * @scl_clk_idx: Index of scalable clocks + * @applied_src_clk_rate Current clock rate of the core source clk * @gpio_data: Pointer to gpio info * @pinctrl_info: Pointer to pinctrl info * @dentry: Debugfs entry @@ -206,6 +207,7 @@ struct cam_hw_soc_info { int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK]; int32_t prev_clk_level; int32_t src_clk_idx; + unsigned long applied_src_clk_rate; bool clk_level_valid[CAM_MAX_VOTE]; int32_t scl_clk_count; int32_t scl_clk_idx[CAM_SOC_MAX_CLK]; @@ -468,11 +470,12 @@ int cam_soc_util_clk_put(struct clk **clk); * @clk: Clock that needs to be turned ON * @clk_name: Clocks name associated with clk * @clk_rate: Clocks rate associated with clk + * @applied_clock_rate Final Clock rate applied to the clk * * @return: Success or failure */ int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, - int32_t clk_rate); + int32_t clk_rate, unsigned long *applied_clock_rate); /** * cam_soc_util_set_clk_rate_level()