diff --git a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 64299c3ea0..840bb0171d 100644 --- a/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/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, @@ -2102,6 +2218,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) { @@ -2717,12 +2839,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 +