/** * omap2_dpll_round_rate - round a target rate for an OMAP DPLL * @clk: struct clk * for a DPLL * @target_rate: desired DPLL clock rate * * Given a DPLL and a desired target rate, round the target rate to a * possible, programmable rate for this DPLL. Attempts to select the * minimum possible n. Stores the computed (m, n) in the DPLL's * dpll_data structure so set_rate() will not need to call this * (expensive) function again. Returns ~0 if the target rate cannot * be rounded, or the rounded rate upon success. */ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { int m, n, r, scaled_max_m; unsigned long scaled_rt_rp; unsigned long new_rate = 0; struct dpll_data *dd; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", clk->name, target_rate); scaled_rt_rp = DIV_ROUND_CLOSEST(target_rate, dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { if (cpu_is_omap34xx()) { /* Is the (input clk, divider)pair valid for the DPLL?*/ r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; } /* Compute the scaled DPLL multiplier, based on the divider */ m = scaled_rt_rp * n; /* * Since we're counting n up, a m overflow means we * can bail out completely (since as n increases in * the next iteration, there's no way that m can * increase beyond the current m) */ if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, dd->clk_ref->rate); /* m can't be set low enough for this n - try with a larger n */ if (r == DPLL_MULT_UNDERFLOW) continue; pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n", clk->name, m, n, new_rate); if (target_rate == new_rate) { dd->last_rounded_m = m; dd->last_rounded_n = n; dd->last_rounded_rate = target_rate; break; } } if (target_rate != new_rate) { pr_debug("clock: %s: cannot round to rate %ld\n", clk->name, target_rate); return ~0; } return target_rate; }
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { int m, n, r, scaled_max_m; unsigned long scaled_rt_rp; unsigned long new_rate = 0; struct dpll_data *dd; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", clk->name, target_rate); scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; m = scaled_rt_rp * n; if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, dd->clk_ref->rate); if (r == DPLL_MULT_UNDERFLOW) continue; pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n", clk->name, m, n, new_rate); if (target_rate == new_rate) { dd->last_rounded_m = m; dd->last_rounded_n = n; dd->last_rounded_rate = target_rate; break; } } if (target_rate != new_rate) { pr_debug("clock: %s: cannot round to rate %ld\n", clk->name, target_rate); return ~0; } return target_rate; }
/** * omap2_dpll_round_rate - round a target rate for an OMAP DPLL * @clk: struct clk * for a DPLL * @target_rate: desired DPLL clock rate * * Given a DPLL, a desired target rate, and a rate tolerance, round * the target rate to a possible, programmable rate for this DPLL. * Rate tolerance is assumed to be set by the caller before this * function is called. Attempts to select the minimum possible n * within the tolerance to reduce power consumption. Stores the * computed (m, n) in the DPLL's dpll_data structure so set_rate() * will not need to call this (expensive) function again. Returns ~0 * if the target rate cannot be rounded, either because the rate is * too low or because the rate tolerance is set too tightly; or the * rounded rate upon success. */ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { int m, n, r, e, scaled_max_m; unsigned long scaled_rt_rp, new_rate; int min_e = -1, min_e_m = -1, min_e_n = -1; struct dpll_data *dd; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; pr_debug("clock: starting DPLL round_rate for clock %s, target rate " "%ld\n", clk->name, target_rate); scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { /* Is the (input clk, divider) pair valid for the DPLL? */ r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; /* Compute the scaled DPLL multiplier, based on the divider */ m = scaled_rt_rp * n; /* * Since we're counting n up, a m overflow means we * can bail out completely (since as n increases in * the next iteration, there's no way that m can * increase beyond the current m) */ if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, dd->clk_ref->rate); /* m can't be set low enough for this n - try with a larger n */ if (r == DPLL_MULT_UNDERFLOW) continue; e = target_rate - new_rate; pr_debug("clock: n = %d: m = %d: rate error is %d " "(new_rate = %ld)\n", n, m, e, new_rate); if (min_e == -1 || min_e >= (int)(abs(e) - dd->rate_tolerance)) { min_e = e; min_e_m = m; min_e_n = n; pr_debug("clock: found new least error %d\n", min_e); /* We found good settings -- bail out now */ if (min_e <= dd->rate_tolerance) break; } } if (min_e < 0) { pr_debug("clock: error: target rate or tolerance too low\n"); return ~0; } dd->last_rounded_m = min_e_m; dd->last_rounded_n = min_e_n; dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, min_e_m, min_e_n); pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", min_e, min_e_m, min_e_n); pr_debug("clock: final rate: %ld (target rate: %ld)\n", dd->last_rounded_rate, target_rate); return dd->last_rounded_rate; }
/** * omap2_dpll_round_rate - round a target rate for an OMAP DPLL * @clk: struct clk * for a DPLL * @target_rate: desired DPLL clock rate * * Given a DPLL and a desired target rate, round the target rate to a * possible, programmable rate for this DPLL. Attempts to select the * minimum possible n. Stores the computed (m, n) in the DPLL's * dpll_data structure so set_rate() will not need to call this * (expensive) function again. Returns ~0 if the target rate cannot * be rounded, or the rounded rate upon success. */ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); int m, n, r, scaled_max_m; int min_delta_m = INT_MAX, min_delta_n = INT_MAX; unsigned long scaled_rt_rp; unsigned long new_rate = 0; struct dpll_data *dd; unsigned long ref_rate; long delta; long prev_min_delta = LONG_MAX; const char *clk_name; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; if (dd->max_rate && target_rate > dd->max_rate) target_rate = dd->max_rate; ref_rate = __clk_get_rate(dd->clk_ref); clk_name = __clk_get_name(hw->clk); pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n", clk_name, target_rate); scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { /* Is the (input clk, divider) pair valid for the DPLL? */ r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; /* Compute the scaled DPLL multiplier, based on the divider */ m = scaled_rt_rp * n; /* * Since we're counting n up, a m overflow means we * can bail out completely (since as n increases in * the next iteration, there's no way that m can * increase beyond the current m) */ if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, ref_rate); /* m can't be set low enough for this n - try with a larger n */ if (r == DPLL_MULT_UNDERFLOW) continue; /* skip rates above our target rate */ delta = target_rate - new_rate; if (delta < 0) continue; if (delta < prev_min_delta) { prev_min_delta = delta; min_delta_m = m; min_delta_n = n; } pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n", clk_name, m, n, new_rate); if (delta == 0) break; } if (prev_min_delta == LONG_MAX) { pr_debug("clock: %s: cannot round to rate %lu\n", clk_name, target_rate); return ~0; } dd->last_rounded_m = min_delta_m; dd->last_rounded_n = min_delta_n; dd->last_rounded_rate = target_rate - prev_min_delta; return dd->last_rounded_rate; }
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { int m, n, r, e, scaled_max_m; unsigned long scaled_rt_rp, new_rate; int min_e = -1, min_e_m = -1, min_e_n = -1; struct dpll_data *dd; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; pr_debug("clock: starting DPLL round_rate for clock %s, target rate " "%ld\n", clk->name, target_rate); scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; m = scaled_rt_rp * n; if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, dd->clk_ref->rate); if (r == DPLL_MULT_UNDERFLOW) continue; e = target_rate - new_rate; pr_debug("clock: n = %d: m = %d: rate error is %d " "(new_rate = %ld)\n", n, m, e, new_rate); if (min_e == -1 || min_e >= (int)(abs(e) - dd->rate_tolerance)) { min_e = e; min_e_m = m; min_e_n = n; pr_debug("clock: found new least error %d\n", min_e); if (min_e <= dd->rate_tolerance) break; } } if (min_e < 0) { pr_debug("clock: error: target rate or tolerance too low\n"); return ~0; } dd->last_rounded_m = min_e_m; dd->last_rounded_n = min_e_n; dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, min_e_m, min_e_n); pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", min_e, min_e_m, min_e_n); pr_debug("clock: final rate: %ld (target rate: %ld)\n", dd->last_rounded_rate, target_rate); return dd->last_rounded_rate; }
/** * omap2_dpll_round_rate - round a target rate for an OMAP DPLL * @clk: struct clk * for a DPLL * @target_rate: desired DPLL clock rate * * Given a DPLL and a desired target rate, round the target rate to a * possible, programmable rate for this DPLL. Attempts to select the * minimum possible n. Stores the computed (m, n) in the DPLL's * dpll_data structure so set_rate() will not need to call this * (expensive) function again. Returns ~0 if the target rate cannot * be rounded, or the rounded rate upon success. */ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { int m, n, r, scaled_max_m; unsigned long scaled_rt_rp; unsigned long new_rate = 0; struct dpll_data *dd; unsigned long bestrate = 0, diff, bestdiff = ULONG_MAX; int bestm = 0, bestn = 0; struct dpll_rate_list *rs, *rate_cache; if (!clk || !clk->dpll_data) return ~0; dd = clk->dpll_data; rate_cache = dd->rate_cache; for (rs = rate_cache; rs; rs = rs->next) if (rs->target_rate == target_rate) { dd->last_rounded_m = rs->m; dd->last_rounded_n = rs->n; dd->last_rounded_rate = rs->actual_rate; return rs->actual_rate; } pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", clk->name, target_rate); scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; dd->last_rounded_rate = 0; for (n = dd->min_divider; n <= dd->max_divider; n++) { /* Is the (input clk, divider) pair valid for the DPLL? */ r = _dpll_test_fint(clk, n); if (r == DPLL_FINT_UNDERFLOW) break; else if (r == DPLL_FINT_INVALID) continue; /* Compute the scaled DPLL multiplier, based on the divider */ m = scaled_rt_rp * n; /* * Since we're counting n up, a m overflow means we * can bail out completely (since as n increases in * the next iteration, there's no way that m can * increase beyond the current m) */ if (m > scaled_max_m) break; r = _dpll_test_mult(&m, n, &new_rate, target_rate, dd->clk_ref->rate); /* m can't be set low enough for this n - try with a larger n */ if (r == DPLL_MULT_UNDERFLOW) continue; #ifdef DEBUG pr_err("clock: target=%ld %s: m = %d: n = %d: new_rate = %ld\n", target_rate, clk->name, m, n, new_rate); #endif if (target_rate > new_rate) diff = target_rate - new_rate; else diff = new_rate - target_rate; if (diff < bestdiff) { bestm = m; bestn = n; bestrate = new_rate; bestdiff = diff; } if (new_rate == target_rate) break; } /* * The following if verifies that the new frequency is within 0.01% of * the target frequency. */ if (bestdiff < (ULONG_MAX / 10000) && ((bestdiff * 10000) / target_rate) < 1) { dd->last_rounded_m = bestm; dd->last_rounded_n = bestn; dd->last_rounded_rate = bestrate; rs = kzalloc(sizeof (struct dpll_rate_list), GFP_ATOMIC); if (rs) { rs->m = bestm; rs->n = bestn; rs->target_rate = target_rate; rs->actual_rate = bestrate; if (rate_cache == dd->rate_cache) { rs->next = dd->rate_cache; dd->rate_cache = rs; } else kzfree(rs); } return bestrate; } else return 0; }