Created
January 20, 2016 11:40
-
-
Save HiassofT/5f458fdec1e6aec33d12 to your computer and use it in GitHub Desktop.
jitter optimized parent selection - untested, don't use
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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