summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/i2c/ccs-pll.c148
-rw-r--r--drivers/media/i2c/ccs-pll.h4
2 files changed, 95 insertions, 57 deletions
diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c
index 43735f6d0bb2..a6443589b948 100644
--- a/drivers/media/i2c/ccs-pll.c
+++ b/drivers/media/i2c/ccs-pll.c
@@ -46,12 +46,14 @@ static inline uint32_t one_or_more(uint32_t a)
}
static int bounds_check(struct device *dev, uint32_t val,
- uint32_t min, uint32_t max, char *str)
+ uint32_t min, uint32_t max, const char *prefix,
+ char *str)
{
if (val >= min && val <= max)
return 0;
- dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+ dev_dbg(dev, "%s_%s out of bounds: %d (%d--%d)\n", prefix,
+ str, val, min, max);
return -EINVAL;
}
@@ -81,7 +83,7 @@ static void print_pll(struct device *dev, struct ccs_pll *pll)
unsigned int which;
} branches[] = {
{ &pll->vt_fr, &pll->vt_bk, PLL_VT },
- { NULL, &pll->op_bk, PLL_OP }
+ { &pll->op_fr, &pll->op_bk, PLL_OP }
}, *br;
unsigned int i;
@@ -127,68 +129,90 @@ static void print_pll(struct device *dev, struct ccs_pll *pll)
pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "");
}
-static int check_all_bounds(struct device *dev,
- const struct ccs_pll_limits *lim,
- const struct ccs_pll_branch_limits_fr *op_lim_fr,
- const struct ccs_pll_branch_limits_bk *op_lim_bk,
- struct ccs_pll *pll,
- struct ccs_pll_branch_fr *op_pll_fr,
- struct ccs_pll_branch_bk *op_pll_bk)
+static int check_fr_bounds(struct device *dev,
+ const struct ccs_pll_limits *lim,
+ struct ccs_pll *pll, unsigned int which)
{
+ const struct ccs_pll_branch_limits_fr *lim_fr;
+ struct ccs_pll_branch_fr *pll_fr;
+ const char *s = pll_string(which);
int rval;
- rval = bounds_check(dev, op_pll_fr->pll_ip_clk_freq_hz,
- op_lim_fr->min_pll_ip_clk_freq_hz,
- op_lim_fr->max_pll_ip_clk_freq_hz,
- "pll_ip_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, op_pll_fr->pll_multiplier,
- op_lim_fr->min_pll_multiplier,
- op_lim_fr->max_pll_multiplier, "pll_multiplier");
- if (!rval)
- rval = bounds_check(
- dev, op_pll_fr->pll_op_clk_freq_hz,
- op_lim_fr->min_pll_op_clk_freq_hz,
- op_lim_fr->max_pll_op_clk_freq_hz, "pll_op_clk_freq_hz");
+ if (which == PLL_OP) {
+ lim_fr = &lim->op_fr;
+ pll_fr = &pll->op_fr;
+ } else {
+ lim_fr = &lim->vt_fr;
+ pll_fr = &pll->vt_fr;
+ }
+
+ rval = bounds_check(dev, pll_fr->pre_pll_clk_div,
+ lim_fr->min_pre_pll_clk_div,
+ lim_fr->max_pre_pll_clk_div, s, "pre_pll_clk_div");
+
if (!rval)
- rval = bounds_check(
- dev, op_pll_bk->sys_clk_div,
- op_lim_bk->min_sys_clk_div, op_lim_bk->max_sys_clk_div,
- "op_sys_clk_div");
+ rval = bounds_check(dev, pll_fr->pll_ip_clk_freq_hz,
+ lim_fr->min_pll_ip_clk_freq_hz,
+ lim_fr->max_pll_ip_clk_freq_hz,
+ s, "pll_ip_clk_freq_hz");
if (!rval)
- rval = bounds_check(
- dev, op_pll_bk->sys_clk_freq_hz,
- op_lim_bk->min_sys_clk_freq_hz,
- op_lim_bk->max_sys_clk_freq_hz,
- "op_sys_clk_freq_hz");
+ rval = bounds_check(dev, pll_fr->pll_multiplier,
+ lim_fr->min_pll_multiplier,
+ lim_fr->max_pll_multiplier,
+ s, "pll_multiplier");
if (!rval)
- rval = bounds_check(
- dev, op_pll_bk->pix_clk_freq_hz,
- op_lim_bk->min_pix_clk_freq_hz,
- op_lim_bk->max_pix_clk_freq_hz,
- "op_pix_clk_freq_hz");
+ rval = bounds_check(dev, pll_fr->pll_op_clk_freq_hz,
+ lim_fr->min_pll_op_clk_freq_hz,
+ lim_fr->max_pll_op_clk_freq_hz,
+ s, "pll_op_clk_freq_hz");
- /*
- * If there are no OP clocks, the VT clocks are contained in
- * the OP clock struct.
- */
- if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
- return rval;
+ return rval;
+}
+
+static int check_bk_bounds(struct device *dev,
+ const struct ccs_pll_limits *lim,
+ struct ccs_pll *pll, unsigned int which)
+{
+ const struct ccs_pll_branch_limits_bk *lim_bk;
+ struct ccs_pll_branch_bk *pll_bk;
+ const char *s = pll_string(which);
+ int rval;
+
+ if (which == PLL_OP) {
+ if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
+ return 0;
+ lim_bk = &lim->op_bk;
+ pll_bk = &pll->op_bk;
+ } else {
+ lim_bk = &lim->vt_bk;
+ pll_bk = &pll->vt_bk;
+ }
+
+ rval = bounds_check(dev, pll_bk->sys_clk_div,
+ lim_bk->min_sys_clk_div,
+ lim_bk->max_sys_clk_div, s, "op_sys_clk_div");
+ if (!rval)
+ rval = bounds_check(dev, pll_bk->sys_clk_freq_hz,
+ lim_bk->min_sys_clk_freq_hz,
+ lim_bk->max_sys_clk_freq_hz,
+ s, "sys_clk_freq_hz");
if (!rval)
- rval = bounds_check(
- dev, pll->vt_bk.sys_clk_freq_hz,
- lim->vt_bk.min_sys_clk_freq_hz,
- lim->vt_bk.max_sys_clk_freq_hz,
- "vt_sys_clk_freq_hz");
+ rval = bounds_check(dev, pll_bk->sys_clk_div,
+ lim_bk->min_sys_clk_div,
+ lim_bk->max_sys_clk_div,
+ s, "sys_clk_div");
if (!rval)
- rval = bounds_check(
- dev, pll->vt_bk.pix_clk_freq_hz,
- lim->vt_bk.min_pix_clk_freq_hz,
- lim->vt_bk.max_pix_clk_freq_hz,
- "vt_pix_clk_freq_hz");
+ rval = bounds_check(dev, pll_bk->pix_clk_freq_hz,
+ lim_bk->min_pix_clk_freq_hz,
+ lim_bk->max_pix_clk_freq_hz,
+ s, "pix_clk_freq_hz");
+
+ return rval;
+}
+static int check_ext_bounds(struct device *dev, struct ccs_pll *pll)
+{
if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING) &&
pll->pixel_rate_pixel_array > pll->pixel_rate_csi) {
dev_dbg(dev, "device does not support derating\n");
@@ -201,7 +225,7 @@ static int check_all_bounds(struct device *dev,
return -EINVAL;
}
- return rval;
+ return 0;
}
#define CPHY_CONST 7
@@ -610,11 +634,21 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
if (rval)
continue;
+ rval = check_fr_bounds(dev, lim, pll, PLL_VT);
+ if (rval)
+ continue;
+
+ rval = check_bk_bounds(dev, lim, pll, PLL_OP);
+ if (rval)
+ continue;
+
ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr,
op_pll_bk, cphy, phy_const);
- rval = check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll,
- op_pll_fr, op_pll_bk);
+ rval = check_bk_bounds(dev, lim, pll, PLL_VT);
+ if (rval)
+ continue;
+ rval = check_ext_bounds(dev, pll);
if (rval)
continue;
diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h
index 03c2428c76cd..6255803eee38 100644
--- a/drivers/media/i2c/ccs-pll.h
+++ b/drivers/media/i2c/ccs-pll.h
@@ -86,6 +86,7 @@ struct ccs_pll_branch_bk {
* (input)
* @vt_fr: Video timing front-end configuration (output)
* @vt_bk: Video timing back-end configuration (output)
+ * @op_fr: Operational timing front-end configuration (output)
* @op_bk: Operational timing back-end configuration (output)
* @pixel_rate_csi: Pixel rate on the output data bus (output)
* @pixel_rate_pixel_array: Nominal pixel rate in the sensor's pixel array
@@ -112,6 +113,7 @@ struct ccs_pll {
/* output values */
struct ccs_pll_branch_fr vt_fr;
struct ccs_pll_branch_bk vt_bk;
+ struct ccs_pll_branch_fr op_fr;
struct ccs_pll_branch_bk op_bk;
uint32_t pixel_rate_csi;
@@ -171,6 +173,7 @@ struct ccs_pll_branch_limits_bk {
* @max_ext_clk_freq_hz: Maximum external clock frequency
* @vt_fr: Video timing front-end limits
* @vt_bk: Video timing back-end limits
+ * @op_fr: Operational timing front-end limits
* @op_bk: Operational timing back-end limits
* @min_line_length_pck_bin: Minimum line length in pixels, with binning
* @min_line_length_pck: Minimum line length in pixels without binning
@@ -182,6 +185,7 @@ struct ccs_pll_limits {
struct ccs_pll_branch_limits_fr vt_fr;
struct ccs_pll_branch_limits_bk vt_bk;
+ struct ccs_pll_branch_limits_fr op_fr;
struct ccs_pll_branch_limits_bk op_bk;
/* Other relevant limits */