Jelajahi Sumber

msm: camera: common: Add AON support

Add Main/Aon camera switch support for image sensor
and it's submodule. This change detects the AON support
from image sensor hw information from it's respective
device tree support. Also sensor needs to call csiphy
to do the cpas top level operation in order to program
the register for Main/AON mux operation, so add API
export from csiphy hw for sensor domain to perform
the operation.

CRs-Fixed: 2899541
Change-Id: Ibde3ce86c15cfd7e7f445f6461565f78a668b812
Signed-off-by: Jigarkumar Zala <[email protected]>
Jigarkumar Zala 4 tahun lalu
induk
melakukan
26cfdeb27c

+ 132 - 31
drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c

@@ -43,6 +43,7 @@ module_param(csiphy_dump, int, 0644);
 struct g_csiphy_data {
 	void __iomem *base_address;
 	uint8_t is_3phase;
+	uint32_t cpas_handle;
 };
 
 static struct g_csiphy_data g_phy_data[MAX_CSIPHY] = {{0, 0}};
@@ -1065,6 +1066,101 @@ static int cam_csiphy_update_lane(
 	return 0;
 }
 
+static int cam_csiphy_cpas_ops(
+	uint32_t cpas_handle, bool start)
+{
+	int rc = 0;
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote = {0};
+
+	if (start) {
+		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(cpas_handle,
+			&ahb_vote, &axi_vote);
+		if (rc < 0) {
+			CAM_ERR(CAM_CSIPHY, "voting CPAS: %d", rc);
+			return rc;
+		}
+		CAM_DBG(CAM_CSIPHY, "CPAS START");
+	} else {
+		rc = cam_cpas_stop(cpas_handle);
+		if (rc < 0) {
+			CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc);
+			return rc;
+		}
+		CAM_DBG(CAM_CSIPHY, "CPAS STOPPED");
+	}
+
+	return rc;
+}
+
+int cam_csiphy_util_update_aon_ops(
+	bool get_access, uint32_t phy_idx)
+{
+	uint32_t aon_config = 0;
+	uint32_t cpas_hdl = 0;
+	int rc = 0;
+
+	if (phy_idx > MAX_CSIPHY) {
+		CAM_ERR(CAM_CSIPHY, "Null device");
+		return -ENODEV;
+	}
+
+	cpas_hdl = g_phy_data[phy_idx].cpas_handle;
+
+	CAM_DBG(CAM_CSIPHY, "PHY idx: %d", phy_idx);
+	rc = cam_csiphy_cpas_ops(cpas_hdl, true);
+	if (rc) {
+		if (rc == -EPERM) {
+			CAM_WARN(CAM_CSIPHY,
+				"CPHY: %d is already in start state");
+		} else {
+			CAM_ERR(CAM_CSIPHY, "voting CPAS: %d failed", rc);
+			return rc;
+		}
+	}
+
+	cam_cpas_reg_read(cpas_hdl, CAM_CPAS_REG_CPASTOP,
+		CAM_CSIPHY_CPAS_AON_SEL_ADDR, true,	&aon_config);
+
+	if (get_access) {
+		aon_config &= ~(CAM_CSIPHY_CPAS_MAIN_CAM_SEL |
+			CAM_CSIPHY_CPAS_MCLK_SEL);
+		CAM_DBG(CAM_CSIPHY,
+			"Selecting MainCamera over AON Camera");
+	} else if (!get_access) {
+		aon_config |= (CAM_CSIPHY_CPAS_MAIN_CAM_SEL |
+			CAM_CSIPHY_CPAS_MCLK_SEL);
+		CAM_DBG(CAM_CSIPHY,
+			"Releasing MainCamera to AON Camera");
+	}
+
+	CAM_DBG(CAM_CSIPHY, "value of aon_config = %u", aon_config);
+	if (cam_cpas_reg_write(cpas_hdl, CAM_CPAS_REG_CPASTOP,
+		CAM_CSIPHY_CPAS_AON_SEL_ADDR, true, aon_config)) {
+		CAM_ERR(CAM_CSIPHY,
+				"CPAS AON sel register write failed");
+	}
+
+	if (rc != -EPERM)
+		cam_csiphy_cpas_ops(cpas_hdl, false);
+
+	return rc;
+}
+
 int32_t cam_csiphy_core_cfg(void *phy_dev,
 			void *arg)
 {
@@ -1145,14 +1241,16 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		if (csiphy_acq_params.combo_mode == 1) {
 			CAM_DBG(CAM_CSIPHY, "combo mode stream detected");
 			csiphy_dev->combo_mode = 1;
-			if (csiphy_acq_params.csiphy_3phase)
+			if (csiphy_acq_params.csiphy_3phase) {
+				CAM_DBG(CAM_CSIPHY, "3Phase ComboMode");
 				csiphy_dev->session_max_device_support =
 					CSIPHY_MAX_INSTANCES_PER_PHY;
-			else
+			} else {
 				csiphy_dev->session_max_device_support =
 					CSIPHY_MAX_INSTANCES_PER_PHY - 1;
+				CAM_DBG(CAM_CSIPHY, "2Phase ComboMode");
+			}
 		}
-
 		if (csiphy_acq_params.cphy_dphy_combo_mode == 1) {
 			CAM_DBG(CAM_CSIPHY,
 				"cphy_dphy_combo_mode stream detected");
@@ -1206,6 +1304,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		csiphy_dev->acquire_count++;
 		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;
 	}
@@ -1226,6 +1325,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		int32_t offset, rc = 0;
 		struct cam_start_stop_dev_cmd config;
 
+		CAM_DBG(CAM_CSIPHY, "STOP_DEV CALLED");
 		rc = copy_from_user(&config, (void __user *)cmd->handle,
 					sizeof(config));
 		if (rc < 0) {
@@ -1287,9 +1387,10 @@ int32_t cam_csiphy_core_cfg(void *phy_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);
+		if (cam_csiphy_cpas_ops(csiphy_dev->cpas_handle, false)) {
+			CAM_ERR(CAM_CSIPHY, "Failed in de-voting CPAS");
+			rc = -EFAULT;
+		}
 
 		CAM_DBG(CAM_CSIPHY, "All PHY devices stopped");
 		csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE;
@@ -1305,6 +1406,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		int32_t offset;
 		struct cam_release_dev_cmd release;
 
+		CAM_DBG(CAM_CSIPHY, "RELEASE_DEV Called");
+
 		if (!csiphy_dev->acquire_count) {
 			CAM_ERR(CAM_CSIPHY, "No valid devices to release");
 			rc = -EINVAL;
@@ -1361,6 +1464,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 	case CAM_CONFIG_DEV: {
 		struct cam_config_dev_cmd config;
 
+		CAM_DBG(CAM_CSIPHY, "CONFIG_DEV Called");
 		if (copy_from_user(&config,
 			u64_to_user_ptr(cmd->handle),
 					sizeof(config))) {
@@ -1375,12 +1479,11 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		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;
 		int clk_vote_level = -1;
 
+		CAM_DBG(CAM_CSIPHY, "START_DEV Called");
 		rc = copy_from_user(&config, (void __user *)cmd->handle,
 			sizeof(config));
 		if (rc < 0) {
@@ -1466,21 +1569,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 			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;
-		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) {
+		rc = cam_csiphy_cpas_ops(csiphy_dev->cpas_handle, true);
+		if (rc) {
 			CAM_ERR(CAM_CSIPHY, "voting CPAS: %d", rc);
 			goto release_mutex;
 		}
@@ -1491,9 +1581,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 					CAM_CPAS_HW_IDX_ANY, NULL)) {
 				CAM_ERR(CAM_CSIPHY,
 					"sec_cam: camera fuse bit not set");
-				cam_cpas_stop(csiphy_dev->cpas_handle);
 				rc = -EINVAL;
-				goto release_mutex;
+				goto cpas_stop;
 			}
 
 			rc = cam_csiphy_notify_secure_mode(
@@ -1502,16 +1591,14 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 			if (rc < 0) {
 				csiphy_dev->csiphy_info[offset].secure_mode =
 					CAM_SECURE_MODE_NON_SECURE;
-				cam_cpas_stop(csiphy_dev->cpas_handle);
-				goto release_mutex;
+				goto cpas_stop;
 			}
 		}
 
 		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;
+			goto cpas_stop;
 		}
 		rc = cam_csiphy_config_dev(csiphy_dev, config.dev_handle);
 		if (csiphy_dump == 1)
@@ -1520,8 +1607,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		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;
+			goto cpas_stop;
 		}
 		csiphy_dev->start_dev_count++;
 
@@ -1554,8 +1640,15 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 			sizeof(struct cam_config_dev_cmd))) {
 			CAM_ERR(CAM_CSIPHY, "failed copy config ext\n");
 			rc = -EFAULT;
+			goto release_mutex;
 		} else {
 			rc = cam_csiphy_external_cmd(csiphy_dev, &submit_cmd);
+			if (rc) {
+				CAM_ERR(CAM_CSIPHY,
+					"exteranal command configuration failed rc: %d",
+					rc);
+				goto release_mutex;
+			}
 		}
 		break;
 	}
