Skip to content

Instantly share code, notes, and snippets.

@HiassofT
Created January 20, 2016 11:40
Show Gist options
  • Save HiassofT/5f458fdec1e6aec33d12 to your computer and use it in GitHub Desktop.
Save HiassofT/5f458fdec1e6aec33d12 to your computer and use it in GitHub Desktop.
jitter optimized parent selection - untested, don't use
/*
* Jitter-optimized parent selection for fractional divisor mode
*
* Find a rate that's near to the requested rate and can be
* generated with the lowest possible jitter.
*
* All rates that can be derived from parents by using an integer
* divisor are possible candidates, the one which is nearest
* to the requested rate is selected as an intermediate result.
*
* If we already found a perfect rate match we can stop searching.
*
* Otherwise find the parent with the highest clock rate that
* can generate a rate near to the requested one in fractional
* mode. If that resulting rate is nearer to the requested one,
* use it.
*/
static int bcm2835_clock_determine_rate_jitter_optimized(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
struct clk_hw *parent, *best_parent = NULL;
unsigned long rate, best_rate = 0;
unsigned long prate, best_prate = 0;
unsigned long deviation, best_deviation = ULONG_MAX;
size_t i;
divmash dm;
u32 div;
size_t nonnull_parents = 0;
size_t num_parents = clk_hw_get_num_parents(hw);
struct clk_hw **parents_sorted;
if (!num_parents)
return -EINVAL;
parents_sorted = kcalloc(num_parents, sizeof(struct clk_hw),
GFP_KERNEL);
if (!parents_sorted)
return -ENOMEM;
/*
* Select parent clock that results in the closest rate,
* without allowing fractional dividers.
* Also populate to parents_sorted array with non-null parents.
*/
for (i = 0; i < num_parents; ++i) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
parents_sorted[nonnull_parents++] = parent;
prate = clk_hw_get_rate(parent);
dm = bcm2835_clock_choose_div(hw, req->rate, prate,
true, false);
div = divmash_get_div(dm);
rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
deviation = (rate < req->rate) ?
(req->rate - rate) : (rate - req->rate);
if (deviation < best_deviation && rate >= req->min_rate &&
rate <= req->max_rate) {
best_parent = parent;
best_prate = prate;
best_rate = rate;
best_deviation = deviation;
}
}
if (nonnull_parents && (best_rate != req->rate)) {
sort(parents_sorted, nonnull_parents, sizeof(struct clk_hw *),
bcm2835_cmp_clk_rate_higher, NULL);
/*
* Iterate over the parents in descending clock rate,
* allowing fractional divisors.
*/
for (i = 0; i < nonnull_parents; ++i) {
parent = parents_sorted[i];
prate = clk_hw_get_rate(parent);
dm = bcm2835_clock_choose_div(hw, req->rate, prate,
true, true);
div = divmash_get_div(dm);
rate = bcm2835_clock_rate_from_divisor(
clock, prate, div);
/*
* Reject parents where choose_div clamped (rate
* is outside range) or changed mash mode to something
* else than NONE or data->mash (which can happen when
* on clamping, too).
*/
if (rate >= req->min_rate &&
rate <= req->max_rate &&
!divmash_get_clamped(dm) &&
((divmash_get_mash(dm) == data->mash) ||
(divmash_get_mash(dm) == MASH_NONE))) {
deviation = (rate < req->rate) ?
(req->rate - rate) : (rate - req->rate);
/*
* Only use this parent if we are better than
* integer clocks. If we get the same best rate
* as before, use the integer clock
*/
if (deviation < best_deviation) {
best_parent = parent;
best_prate = prate;
best_rate = rate;
best_deviation = deviation;
}
break;
}
}
}
kfree(parents_sorted);
if (!best_parent)
return -EINVAL;
req->best_parent_hw = best_parent;
req->best_parent_rate = best_prate;
req->rate = best_rate;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment