aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/smiapp-pll.c
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@iki.fi>2012-10-22 15:27:27 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-10-29 07:49:30 -0400
commit6de1b143a45d3c4b8ad277b484e0d14df0d30d63 (patch)
tree7776cc0963b1f3793713f7d07e4411990d9c1ba1 /drivers/media/i2c/smiapp-pll.c
parentc2ebca00324ce7b89f756d5e182a5b3db938a4c9 (diff)
[media] smiapp-pll: Try other pre-pll divisors
The smiapp pll calculator assumed that the minimum pre-pll divisor was perfect. That may not always be the case, so let's try the others, too. Typically there are just a few alternatives. Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/smiapp-pll.c')
-rw-r--r--drivers/media/i2c/smiapp-pll.c131
1 files changed, 73 insertions, 58 deletions
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
index e92dc46e6221..d7e347594e19 100644
--- a/drivers/media/i2c/smiapp-pll.c
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -58,7 +58,7 @@ static int bounds_check(struct device *dev, uint32_t val,
58 if (val >= min && val <= max) 58 if (val >= min && val <= max)
59 return 0; 59 return 0;
60 60
61 dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); 61 dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
62 62
63 return -EINVAL; 63 return -EINVAL;
64} 64}
@@ -87,14 +87,14 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll)
87 dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz); 87 dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
88} 88}
89 89
90int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, 90static int __smiapp_pll_calculate(struct device *dev,
91 struct smiapp_pll *pll) 91 struct smiapp_pll_limits *limits,
92 struct smiapp_pll *pll, uint32_t mul,
93 uint32_t div, uint32_t lane_op_clock_ratio)
92{ 94{
93 uint32_t sys_div; 95 uint32_t sys_div;
94 uint32_t best_pix_div = INT_MAX >> 1; 96 uint32_t best_pix_div = INT_MAX >> 1;
95 uint32_t vt_op_binning_div; 97 uint32_t vt_op_binning_div;
96 uint32_t lane_op_clock_ratio;
97 uint32_t mul, div;
98 uint32_t more_mul_min, more_mul_max; 98 uint32_t more_mul_min, more_mul_max;
99 uint32_t more_mul_factor; 99 uint32_t more_mul_factor;
100 uint32_t min_vt_div, max_vt_div, vt_div; 100 uint32_t min_vt_div, max_vt_div, vt_div;
@@ -102,54 +102,6 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
102 unsigned int i; 102 unsigned int i;
103 int rval; 103 int rval;
104 104
105 if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
106 lane_op_clock_ratio = pll->lanes;
107 else
108 lane_op_clock_ratio = 1;
109 dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
110
111 dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
112 pll->binning_vertical);
113
114 /* CSI transfers 2 bits per clock per lane; thus times 2 */
115 pll->pll_op_clk_freq_hz = pll->link_freq * 2
116 * (pll->lanes / lane_op_clock_ratio);
117
118 /* Figure out limits for pre-pll divider based on extclk */
119 dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
120 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
121 limits->max_pre_pll_clk_div =
122 min_t(uint16_t, limits->max_pre_pll_clk_div,
123 clk_div_even(pll->ext_clk_freq_hz /
124 limits->min_pll_ip_freq_hz));
125 limits->min_pre_pll_clk_div =
126 max_t(uint16_t, limits->min_pre_pll_clk_div,
127 clk_div_even_up(
128 DIV_ROUND_UP(pll->ext_clk_freq_hz,
129 limits->max_pll_ip_freq_hz)));
130 dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
131 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
132
133 i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
134 mul = div_u64(pll->pll_op_clk_freq_hz, i);
135 div = pll->ext_clk_freq_hz / i;
136 dev_dbg(dev, "mul %d / div %d\n", mul, div);
137
138 limits->min_pre_pll_clk_div =
139 max_t(uint16_t, limits->min_pre_pll_clk_div,
140 clk_div_even_up(
141 DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
142 limits->max_pll_op_freq_hz)));
143 dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
144 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
145
146 if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
147 dev_err(dev, "unable to compute pre_pll divisor\n");
148 return -EINVAL;
149 }
150
151 pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
152
153 /* 105 /*
154 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be 106 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
155 * too high. 107 * too high.
@@ -193,8 +145,8 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
193 more_mul_min); 145 more_mul_min);
194 146
195 if (more_mul_min > more_mul_max) { 147 if (more_mul_min > more_mul_max) {
196 dev_warn(dev, 148 dev_dbg(dev,
197 "unable to compute more_mul_min and more_mul_max\n"); 149 "unable to compute more_mul_min and more_mul_max\n");
198 return -EINVAL; 150 return -EINVAL;
199 } 151 }
200 152
@@ -209,7 +161,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
209 161
210 dev_dbg(dev, "final more_mul: %d\n", i); 162 dev_dbg(dev, "final more_mul: %d\n", i);
211 if (i > more_mul_max) { 163 if (i > more_mul_max) {
212 dev_warn(dev, "final more_mul is bad, max %d\n", more_mul_max); 164 dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max);
213 return -EINVAL; 165 return -EINVAL;
214 } 166 }
215 167
@@ -354,8 +306,6 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
354 pll->pixel_rate_csi = 306 pll->pixel_rate_csi =
355 pll->op_pix_clk_freq_hz * lane_op_clock_ratio; 307 pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
356 308
357 print_pll(dev, pll);
358
359 rval = bounds_check(dev, pll->pre_pll_clk_div, 309 rval = bounds_check(dev, pll->pre_pll_clk_div,
360 limits->min_pre_pll_clk_div, 310 limits->min_pre_pll_clk_div,
361 limits->max_pre_pll_clk_div, "pre_pll_clk_div"); 311 limits->max_pre_pll_clk_div, "pre_pll_clk_div");
@@ -411,6 +361,71 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
411 361
412 return rval; 362 return rval;
413} 363}
364
365int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
366 struct smiapp_pll *pll)
367{
368 uint32_t lane_op_clock_ratio;
369 uint32_t mul, div;
370 unsigned int i;
371 int rval = -EINVAL;
372
373 if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
374 lane_op_clock_ratio = pll->lanes;
375 else
376 lane_op_clock_ratio = 1;
377 dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
378
379 dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
380 pll->binning_vertical);
381
382 /* CSI transfers 2 bits per clock per lane; thus times 2 */
383 pll->pll_op_clk_freq_hz = pll->link_freq * 2
384 * (pll->lanes / lane_op_clock_ratio);
385
386 /* Figure out limits for pre-pll divider based on extclk */
387 dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
388 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
389 limits->max_pre_pll_clk_div =
390 min_t(uint16_t, limits->max_pre_pll_clk_div,
391 clk_div_even(pll->ext_clk_freq_hz /
392 limits->min_pll_ip_freq_hz));
393 limits->min_pre_pll_clk_div =
394 max_t(uint16_t, limits->min_pre_pll_clk_div,
395 clk_div_even_up(
396 DIV_ROUND_UP(pll->ext_clk_freq_hz,
397 limits->max_pll_ip_freq_hz)));
398 dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
399 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
400
401 i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
402 mul = div_u64(pll->pll_op_clk_freq_hz, i);
403 div = pll->ext_clk_freq_hz / i;
404 dev_dbg(dev, "mul %d / div %d\n", mul, div);
405
406 limits->min_pre_pll_clk_div =
407 max_t(uint16_t, limits->min_pre_pll_clk_div,
408 clk_div_even_up(
409 DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
410 limits->max_pll_op_freq_hz)));
411 dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
412 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
413
414 for (pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
415 pll->pre_pll_clk_div <= limits->max_pre_pll_clk_div;
416 pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
417 rval = __smiapp_pll_calculate(dev, limits, pll, mul, div,
418 lane_op_clock_ratio);
419 if (rval)
420 continue;
421
422 print_pll(dev, pll);
423 return 0;
424 }
425
426 dev_info(dev, "unable to compute pre_pll divisor\n");
427 return rval;
428}
414EXPORT_SYMBOL_GPL(smiapp_pll_calculate); 429EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
415 430
416MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); 431MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");