Ver Fonte

Merge "msm: camera: csiphy: Expand CSIPHY Onthego support" into camera-kernel.lnx.7.0

Camera Software Integration há 1 ano atrás
pai
commit
7faeb4a453
1 ficheiros alterados com 142 adições e 20 exclusões
  1. 142 20
      drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c

+ 142 - 20
drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c

@@ -33,13 +33,12 @@
  */
 #define CAM_MAX_PHYS_PER_CP_CTRL_REG 4
 
-static DEFINE_MUTEX(active_csiphy_cnt_mutex);
-static DEFINE_MUTEX(main_aon_selection);
+/*
+ * PHY ON-The-Go Buffer Size
+ */
+#define CSIPHY_ONTHEGO_BUFSIZE 30
+
 
-static int csiphy_onthego_reg_count;
-static unsigned int csiphy_onthego_regs[150];
-module_param_array(csiphy_onthego_regs, uint, &csiphy_onthego_reg_count, 0644);
-MODULE_PARM_DESC(csiphy_onthego_regs, "Functionality to let csiphy registers program on the fly");
 
 struct g_csiphy_data {
 	void __iomem *base_address;
@@ -51,8 +50,125 @@ struct g_csiphy_data {
 	struct cam_csiphy_aon_sel_params_t *aon_sel_param;
 };
 
+static DEFINE_MUTEX(active_csiphy_cnt_mutex);
+static DEFINE_MUTEX(main_aon_selection);
 static struct g_csiphy_data g_phy_data[MAX_CSIPHY] = {0};
 static int active_csiphy_hw_cnt;
+static char csiphy_onthego_regs[20];
+static int csiphy_onthego_reg_count[MAX_CSIPHY];
+static unsigned int csiphy_onthego_regvals[MAX_CSIPHY][CSIPHY_ONTHEGO_BUFSIZE];
+
+
+typedef int (*csiphy_onthego_func)(int *inp, int n_inp, int phy_idx, char *outp);
+static int csiphy_onthego_get_set(int *inp, int n_inp, int phy_idx, char *outp);
+
+static int csiphy_set_onthego_values(const char *val, const struct kernel_param *kp)
+{
+	/**
+	 * Expected format string: ":n1,n2,..:val1,val2,...""
+	 * Values between the colons, specify the PHY(s) with
+	 * which these settings apply to
+	 * The actual onthego values should have comma-delimited
+	 * entries with total a multiple of 3 (reg_addr, val, delay)
+	 */
+	csiphy_onthego_func fn = (csiphy_onthego_func) kp->arg;
+	int i, idx, onthego_val, onthego_idx = 0;
+	int onthego_values[CSIPHY_ONTHEGO_BUFSIZE] = {0};
+	char *p1, *p2, *token;
+	bool phy_target[MAX_CSIPHY] = {false};
+
+	p1 = strnchr(val, 1, ':'); p2 = strrchr(val, ':');
+	if (!p1 || !p2 || p2 - p1 < 2) {
+		CAM_ERR(CAM_CSIPHY, "Invalid csiphy onthego input string: %s", val);
+		return -EINVAL;
+	}
+
+	strscpy(csiphy_onthego_regs, p1, 20);
+	while ((token = strsep(&p1, ":")) != NULL) {
+		if (!kstrtoint(token, 0, &idx) && idx >= 0 && idx < MAX_CSIPHY)
+			phy_target[idx] = true;
+	}
+
+	p1 = p2 + 1;
+
+	if (!strncasecmp(p1, "X", 1)) {
+		for (i = 0; i < MAX_CSIPHY; i++) {
+			if (phy_target[i])
+				csiphy_onthego_reg_count[i] = 0;
+		}
+		return 0;
+	}
+
+	while ((token = strsep(&p1, ",")) != NULL) {
+		if (!kstrtoint(token, 0, &onthego_val))
+			onthego_values[onthego_idx++] = onthego_val;
+	}
+
+	if (!onthego_idx || (onthego_idx % 3)) {
+		CAM_ERR(CAM_CSIPHY, "Invalid multiple of onthego entries: %d,", onthego_idx);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_CSIPHY && onthego_idx; i++) {
+		if (phy_target[i])
+			fn(onthego_values, onthego_idx, i, NULL);
+	}
+
+	return 0;
+}
+
+static int csiphy_get_onthego_values(char *buffer, const struct kernel_param *kp)
+{
+	csiphy_onthego_func fn = (csiphy_onthego_func) kp->arg;
+	int rc = 0, i;
+	char *p = buffer;
+
+	for (i = 0; i < MAX_CSIPHY; i++)
+		rc += fn(NULL, 0, i, p + rc);
+
+	return rc;
+}
+
+static const struct kernel_param_ops csiphy_onthego_ops = {
+	.set = csiphy_set_onthego_values,
+	.get = csiphy_get_onthego_values,
+};
+
+module_param_cb(csiphy_onthego_regs, &csiphy_onthego_ops, csiphy_onthego_get_set, 0644);
+MODULE_PARM_DESC(csiphy_onthego_regs, "Functionality to let csiphy registers program on the fly");
+
+static int csiphy_onthego_get_set(int *inp, int n_inp, int phy_idx, char *outp)
+{
+	int i, idx, rc = 0;
+	char *p;
+
+	idx = csiphy_onthego_reg_count[phy_idx];
+
+	if (inp && n_inp) {
+		for (i = 0; i < n_inp; i++) {
+			csiphy_onthego_regvals[phy_idx][idx] = (unsigned int) inp[i];
+			if (++idx == CSIPHY_ONTHEGO_BUFSIZE) {
+				CAM_WARN(CAM_CSIPHY,
+					"Onthego input for PHY %d reached end of circular buffer, circling back",
+					phy_idx);
+				idx = idx % CSIPHY_ONTHEGO_BUFSIZE;
+			}
+		}
+	}
+
+	csiphy_onthego_reg_count[phy_idx] = idx;
+
+	if (outp) {
+		p = outp;
+		rc += scnprintf(p, PAGE_SIZE, "PHY idx %d: ", phy_idx);
+		for (i = 0; i < idx; i++)
+			rc += scnprintf(p + rc, PAGE_SIZE - rc, "0x%x,",
+				csiphy_onthego_regvals[phy_idx][i]);
+		rc += scnprintf(p + rc, PAGE_SIZE - rc, "\n");
+	}
+
+	return rc;
+}
 
 void cam_csiphy_update_auxiliary_mask(struct csiphy_device *csiphy_dev)
 {
@@ -172,23 +288,23 @@ static inline void cam_csiphy_apply_onthego_reg_values(void __iomem *csiphybase,
 
 	CAM_DBG(CAM_CSIPHY, "csiphy: %d, onthego_reg_count: %d",
 		csiphy_idx,
-		csiphy_onthego_reg_count);
+		csiphy_onthego_reg_count[csiphy_idx]);
 
-	if (csiphy_onthego_reg_count % 3)
-		csiphy_onthego_reg_count -= (csiphy_onthego_reg_count % 3);
+	for (i = 0; i < csiphy_onthego_reg_count[csiphy_idx]; i += 3) {
+		cam_io_w_mb(csiphy_onthego_regvals[csiphy_idx][i+1],
+			csiphybase + csiphy_onthego_regvals[csiphy_idx][i]);
 
-	for (i = 0; i < csiphy_onthego_reg_count; i += 3) {
-		cam_io_w_mb(csiphy_onthego_regs[i+1],
-			csiphybase + csiphy_onthego_regs[i]);
-
-		if (csiphy_onthego_regs[i+2])
-			usleep_range(csiphy_onthego_regs[i+2], csiphy_onthego_regs[i+2] + 5);
+		if (csiphy_onthego_regvals[csiphy_idx][i+2])
+			usleep_range(csiphy_onthego_regvals[csiphy_idx][i+2],
+				csiphy_onthego_regvals[csiphy_idx][i+2] + 5);
 
 		CAM_INFO(CAM_CSIPHY, "Offset: 0x%x, Val: 0x%x Delay(us): %u",
-			csiphy_onthego_regs[i],
-			cam_io_r_mb(csiphybase + csiphy_onthego_regs[i]),
-			csiphy_onthego_regs[i+2]);
+			csiphy_onthego_regvals[csiphy_idx][i],
+			cam_io_r_mb(csiphybase + csiphy_onthego_regvals[csiphy_idx][i]),
+			csiphy_onthego_regvals[csiphy_idx][i+2]);
 	}
+
+	csiphy_onthego_reg_count[csiphy_idx] = 0;
 }
 
 static inline int cam_csiphy_release_from_reset_state(struct csiphy_device *csiphy_dev,
@@ -2100,6 +2216,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 	csiphy_reg = csiphy_dev->ctrl_reg->csiphy_reg;
 	status_reg_ptr = csiphy_reg->status_reg_params;
 
+	if (!status_reg_ptr) {
+		CAM_ERR(CAM_CSIPHY, "CSIPHY %d status reg is NULL: %s",
+			soc_info->index, CAM_IS_NULL_TO_STR(status_reg_ptr));
+		return -EINVAL;
+	}
+
 	CAM_DBG(CAM_CSIPHY, "Opcode received: %d", cmd->op_code);
 	mutex_lock(&csiphy_dev->mutex);
 	switch (cmd->op_code) {
@@ -2715,12 +2837,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev,
 			goto hw_cnt_decrement;
 		}
 
-		if (csiphy_onthego_reg_count)
+		if (csiphy_onthego_reg_count[soc_info->index])
 			cam_csiphy_apply_onthego_reg_values(csiphybase, soc_info->index);
 
 		cam_csiphy_release_from_reset_state(csiphy_dev, csiphybase, offset);
 
-		if (g_phy_data[soc_info->index].is_3phase && status_reg_ptr) {
+		if (g_phy_data[soc_info->index].is_3phase) {
 			for (i = 0; i < CAM_CSIPHY_MAX_CPHY_LANES; i++) {
 				if (status_reg_ptr->cphy_lane_status[i]) {
 					cphy_trio_status = cam_io_r_mb(csiphybase +