amalcolm
Posts: 14
Joined: Sun Feb 21, 2016 9:31 am

Set up GPIO clock from device tree

Sun Feb 21, 2016 9:46 am

I am trying to setup a GPIO clock from a device tree to support a device driver for a hardware codec.

There is a section in:

https://www.raspberrypi.org/documentati ... uration.md

labelled CLOCK CONFIGURATION

which shows the following:

clock_routing {
[email protected] { freq = <1966080000>; };
[email protected] { div = <4>; };
[email protected] { pll = "PLLA"; chan = "APER"; };
};

clock_setup {
[email protected] { freq = <2400000>; };
[email protected] { freq = <12288000>; };
[email protected] { freq = <25000000>; };
};

I have tried to put this in a device tree fragment in order to set up CLK0 on GPIO4 (I can do this programatically, by the way, so I know my hardware is good).

Is this all that is required to start the clock? (I have also add a fragment to set GPIO4 to alternate mode, and I believe that is working:

/ {
compatible = "brcm,bcm2708";


[email protected] {
target-path = "/clocks";
__overlay__ {
clock_routing {
[email protected] { freq = <1966080000>; };
chan[email protected] { div = <4>; };
[email protected] { pll = "PLLA"; chan = "APER"; };
};

clock_setup {
[email protected] { freq = <12288000>; };
};
};
};

[email protected] {
target = <&gpio>;
__overlay__ {
clock_pin: clock_pin {
brcm,pins = <4>;
brcm,function = <4>;
};
};
};
etc .....

I have checked the output of vcdbg and my dtb file is loaded correctly:

001610.109: Loaded overlay 'max9860'
001610.148: dtdebug: Found fragment 0 (offset 36)
001612.541: dtdebug: merge_fragment(/clocks,/[email protected]/__overlay__)
001614.601: dtdebug: merge_fragment(/clocks/clock_routing,/[email protected]/__overlay__/clock_routing)
001616.358: dtdebug: merge_fragment(/clocks/clock_routing/[email protected],/[email protected]/__overlay__/clock$
001616.383: dtdebug: +prop(freq)
001616.811: dtdebug: merge_fragment() end
001618.608: dtdebug: merge_fragment(/clocks/clock_routing/[email protected],/[email protected]/__overlay__/cloc$
001618.631: dtdebug: +prop(div)
001619.044: dtdebug: merge_fragment() end
001620.895: dtdebug: merge_fragment(/clocks/clock_routing/[email protected],/[email protected]/__overlay__/c$
001620.918: dtdebug: +prop(pll)
001621.412: dtdebug: +prop(chan)
001621.913: dtdebug: merge_fragment() end
001621.938: dtdebug: merge_fragment() end
001624.230: dtdebug: merge_fragment(/clocks/clock_setup,/[email protected]/__overlay__/clock_setup)
001626.069: dtdebug: merge_fragment(/clocks/clock_setup/[email protected],/[email protected]/__overlay__/clo$
001626.095: dtdebug: +prop(freq)
001626.538: dtdebug: merge_fragment() end
001626.562: dtdebug: merge_fragment() end
001626.595: dtdebug: merge_fragment() end
001626.712: dtdebug: Found fragment 1 (offset 316)
001628.533: dtdebug: merge_fragment(/soc/[email protected],/[email protected]/__overlay__)
001630.012: dtdebug: merge_fragment(/soc/[email protected]/clock_pin,/[email protected]/__overlay__/clock_p$
001630.037: dtdebug: +prop(brcm,pins)
001630.659: dtdebug: +prop(brcm,function)
001631.293: dtdebug: +prop(linux,phandle)
001631.904: dtdebug: +prop(phandle)
001632.532: dtdebug: merge_fragment() end
001632.556: dtdebug: merge_fragment() end
001632.620: dtdebug: Found fragment 2 (offset 456)
001633.647: dtdebug: merge_fragment(/sound,/[email protected]/__overlay__)
001633.670: dtdebug: +prop(compatible)
001634.324: dtdebug: +prop(i2s-controller)
001635.172: dtdebug: +prop(status)
001635.878: dtdebug: merge_fragment() end
001635.931: dtdebug: Found fragment 3 (offset 572)
001638.745: dtdebug: merge_fragment(/soc/[email protected],/[email protected]/__overlay__)
001638.769: dtdebug: +prop(status)
001639.279: dtdebug: merge_fragment() end
001639.327: dtdebug: Found fragment 4 (offset 648)
001643.380: dtdebug: merge_fragment(/soc/[email protected],/[email protected]/__overlay__)
001643.405: dtdebug: +prop(#address-cells)
001643.819: dtdebug: +prop(#size-cells)
001644.236: dtdebug: +prop(status)
001646.521: dtdebug: merge_fragment(/soc/[email protected]/[email protected],/[email protected]/__overlay__/m$
001646.546: dtdebug: +prop(#sound-dai-cells)
001647.022: dtdebug: +prop(compatible)
001647.425: dtdebug: +prop(reg)
001647.862: dtdebug: +prop(pinctrl-names)
001648.355: dtdebug: +prop(pinctrl-0)

However, I get no clock output.

If anyone can shed light on this I would be very grateful.

Thanks in advance

Andrew

f5oeo
Posts: 17
Joined: Sun Oct 12, 2014 10:16 am

Re: Set up GPIO clock from device tree

Sun Mar 27, 2016 1:10 pm

Try also to experiment with clock in device tree overlay without success.
Any update or extra documentation in PLL and clock ?

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2148
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Set up GPIO clock from device tree

Tue Mar 29, 2016 8:01 am

The "Device Tree" that is used to generate the dt-blob.bin isn't Device Tree that would be recognised by anything else; it uses the same syntax, but the semantics are completely different.

What you are trying to do isn't possible at the moment. Although the RPi DTBs contain clock definitions, they are only describing clocks that the firmware has initialised (except for clk_uart1/[email protected] which is a multiple of a clock set up by the firmware). There are efforts upstream to create an ARM-side clock driver that can actually configure and control the BCM2835 PLLs and clock dividers - see drivers/clk/bcm/clk-bcm2835.c for how far Eric Anholt has got - but we aren't using that in Raspberry Pi builds yet.

Currently the only way to create a clock on RPi (short of using a kernel with a different clock driver) is to ask the firmware to do it using a custom dt-blob.bin, which is horrible - sorry. I would like to see the firmware making more use of the main DTB file to avoid duplication, and this is one area where it would be beneficial.

amalcolm
Posts: 14
Joined: Sun Feb 21, 2016 9:31 am

Re: Set up GPIO clock from device tree

Tue Mar 29, 2016 8:22 am

OK, thanks for that. I currently have a user-space program to initialize the clock via /dev/mem. I will integrate this into my driver.

Regards

Andrew Malcolm

tecmec
Posts: 4
Joined: Sun May 07, 2017 9:36 pm

Re: Set up GPIO clock from device tree

Sun May 07, 2017 10:11 pm

PhilE wrote:The "Device Tree" that is used to generate the dt-blob.bin isn't Device Tree that would be recognised by anything else; it uses the same syntax, but the semantics are completely different.

What you are trying to do isn't possible at the moment. Although the RPi DTBs contain clock definitions, they are only describing clocks that the firmware has initialised (except for clk_uart1/[email protected] which is a multiple of a clock set up by the firmware). There are efforts upstream to create an ARM-side clock driver that can actually configure and control the BCM2835 PLLs and clock dividers - see drivers/clk/bcm/clk-bcm2835.c for how far Eric Anholt has got - but we aren't using that in Raspberry Pi builds yet.

Currently the only way to create a clock on RPi (short of using a kernel with a different clock driver) is to ask the firmware to do it using a custom dt-blob.bin, which is horrible - sorry. I would like to see the firmware making more use of the main DTB file to avoid duplication, and this is one area where it would be beneficial.
Is this information still correct? I am trying to set up an external peripheral using the device tree, and I think I have everything working right now, except the clock. While I really wanted to set up the clock in the device tree (so that everything is nicely contained), I have come to accept that I might have to do so elsewhere. However, I can't find this "dt-blob.bin" anywhere. Also, it does seem like clk-bcm2835.c is in fact being used by the RPi builds now.

How would I go about setting up GPCLK0 at boot time (so that my downstream peripheral can be properly detected and initialized during boot)? So far I have the following in my overlay dts, but I'm missing the actual setup of the GPCLK0 frequency.

Code: Select all

...

/* set GPIO4 to ALT0 (GPCLK0) */
    [email protected] {
        target = <&gpio>;
        __overlay__ {
            can_osc_pin {
                brcm,pins = <4>;
                brcm,function = <4>;
            };
        };
    };
 
    [email protected] {
        target = <&spi0>;
        __overlay__ {
            /* needed to avoid dtc warning */
            #address-cells = <1>;
            #size-cells = <0>;
            cs-gpios = <0>, <0>;
            status = "okay";
 
            can0: [email protected] {
                compatible = "microchip,mcp2515";
                reg = <0>;
                clocks = <&clocks 38>; /* BCM2835_CLOCK_GP0 */
                interrupt-parent = <&tca9539_74>;
                interrupts = <2 0x2>;
                vdd-supply = <&vdd_3v3_reg>;
                xceiver-supply = <&vdd_5v0_reg>;
                spi-max-frequency = <10000000>;
            };
        };
    };

...

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2148
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Set up GPIO clock from device tree

Mon May 08, 2017 10:26 am

I believe my comment still applies. Although the bcm2835-cprman driver is being used as of rpi-4.9.y onwards, as far as I know it doesn't allow you to initialise a clock to have specific clock rate unless it is requested by the consumer of the clock, i.e. the driver for the hardware that needs the clock. Fixed clocks support the "clock-frequency" property, but they are meant to be used with oscillators or other clocks that have been pre-configured - see the mcp2515-can0 overlay source here for a relevant example.

If you google "dt-blob.bin", the first result is our documentation of the dt-blob.bin configuration file. The source to our current dt-blob.bin, which is compiled into the start*.elf images but overridable by a file in the boot partition, can be found at: https://github.com/raspberrypi/firmware ... t-blob.dts

tecmec
Posts: 4
Joined: Sun May 07, 2017 9:36 pm

Re: Set up GPIO clock from device tree

Mon May 08, 2017 2:19 pm

Thanks. I missed the part where the file was an override (and so wouldn't exist out of the box).

I suppose the other option may be to see if I can modify the device driver to request a clock through that interface. Right now I see where it queries for the clock rate. I wonder how hard it would be to extend it to be more proactive if it fails.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2148
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Set up GPIO clock from device tree

Mon May 08, 2017 2:38 pm

It shouldn't be very difficult. You can use Eric Anholt's VC4 driver as an example: https://github.com/raspberrypi/linux/bl ... /vc4_dsi.c

Look for all occurrences of "pixel_clock" to show you what to do.

tecmec
Posts: 4
Joined: Sun May 07, 2017 9:36 pm

Re: Set up GPIO clock from device tree

Sun Jun 18, 2017 9:48 pm

I got the clock to work by doing two things. First, I modified driver of the device that consumes the clock to request a specific frequency (like the DSI driver you linked does), by calling clk_set_rate() during initialization. The second thing I had to do though, was to create a custom dt-blob.dtb that includes [email protected] { function = "gp_clk"; termination = "pull_down"; };. I don't entirely understand why I had to do that though, because my dto (for linux, not the bootloader) includes:

Code: Select all

    [email protected] {
        target = <&gpio>;
        __overlay__ {
            can_osc_pin {
                brcm,pins = <4>;
                brcm,function = <4>;
            };
        };
    };
From what I can tell, this should do the exact same thing - configure the GPIO4 pin for the ALT0 functionality (GP_CLK, in this case). I don't know why it doesn't work in the linux dto though. Thoughts?

tecmec
Posts: 4
Joined: Sun May 07, 2017 9:36 pm

Re: Set up GPIO clock from device tree

Mon Jun 19, 2017 12:33 am

To answer my own question, my pinctrl overlay under &gpio doesn't do anything all by itself. The pinctrl needs to be referenced by some other node so that it is actually applied. I changed my device tree overlay to have my device reference the pinctrl, and now everything works without using a custom dt-blob.bin.

Code: Select all

/* set GPIO4 to ALT0 (GPCLK0) */
    [email protected] {
        target = <&gpio>;
        __overlay__ {
            can_clk_pin: can_clk_pin {
                brcm,pins = <4>;
                brcm,function = <4>;
                brcm,pull = <1>;
            };
        };
    };
 
    [email protected] {
        target = <&spi0>;
        __overlay__ {
            /* needed to avoid dtc warning */
            #address-cells = <1>;
            #size-cells = <0>;
            cs-gpios = <0>, <0>;
            status = "okay";
 
            can0: [email protected] {
                compatible = "microchip,mcp2515";
                reg = <0>;
                clocks = <&clocks 38>; /* BCM2835_CLOCK_GP0 */
                interrupt-parent = <&tca9539_74>;
                interrupts = <2 0x2>;
                vdd-supply = <&vdd_3v3_reg>;
                xceiver-supply = <&vdd_5v0_reg>;
                spi-max-frequency = <10000000>;
                pinctrl-names = "default";
                pinctrl-0 = <&can_clk_pin>;
            };
        };
    };
Last edited by tecmec on Mon Jun 19, 2017 2:04 pm, edited 1 time in total.

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2148
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Set up GPIO clock from device tree

Mon Jun 19, 2017 8:41 am

Nice one - you found the answer before I saw the question. As you found, the groups of pin settings within the gpio node are only applied when an active node refers to them through a pinctrl-0 property.

Xavier_S
Posts: 7
Joined: Fri Nov 16, 2018 8:53 am

Re: Set up GPIO clock from device tree

Mon Mar 18, 2019 3:39 pm

Hello,

I am resurrecting this old thread because I need to set up a GPIO clock from the device tree, and none of the operations described above have worked for me so far.

I am building an I2S codec (which works), controlled and configured via I2C (which also works).
My I2S interface already has its own clock source, and so does my I2C interface. However for calibration purposes I need an extra, permanent and very stable 4.8 MHz clock, which has to be available very early in the boot process because my driver needs it during probe() to check certain parts of the hardware.

I am currently using an extra 4.8 MHz oscillator. However I would like to avoid this unnecessary expense and get the clock from the Raspberry Pi as a free hardware resource instead (the same way I get free power supplies).

I would like to get this clock from pin GPIO4 (connector pin 7) configured as GPCLK0. Achieving this from user space is fairly straightforward:

Code: Select all

gpio mode 7 clock
gpio -g clock 4 4800000
makes it. Therefore I naively expected it to be simple enough from kernel space as well, with the help of a few lines in my codec's device tree.
I first declared the function of the pin:

Code: Select all

    [email protected] {
        target = <&gpio>;
        __overlay__ {
            my_clk_pin {
                brcm,pins = <4>;
                brcm,function = <4>;
            };
        };
    };
But then I had to find some place to reference this pin and consume the clock, i.e. I had to put these three lines somewhere:

Code: Select all

            	pinctrl-names = "default";
            	pinctrl-0 = <&my_clk_pin>;
            	clocks = <&clocks 38>; /* BCM2835_CLOCK_GP0 */
This is where I have a problem. As this clock is not related to my I2S or I2C interface in any way, there is no reason why I would include these lines in my target = <&sound>; or target = <&i2c1>; fragments. I tried anyway, however calling devm_clk_get() and clk_set_rate() in the relevant probe() functions in my driver yielded nothing.

I then tried to add the fragment below to my device tree, but to no avail once again:

Code: Select all

    [email protected] {
        target-path = "/clocks";
        __overlay__ {
            my_osc: my_osc {
                compatible = "fixed-clock";
                #clock-cells = <0>;
                clock-frequency = <4800000>;
                pinctrl-names = "default";
                pinctrl-0 = <&my_clk_pin>;
                clocks = <&clocks 38>; /* BCM2835_CLOCK_GP0 */
                status = "okay";
           };
        };
    };
At this point I am a little bit confused, as I can't figure out the right place to reference my clock pin, and have Raspbian understand that I NEED this clock.
Any help appreciated !

Regards,
Xavier

PhilE
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2148
Joined: Mon Sep 29, 2014 1:07 pm
Location: Cambridge

Re: Set up GPIO clock from device tree

Mon Mar 18, 2019 4:36 pm

The problem is, as you've surmised, that you need to "find some place to reference this pin and consume the clock". Unfortunately, unlike pinctrl that configures pins for a device node whether or not it actually uses them, clocks have to be requested by the driver. Similarly, the "clock-frequency" property is just a naming convention - the driver would have to read the value and configure the clock accordingly.

There have been a few occasions where a GPIO configuration driver would have been useful, and to some extent your case sounds like it would benefit from the clock configuration driver, but in both cases there is usually a better way to go about things. In your case you have a driver, one that you said needs the clock during probe, so the natural place to request and configure that clock is in the probe function of that driver.

See pages 37 and 38 of this presentation for a partial example, to which you will need to add something like:

Code: Select all

	if (of_property_read_u32(dev->of_node, "clock-frequency", &rate))
		return NULL;
	clk_set_rate(pp->clk, rate);

Xavier_S
Posts: 7
Joined: Fri Nov 16, 2018 8:53 am

Re: Set up GPIO clock from device tree

Fri Apr 12, 2019 5:36 pm

Thanks PhilE for your answer, which helped me go in the right direction.

At last I got it to work. What I was missing was the clk_prepare(), which I forgot to call after devm_clk_get() and clk_set_rate().

From my experiments I made a couple of observations I found interesting to share here, as extensively googling around on this topic showed me that I was far from the only one with the same problem.

In order to isolate my problem I first stripped my overlay and driver down to the bare minimum. I attached the pin controller to the Leds subsystem and wrote a small platform driver accordingly. Here is the device tree:

Code: Select all

/* set GPIO4 to ALT0 (GPCLK0) */
	[email protected] {
		target = <&gpio>;
		__overlay__ {
			gpio4_clk_pin: clk_pin {
				brcm,pins = <4>;
				brcm,function = <4>;
			};
		};
	};

	[email protected] {
		target = <&leds>;
		gpio4_clk: __overlay__ {
			compatible = "my_co,gpio4-clk";
			pinctrl-names = "default";
			pinctrl-0 = <&gpio4_clk_pin>;
			clocks = <&clocks 38>; /* BCM2835_CLOCK_GP0 */
			clock-frequency = <4800000>;
			status = "okay";
		};
	};

	__overrides__ {
		sclk = <&gpio4_clk>,"clock-frequency:0";
	};
And here is what goes in the driver's probe():

Code: Select all

	sclk = devm_clk_get(dev, NULL);	
	if (of_property_read_u32(dev->of_node, "clock-frequency", &rate))
		return NULL;
	clk_set_rate(sclk, rate);	
	clk_prepare(sclk);
For me clk_prepare() was enough to do the job, and I didn't see any difference using clk_prepare_enable().

My goal was to get a clock with the lowest possible jitter. Unfortunately Broadcom's BCM2836 hardware datasheet is nowhere to be found, and the only available information about this seems to be from the Raspberry Pi Compute Module datasheet. Here is the significant excerpt:
BCM2836_jitter.png
BCM2836_jitter.png (66.78 KiB) Viewed 967 times
Obviously the 19.2 MHz oscillator is to be preferred as a clock source when possible, as the jitter we get from the PLLs is more than twice as bad as from the oscillator.

As I wanted to know which parent the clock framework would choose for me, here is what I included just after clk_prepare():

Code: Select all

	printk(KERN_ALERT "GPIO4_CLK: %lu Hz\n", clk_get_rate(sclk));
	parent_clk = clk_get_parent(sclk);
	if (!(IS_ERR(parent_clk))) {
		printk(KERN_ALERT "Parent clock name: %s\n", __clk_get_name(parent_clk));
		printk(KERN_ALERT "Parent clock rate: %lu Hz\n", clk_get_rate(parent_clk));
	}
In order to get a chance to be granted the oscillator as a parent clock, I started by asking for a 19.2 MHz submultiple, so I chose 4.8 MHz. Here is what I got:

[ 3.255377] GPIO4_CLK: 4800000 Hz
[ 3.255392] Parent clock name: osc
[ 3.255400] Parent clock rate: 19200000 Hz

and my frequency meter confirmed that I had the signal I wanted right at the GPIO4 output. Bingo!

I explored a little bit further anyway, as I wanted to know what happened with non-submultiple frequencies. First I tried with 3 MHz:

[ 3.203769] GPIO4_CLK: 3000000 Hz
[ 3.203789] Parent clock name: pllh_aux
[ 3.203797] Parent clock rate: 216000000 Hz

This time I was given the HDMI auxiliary PLL, which was available indeed in my system as I have nothing connected to HDMI.

Then I asked for 5 MHz, and here is what I got:

[ 3.179959] GPIO4_CLK: 4999987 Hz
[ 3.179979] Parent clock name: plld_per
[ 3.179987] Parent clock rate: 500000006 Hz

There is no typo here in the parent clock rate and Linux seems to attach great importance to these six little Hertz, as I consistently got the same value from all my experiments with two different machines. And it's amazing to see how a round value like 5000000 Hz for GPCLK0 cannot be reached exactly, when it seems so straightforward to just divide PLLD by 100.

I first thought that the clock framework was only choosing PLLH when the requested frequency was a submultiple of 216000000, but it is not that simple. Take 12.288 MHz, which is 216 MHz*(64/1125):

[ 3.180845] GPIO4_CLK: 12288000 Hz
[ 3.184276] Parent clock name: pllh_aux
[ 3.188289] Parent clock rate: 216000000 Hz

What happens then if I want 12.288 MHz, but PLLH is not available for some reason? I simulated it by just adding hdmi_force_hotplug=1 to my config.txt, and I got this:

[ 5.021454] GPIO4_CLK: 12287975 Hz
[ 5.023998] Parent clock name: plld_per
[ 5.026493] Parent clock rate: 500000006 Hz

In the former case (PLLH) my frequency meter measured 12288043 Hz, while the latter (PLLD) gave 12288018 Hz, hence a 25 Hz difference. This shows that the weird value claimed by the clock framework when using PLLD is for real, and not just the result of some obscure rounding problem.

I didn't plug a spectrum analyser on GPIO4 to see whether PLLD or PLLH as a parent yields a noisier output. Therefore, aside from this problem of not being able to get the exact requested value from PLLD, I can't tell which one is better. However, given the number of projects I have seen where GPCLK0 is used as a master clock to an audio codec, I think it is worth asking the question.

Given the figures above, unless a jitter measurement gives me wrong my natural preference would go to PLLH over PLLD when possible, by selecting a compatible GPCLK0 frequency – which I currently don't know how to achieve for sure other than by trial-and-error, knowledgeable people please give some input here!

As I didn't want yet another kernel module in my system just for the purpose of getting this clock, I then moved the code snippets above (driver + pin controller) first to my I2C driver, then to my sound card driver. Both configurations worked well and behaved exactly as above.

About doing this in the sound card driver: in my system the Raspberry is an I2S clock slave, therefore the BCM2836 audio interface normally does not require any high-quality clock from the clock framework. However Linux cannot guess it until I snd_soc_register_card() my sound card. I first tried to configure GPCLK0 before registering the sound card. While with frequencies using OSC or PLLH as a parent everything went without a hitch, on the other hand in situations where PLLD was the parent, clk_set_rate() returned a 'Device or resource busy' error, which oddly enough did not prevent it from doing its job normally. Therefore it is advised to do the GPCLK0 stuff AFTER registering the sound card, in which case no error occurs.

OK, that's all for today. Hope that helps!

Return to “Device Tree”