-
Notifications
You must be signed in to change notification settings - Fork 24
clk bcm2835.c clock management
The Linux common clock driver for the 2835 series lets you enable, disable, and set rates on any clock in the tree. The main caveat is that if the firmware-side clock code is going to be messing with that tree, then we need to stay away from it on the linux side.
An example of using a clock would be HDMI. In the DT for the HDMI device node we've got:
clocks = <&cprman BCM2835_PLLH_PIX>,
<&cprman BCM2835_CLOCK_HSM>;
clock-names = "pixel", "hdmi";
You can find all the clocks supported under include/dt-bindings/clock/bcm2835.h
Take a look at drivers/gpu/drm/vc4/vc4_hdmi.c
for an example of using the clocks. You get a struct clk *
reference to the clock with:
hdmi->pixel_clock = devm_clk_get(dev, "pixel");
if (IS_ERR(hdmi->pixel_clock)) {
DRM_ERROR("Failed to get pixel clock\n");
return PTR_ERR(hdmi->pixel_clock);
}
Setting the rate to a frequency (in Hz -- mode->clock is kHz) is:
clk_set_rate(vc4->hdmi->pixel_clock, mode->clock * 1000 *
((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1));
For the root PLLs, setting the rate adjusts the divider off of the external oscillator.
For the PLL channels, setting the rate will try to keep the parent rate the same if we can hit it exactly (see clk_divider_bestdiv()
in clk-divider.c
), but will otherwise adjust the root PLL to get the requested rate closer. This means that setting the rate of a PLLD channel is dangerous, since so many other clocks are hung off of PLLD channels.
For the leaf clocks (BCM2835_CLOCK_*
) the rate can only be set while the clock is off. They will choose a new parent PLL channel and divider as appropriate to get as close to the requested frequency as possible. It won't change the PLL divider's rate, though (see bcm2835_clock_determine_rate()
of clk-bcm8235.c
).
Turning on the clock is a matter of:
ret = clk_prepare_enable(hdmi->pixel_clock);
if (ret) {
DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
goto err_put_i2c;
}
This is refcounted, so when you're done with the clock you can drop the ref:
clk_disable_unprepare(hdmi->pixel_clock);
Note that we consider any CPRMAN clock (the leaves of the tree) that was on at boot as critical, and won't ever disable it.
At runtime, you can look at Linux's view of the clock tree with
sudo mkdir /debug
sudo mount -t debugfs debugfs /debug
cat /debug/clk/clk_summary
The rates there are the programmed rates. We don't yet do clock measurement for debug feedback yet, but on the rpi-4.4.y tree you can still use vcgencmd measure_clock
This won't reflect runtime changes of the clocks by the firmware.