Skip to content

Commit

Permalink
clk: bcm2835: Minimise clock jitter for PCM clock
Browse files Browse the repository at this point in the history
Fractional clock dividers generate accurate average frequencies but
with jitter, particularly when the integer divisor is small.

Introduce a new metric of clock accuracy to penalise clocks with a good
average but worse jitter compared to clocks with an average which is no
better but with lower jitter. The metric is the ideal rate minus the
worse deviation from that ideal using the nearest integer divisors.

Use this metric for parent selection for clocks requiring low jitter
(currently just PCM).

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
  • Loading branch information
Phil Elwell committed May 23, 2017
1 parent 4222b8d commit ab2c8a1
Showing 1 changed file with 34 additions and 5 deletions.
39 changes: 34 additions & 5 deletions drivers/clk/bcm/clk-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ struct bcm2835_clock_data {

bool is_vpu_clock;
bool is_mash_clock;
bool low_jitter;

u32 tcnt_mux;
};
Expand Down Expand Up @@ -1154,7 +1155,8 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
int parent_idx,
unsigned long rate,
u32 *div,
unsigned long *prate)
unsigned long *prate,
unsigned long *avgrate)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
Expand All @@ -1166,11 +1168,33 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
parent = clk_hw_get_parent_by_index(hw, parent_idx);

if (!(BIT(parent_idx) & data->set_rate_parent)) {
unsigned long tmp_rate;

*prate = clk_hw_get_rate(parent);
*div = bcm2835_clock_choose_div(hw, rate, *prate, true);

return bcm2835_clock_rate_from_divisor(clock, *prate,
*div);
tmp_rate = bcm2835_clock_rate_from_divisor(clock, *prate, *div);
*avgrate = tmp_rate;

if (data->low_jitter && (*div & CM_DIV_FRAC_MASK)) {
unsigned long high, low;
u32 idiv = *div & ~CM_DIV_FRAC_MASK;

high = bcm2835_clock_rate_from_divisor(clock, *prate,
idiv);
idiv += CM_DIV_FRAC_MASK + 1;
low = bcm2835_clock_rate_from_divisor(clock, *prate,
idiv);

/* Return a value which is the maximum deviation
* below the ideal rate, for use as a metric.
*/
if ((tmp_rate - low) < (high - tmp_rate))
tmp_rate = low;
else
tmp_rate -= high - tmp_rate;
}
return tmp_rate;
}

if (data->frac_bits)
Expand All @@ -1197,6 +1221,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,

*div = curdiv << CM_DIV_FRAC_BITS;
*prate = curdiv * best_rate;
*avgrate = best_rate;

return best_rate;
}
Expand All @@ -1208,6 +1233,7 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
bool current_parent_is_pllc;
unsigned long rate, best_rate = 0;
unsigned long prate, best_prate = 0;
unsigned long avgrate, best_avgrate = 0;
size_t i;
u32 div;

Expand All @@ -1232,11 +1258,13 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
continue;

rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate,
&div, &prate);
&div, &prate,
&avgrate);
if (rate > best_rate && rate <= req->rate) {
best_parent = parent;
best_prate = prate;
best_rate = rate;
best_avgrate = avgrate;
}
}

Expand All @@ -1246,7 +1274,7 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
req->best_parent_hw = best_parent;
req->best_parent_rate = best_prate;

req->rate = best_rate;
req->rate = best_avgrate;

return 0;
}
Expand Down Expand Up @@ -2061,6 +2089,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
.int_bits = 12,
.frac_bits = 12,
.is_mash_clock = true,
.low_jitter = true,
.parents = bcm2835_pcm_per_parents,
.tcnt_mux = 23),
[BCM2835_CLOCK_PWM] = REGISTER_PER_CLK(
Expand Down

0 comments on commit ab2c8a1

Please sign in to comment.