[PATCH 5/6] clk: bcm2835: correctly enable fractional clock support

Martin Sperl kernel at martin.sperl.org
Mon Feb 29 13:59:43 PST 2016


> On 29.02.2016, at 21:33, Eric Anholt <eric at anholt.net> wrote:
> 
> kernel at martin.sperl.org writes:
> 
>> From: Martin Sperl <kernel at martin.sperl.org>
>> 
>> The current driver calculates the clock divider with
>> fractional support enabled.
>> 
>> But it does not enable fractional support in the
>> control register itself resulting in an integer only divider,
>> but in clk_set_rate responds back the fractionally divided
>> clock frequency.
>> 
>> This patch enables fractional support in the control register
>> whenever there is a fractional bit set in the requested clock divider.
>> 
>> Mash clock limits are are also handled for the PWM clock
>> applying the correct divider limits (2 and max_int) applicable to
>> basic fractional divider support (mash order of 1).
>> 
>> It also adds locking to protect the read/modify/write cycle of
>> the register modification.
>> 
>> Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the
>> audio domain clocks")
>> 
>> Signed-off-by: Martin Sperl <kernel at martin.sperl.org>
> 
> Rewrite of the commit message:
> 
> The driver has been using fractional dividers for all clocks with
> fractional bits.  However, MASH clocks (those used to drive audio) only
> do fractional division when in MASH mode, which is used to push clock
> jitter out of the audio band.  The PWM clock (used to drive i2s audio)
> is the only MASH clock currently enabled in the driver.
> 
> Additional MASH modes are available that widen the frequency range, but
> only 1-level MASH is used for now, until we characterize some better
> policy.
> 
> Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the
> audio domain clocks”)

That is not 100% true - non mash modes have CM_FRAC and CM_FRAC = CM_MASH0
so these map each other

And for a non-mash clock if CM_FRAC is not set then the factual divider
support is not used and only the integer portion is used.
This results in a frequency that is to high (as the frac bits are missing).

Just to giv an example of firmware set clock for the timer:
root at raspcm:~# head /sys/kernel/debug/clk/timer/current_*
==> /sys/kernel/debug/clk/timer/current_divf <==
819

==> /sys/kernel/debug/clk/timer/current_divi <==
19

==> /sys/kernel/debug/clk/timer/current_frac <==
1

==> /sys/kernel/debug/clk/timer/current_parent <==
xosc

root at raspcm:~# head /sys/kernel/debug/clk/timer/regdump
ctl = 0x00000291
div = 0x00013333

So this - non mash - clock has frac set by default
and this clock is set up by the firmware!

Similar things for: hsm and uart - all of them are “normal”
clocks and they have the CM_FRAC bit set and divf > 0.

So the code essentially sets:
* CM_FRAC for “normal” clocks
* CM_MASH0 for mash clocks
when the divider has a fract component.

So I believe my description is correct.

But anyway: except for the pcm clocks clk_set_rate
is not really being used right now, as we still consume
the clocks set up by the firmware.

The comment portion about mash-order=1 could probably get added.

As for enabling higher order mash modes - at least in the audio
domain using I2S I have done some interresting measurements
making use of all the variations (and clock selections).

The result there was that - at least with the DAC that I 
am using - the noise level varies widely between
different mash modes and clock dividers.

So the “lowest” noise showed the following combinations:
osc-mash3
pllc-mash2
osc-mash1
osc-non-frac (optimized so that we may use integer divider)
osc-mash2
pllc-mash1
pllc-mash3

So the "selection” of clocks/divider/mash is really requiring
fine tuning and measurement - because there is no real pattern
visible.

Here a graph showing the audio spectrum for the different
modes with a 400Hz signal:
https://cloud.githubusercontent.com/assets/2638784/13278003/20e09002-dacd-11e5-8d62-17eb7118a4fa.jpg

> 
> This is just the low bit of the 2-bit CM_MASH field at 9:10.  So you're
> enabling MASH mode 1 in this patch.  Similarly, the subject of the patch
> should be something like "Fix MASH-based fractional clock support for
> PWM" since all the other clocks work with fractional already.
> 

As explained above: no they do not work without setting the FRAC bit!

Take again the example of timer:
when not using FRAC you get a timer clock of:
1010526Hz while with FRAC you get 1000002 Hz

So you NEED to set FRAC for all.
>> 
>> 
>> +	ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC;
>> +	ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0;
>> +	cprman_write(cprman, data->ctl_reg, ctl);
> 
> This should all be under "if (data->is_mash_clock) {}" since it doesn't
> do anything on non-mash clocks.
Again: without CM_FRAC you get a frequency that is too high, so it
needs to be implemented for all - independent of if it is a mash clock
or a FRAC clock.
The only cases where it does not apply is for clocks that have no fract
bits at all.






More information about the linux-arm-kernel mailing list