aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/dpll3xxx.c
diff options
context:
space:
mode:
authorJon Hunter <jon-hunter@ti.com>2012-12-15 03:35:46 -0500
committerPaul Walmsley <paul@pwsan.com>2012-12-15 03:35:46 -0500
commit3ff51ed8287d3d2c7899f18f0487348e3448afb5 (patch)
treef0e7d354eb490bba562e2a5ee2ea5334cca2a9cb /arch/arm/mach-omap2/dpll3xxx.c
parent9b4fcc86941ec0c12b27fefa39dc85e32244dc64 (diff)
ARM: OMAP4: Enhance support for DPLLs with 4X multiplier
On OMAP4 devices, the ABE DPLL has an internal 4X multiplier that can be enabled or disabled in addition to the standard configurable multiplier (M) for OMAP DPLLs. When configuring the ABE DPLL the 4X multiplier is accounted for by checking to see whether it is enabled or not. However, when calculating a new rate we only check to see if the rate can be achieved with the current setting for the 4X multiplier. Enhance the round_rate() function for such DPLLs to see if the rate can be achieved with the 4X multiplier if it cannot be achieved without the 4X multiplier. This change is necessary, because when using the 32kHz clock as the source clock for the ABE DPLL, the default DPLL frequency for the ABE DPLL cannot be achieved without enabling the 4X multiplier. When using the 32kHz clock as the source clock for the ABE DPLL and attempting to lock the DPLL to 98.304MHz (default frequency), it was found that the DPLL would fail to lock if the low-power mode for the DPLL was not enabled. From reviewing boot-loader settings that configure the ABE DPLL it was found that the low-power mode is enabled when using the 32kHz clock source, however, the documentation for OMAP does not state that this is a requirement. Therefore, introduce a new function for OMAP4 devices to see if low-power mode can be enabled when calculating a new rate to ensure the DPLL will lock. New variables for the last calculated 4X multiplier and low-power setting have been added to the dpll data structure as well as variables defining the bit mask for enabling these features via the DPLL's control_reg. It is possible that we could eliminate these bit masks from the dpll data structure as these bit masks are not unique to OMAP4, if it is preferred. The function omap3_noncore_program_dpll() has been updated to avoid passing the calculated values for the multiplier (M) and divider (N) as these are stored in the clk structure. Signed-off-by: Jon Hunter <jon-hunter@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2/dpll3xxx.c')
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index fafb28c0dcbc..2bb18838cba9 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -291,16 +291,13 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
291 291
292/* 292/*
293 * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly 293 * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
294 * @clk: struct clk * of DPLL to set 294 * @clk: struct clk * of DPLL to set
295 * @m: DPLL multiplier to set 295 * @freqsel: FREQSEL value to set
296 * @n: DPLL divider to set
297 * @freqsel: FREQSEL value to set
298 * 296 *
299 * Program the DPLL with the supplied M, N values, and wait for the DPLL to 297 * Program the DPLL with the last M, N values calculated, and wait for
300 * lock.. Returns -EINVAL upon error, or 0 upon success. 298 * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
301 */ 299 */
302static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n, 300static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
303 u16 freqsel)
304{ 301{
305 struct dpll_data *dd = clk->dpll_data; 302 struct dpll_data *dd = clk->dpll_data;
306 u8 dco, sd_div; 303 u8 dco, sd_div;
@@ -323,23 +320,45 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n,
323 /* Set DPLL multiplier, divider */ 320 /* Set DPLL multiplier, divider */
324 v = __raw_readl(dd->mult_div1_reg); 321 v = __raw_readl(dd->mult_div1_reg);
325 v &= ~(dd->mult_mask | dd->div1_mask); 322 v &= ~(dd->mult_mask | dd->div1_mask);
326 v |= m << __ffs(dd->mult_mask); 323 v |= dd->last_rounded_m << __ffs(dd->mult_mask);
327 v |= (n - 1) << __ffs(dd->div1_mask); 324 v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
328 325
329 /* Configure dco and sd_div for dplls that have these fields */ 326 /* Configure dco and sd_div for dplls that have these fields */
330 if (dd->dco_mask) { 327 if (dd->dco_mask) {
331 _lookup_dco(clk, &dco, m, n); 328 _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
332 v &= ~(dd->dco_mask); 329 v &= ~(dd->dco_mask);
333 v |= dco << __ffs(dd->dco_mask); 330 v |= dco << __ffs(dd->dco_mask);
334 } 331 }
335 if (dd->sddiv_mask) { 332 if (dd->sddiv_mask) {
336 _lookup_sddiv(clk, &sd_div, m, n); 333 _lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
334 dd->last_rounded_n);
337 v &= ~(dd->sddiv_mask); 335 v &= ~(dd->sddiv_mask);
338 v |= sd_div << __ffs(dd->sddiv_mask); 336 v |= sd_div << __ffs(dd->sddiv_mask);
339 } 337 }
340 338
341 __raw_writel(v, dd->mult_div1_reg); 339 __raw_writel(v, dd->mult_div1_reg);
342 340
341 /* Set 4X multiplier and low-power mode */
342 if (dd->m4xen_mask || dd->lpmode_mask) {
343 v = __raw_readl(dd->control_reg);
344
345 if (dd->m4xen_mask) {
346 if (dd->last_rounded_m4xen)
347 v |= dd->m4xen_mask;
348 else
349 v &= ~dd->m4xen_mask;
350 }
351
352 if (dd->lpmode_mask) {
353 if (dd->last_rounded_lpmode)
354 v |= dd->lpmode_mask;
355 else
356 v &= ~dd->lpmode_mask;
357 }
358
359 __raw_writel(v, dd->control_reg);
360 }
361
343 /* We let the clock framework set the other output dividers later */ 362 /* We let the clock framework set the other output dividers later */
344 363
345 /* REVISIT: Set ramp-up delay? */ 364 /* REVISIT: Set ramp-up delay? */
@@ -492,8 +511,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
492 pr_debug("%s: %s: set rate: locking rate to %lu.\n", 511 pr_debug("%s: %s: set rate: locking rate to %lu.\n",
493 __func__, __clk_get_name(hw->clk), rate); 512 __func__, __clk_get_name(hw->clk), rate);
494 513
495 ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, 514 ret = omap3_noncore_dpll_program(clk, freqsel);
496 dd->last_rounded_n, freqsel);
497 if (!ret) 515 if (!ret)
498 new_parent = dd->clk_ref; 516 new_parent = dd->clk_ref;
499 } 517 }