@@ -1565,6 +1658,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 		goto release_mutex;
 	}
 
+	mutex_unlock(&csiphy_dev->mutex);
+	return rc;
+
+cpas_stop:
+	if (cam_csiphy_cpas_ops(csiphy_dev->cpas_handle, false))
+		CAM_ERR(CAM_CSIPHY, "cpas stop failed");
 release_mutex:
 	mutex_unlock(&csiphy_dev->mutex);
 
@@ -1586,4 +1685,6 @@ void cam_csiphy_register_baseaddress(struct csiphy_device *csiphy_dev)
 
 	g_phy_data[csiphy_dev->soc_info.index].base_address =
 		csiphy_dev->soc_info.reg_map[0].mem_base;
+	g_phy_data[csiphy_dev->soc_info.index].cpas_handle =
+		csiphy_dev->cpas_handle;
 }

+ 10 - 1
drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 2020-2021 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_CSIPHY_CORE_H_
@@ -56,4 +56,13 @@ void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev);
  */
 void cam_csiphy_register_baseaddress(struct csiphy_device *csiphy_dev);
 
+/**
+ * @get_access : Get Access for the Main Camera over AON Camera
+ * @phy_idx    : To acquire the correct PHY hw to do the operation with
+ *
+ * This API provides Utility/helper function to program the MUX for
+ * correct PHY hw.
+ *
+ */
+int cam_csiphy_util_update_aon_ops(bool get_access, uint32_t phy_idx);
 #endif /* _CAM_CSIPHY_CORE_H_ */

