The Xilinx Zynq Ultrascale devices seem to have this covered, but I struggled to find much info on how to do this with the Zynq 7000 parts. Here’s my notes on both platforms.
With a 4.19 kernel, the Xilinx PL clock enabler (XILINX_FCLK) is the driver you need. This will expose any compatible = “xlnx,fclk” device-tree nodes to userspace through sysfs. On Zynq this is something like
# echo 150000000 > /sys/devices/soc0/fclk0/set_rate # cat /sys/devices/soc0/fclk0/set_rate 142857142 # obviously some PLL rounding to deal with
on ZynqMP
# echo 150000000 > /sys/devices/platform/fclk0/set_rate # cat /sys/devices/platform/fclk0/set_rate 133333332 # obviously some PLL rounding to deal with
The ZynqMP dtsi’s already have fclk nodes supplied from zynqmp-clk-ccf.dtsi. My Zynq dts didn’t (probably because it was branched many years ago…) but they can be added like:
fclk0: fclk0 { status = "okay"; compatible = "xlnx,fclk"; clocks = <&clkc 15>; };
The PL clocks on the Zynq are <&clkc 15>, <&clkc 16>, <&clkc 17> and <&clkc 18>. On the ZynqMP they are <&zynqmp_clk PL0_REF> etc. (if you #include <dt-bindings/clock/xlnx-zynqmp-clk.h>).
If you don’t want to set clock frequencies from userspace, you can use ‘assigned-clocks’ in any device tree node that seems relevant.
&custom-thing { assigned-clocks = <&clkc 15>, <&clkc 16>; assigned-clock-rates = <250000000>, <100000000>; };
Hope this saves someone else some time.