|
@@ -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 +
|