+ 4 - 0
drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h

@@ -64,6 +64,10 @@
 #define DPHY_LANE_3    BIT(6)
 #define DPHY_CLK_LN    BIT(7)
 
+#define CAM_CSIPHY_CPAS_AON_SEL_ADDR    0x001E0
+#define CAM_CSIPHY_CPAS_MAIN_CAM_SEL    BIT(0)
+#define CAM_CSIPHY_CPAS_MCLK_SEL        BIT(8)
+
 enum cam_csiphy_state {
 	CAM_CSIPHY_INIT,
 	CAM_CSIPHY_ACQUIRE,

+ 29 - 0
drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c

@@ -1288,6 +1288,20 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl)
 		}
 	}
 
+	if (s_ctrl->is_aon_user) {
+		CAM_DBG(CAM_SENSOR,
+			"Setup for Main Camera with csiphy index: %d",
+			s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]);
+		rc = cam_sensor_util_aon_ops(true,
+			s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]);
+		if (rc) {
+			CAM_WARN(CAM_SENSOR,
+				"Main camera access opertion is not successful rc: %d",
+				rc);
+			return rc;
+		}
+	}
+
 	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);
@@ -1327,6 +1341,7 @@ int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl)
 		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);
@@ -1343,6 +1358,20 @@ int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl)
 		}
 	}
 
+	if (s_ctrl->is_aon_user) {
+		CAM_DBG(CAM_SENSOR,
+			"Setup for AON FW with csiphy index: %d",
+			s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]);
+		rc = cam_sensor_util_aon_ops(false,
+			s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]);
+		if (rc) {
+			CAM_WARN(CAM_SENSOR,
+				"AON FW access opertion is not successful rc: %d",
+				rc);
+			return rc;
+		}
+	}
+
 	camera_io_release(&(s_ctrl->io_master_info));
 
 	return rc;

+ 30 - 26
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-2019, 2021 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_SENSOR_DEV_H_
@@ -86,33 +86,37 @@ struct sensor_intf_params {
  * @last_flush_req: Last request to flush
  * @pipeline_delay: Sensor pipeline delay
  * @sensor_name: Sensor name
+ * @is_aon_user: To determine whether sensor is AON user or not
  */
 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;
-	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 sensor_intf_params bridge_intf;
-	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;
-	char     sensor_name[CAM_SENSOR_NAME_MAX_SIZE];
+	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;
+	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 sensor_intf_params      bridge_intf;
+	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;
+	char                           sensor_name[
+		CAM_SENSOR_NAME_MAX_SIZE];
+	bool                           is_aon_user;
 };
 
 /**

+ 13 - 1
drivers/cam_sensor_module/cam_sensor/cam_sensor_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-2019, 2021 The Linux Foundation. All rights reserved.
  */
 
 #include <linux/of.h>
@@ -203,6 +203,18 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl)
 		sensordata->pos_yaw = 360;
 	}
 
+	if (!of_property_read_bool(of_node, "aon-user")) {
+		CAM_DBG(CAM_SENSOR,
+			"SENSOR cell_idx: %d not use for AON usecase",
+			s_ctrl->soc_info.index);
+		s_ctrl->is_aon_user = false;
+	} else {
+		CAM_DBG(CAM_SENSOR,
+			"SENSOR cell_idx: %d is user for AON usecase",
+			s_ctrl->soc_info.index);
+		s_ctrl->is_aon_user = true;
+	}
+
 	return rc;
 
 FREE_SENSOR_DATA:

+ 9 - 1
drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.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_UTIL_H_
@@ -18,6 +18,7 @@
 #include "cam_soc_util.h"
 #include "cam_debug_util.h"
 #include "cam_sensor_io.h"
+#include "cam_csiphy_core.h"
 
 #define INVALID_VREG 100
 #define RES_MGR_GPIO_NEED_HOLD   1
@@ -81,4 +82,11 @@ int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info,
 	int bob_reg_idx, bool flag);
 
 bool cam_sensor_util_check_gpio_is_shared(struct cam_hw_soc_info *soc_info);
+
+static inline int cam_sensor_util_aon_ops(bool get_access, uint32_t phy_idx)
+{
+	CAM_DBG(CAM_SENSOR, "Updating Main/Aon operation");
+	return cam_csiphy_util_update_aon_ops(get_access, phy_idx);
+}
+
 #endif /* _CAM_SENSOR_UTIL_H_ */