hw/misc/bcm2835_cprman: implement PLL channels behaviour
A PLL channel is able to further divide the generated PLL frequency. The divider is given in the CTRL_A2W register. Some channels have an additional fixed divider which is always applied to the signal. Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Luc Michel <luc@lmichel.fr> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
09d56bbc9b
commit
9574581112
@ -134,9 +134,40 @@ static const TypeInfo cprman_pll_info = {
|
||||
|
||||
/* PLL channel */
|
||||
|
||||
static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
|
||||
{
|
||||
/*
|
||||
* XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
|
||||
* not set it when enabling the channel, but does clear it when disabling
|
||||
* it.
|
||||
*/
|
||||
return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
|
||||
&& !(*channel->reg_cm & channel->hold_mask);
|
||||
}
|
||||
|
||||
static void pll_channel_update(CprmanPllChannelState *channel)
|
||||
{
|
||||
clock_update(channel->out, 0);
|
||||
uint64_t freq, div;
|
||||
|
||||
if (!pll_channel_is_enabled(channel)) {
|
||||
clock_update(channel->out, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
|
||||
|
||||
if (!div) {
|
||||
/*
|
||||
* It seems that when the divider value is 0, it is considered as
|
||||
* being maximum by the hardware (see the Linux driver).
|
||||
*/
|
||||
div = R_A2W_PLLx_CHANNELy_DIV_MASK;
|
||||
}
|
||||
|
||||
/* Some channels have an additional fixed divider */
|
||||
freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
|
||||
|
||||
clock_update_hz(channel->out, freq);
|
||||
}
|
||||
|
||||
/* Update a PLL and all its channels */
|
||||
|
Loading…
Reference in New Issue
Block a user