Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef4e88e5 authored by Sravan Muppidi's avatar Sravan Muppidi
Browse files

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: default avatarSravan Muppidi <muppidi@codeaurora.org>
parent 299c1a13
Loading
Loading
Loading
Loading
+46 −8
Original line number Diff line number Diff line
// 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 <linux/of.h>
@@ -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);