mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Confused by the Device Tree (shipped with raspian)

Fri Feb 13, 2015 8:36 pm

Hi,

I've got the LED blinking and the UART saying hello on my RPi 2 so I'm all set to do more bare metal work. But before I continue I wanted to do things right and support both the RPi and RPi 2. But I've run into a bunch of problems:
  1. At boot R1 should contain an unique device ID. For the RPi this is 0xC42. Now for the RPi 2 I also get 0xC42. Not verry unique is it?
  2. Next I switched from booting with ATAGS to booting with Device Tree, because the device tree contains the model name and compatible tags that differ between RPi and RPi2. But now I have to specify the right device tree in the config.txt. Is there any way to make the loader choose the right device tree like it picks kernel.img or kernel7.img?
  3. When enabling device tree the ID in R1 is also supposed to change again to yet another unique ID so kernels can know wether ATAGs or DT is used. I still get 0xC42 with DT.
Ignoring for the moment that I have to hardcode the device tree file to config.txt I then went ahead and wanted to extract the peripherals base address from the device tree. The raspbootin image I downloaded initially to get a booting SD card is nice enough to contain *.dtb files for three different RPi models (bcm2708-rpi-b-plus.dtb, bcm2708-rpi-b.dtb and bcm2709-rpi-2-b.dtb). And I can make them human readable using fdtdump under linux. So I looked at that before implementing my own parser. The peripherals base address is supposed to be the ranges listed in "/soc" node. This gives me 3 values, one for each dtb file, i.e. one per model:
  • bcm2708-rpi-b-plus.dtb: model = "Raspberry Pi Model B+"; ranges = <0x7e000000 0x00000004 0x00000004>;
  • bcm2708-rpi-b.dtb: model = "Raspberry Pi Model B"; ranges = <0x7e000000 0x00000004 0x00000004>;
  • bcm2709-rpi-2-b.dtb: model = "Raspberry Pi 2 Model B"; ranges = <0x7e000000 0x00000004 0x00000004>;
Now I know that the old RPi has its peripherals at 0x20000000 and the new one at 0x3F000000. Also the old VC only has 1GB address space repeated 4 times and uses the most significant 2 address bits to determine caching strategies. I assume the VC on the RPi 2 does too.

So then why do all 3 say peripherals are at 0x7e000000? Are the device trees on the raspian image just plain wrong? If so where do I get a correct one from?

mimi123
Posts: 583
Joined: Thu Aug 22, 2013 3:32 pm

Re: Confused by the Device Tree (shipped with raspian)

Fri Feb 13, 2015 8:52 pm

The VC4 addresses are the same. (aka all the bare metal VC4 samples are running the same)

JacobL
Posts: 76
Joined: Sun Apr 15, 2012 2:23 pm

Re: Confused by the Device Tree (shipped with raspian)

Fri Feb 13, 2015 10:50 pm

mrvn wrote:So then why do all 3 say peripherals are at 0x7e000000? Are the device trees on the raspian image just plain wrong? If so where do I get a correct one from?
Those are the bus addresses as referenced in the BCM2835 data book. There must be another entry somewhere in the device tree that contains the mapping.

On the other hand, take a look at the BCM2835 dts from kernel 3.19: https://git.kernel.org/cgit/linux/kerne ... tags/v3.19 - in that file, we have ranges = <0x7e000000 0x20000000 0x02000000>;
where the fields match bus address, ARM physical address and size. You might want to look into why your dts is different.

mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Re: Confused by the Device Tree (shipped with raspian)

Sat Feb 14, 2015 11:35 am

Those are the bus addresses as referenced in the BCM2835 data book. There must be another entry somewhere in the device tree that contains the mapping.
You are both right and wrong.

ranges = <0x7e000000 0x00000004 0x00000004>;

Means, as far as I figured out now, that the device is at bus address 0x7e000000 on the VC side and 0x00000004 at the arm side and all the childs addresses are relative to that mapping. The DTS files from linux show 0x20000000 and 0x3F000000 in the ranges property as it should be. So I was looking at the wrong value (since 0x00000004 made no sense at all). The DTB files included with the raspian image are garbage unless the bootloader fills in the actually right values during boot. I should dump the DTB I receive at boot to the serial and decode that. A quick check of the header already showed that the DTB at boot is larger than the one on file so the bootloader at least adds something. Maybe it corrects existing entries too.

As a side node the DT from the linux kernel seems to not only have the correct values but also a bit more information too. Like which GPIO pin the LEDs are connected too. So my plan for this weekend is twofold: 1) decode the actual DTB passed at boot instead of the input file and 2) compile the DTS/DTI files from linux to generate usefull DTB files for testing and maybe use.

MfG
Goswin

mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Re: Confused by the Device Tree (shipped with raspian)

Sat Feb 14, 2015 12:30 pm

Here is the device tree passed after boot (using bcm2709-rpi-2-b.dtb in config.txt):

Code: Select all

/dts-v1/;
// magic:               0xd00dfeed
// totalsize:           0x3f00 (16128)
// off_dt_struct:       0x38
// off_dt_strings:      0x154c
// off_mem_rsvmap:      0x28
// version:             17
// last_comp_version:   16
// boot_cpuid_phys:     0x0
// size_dt_strings:     0x2b4
// size_dt_struct:      0x1514

/ {
    memreserve = <0x37000000 0x00000000>;
    #address-cells = <0x00000001>;
    #size-cells = <0x00000001>;
    compatible = "brcm,bcm2709";
    model = "Raspberry Pi 2 Model B";
    interrupt-parent = <0x00000001>;
    display {
        broadcom,depth = <0x00000010>;
        broadcom,height = <0x00000000>;
        broadcom,width = <0x00000000>;
    };
    system {
        linux,serial = <0x00000000 0x0000024c>;
        linux,revision = <0x00a01041>;
    };
    axi {
        uart0 {
            clock-frequency = <0x002dc6c0>;
        };
        sdhci {
            clock-frequency = <0x02faf080>;
        };
        dma {
            broadcom,channels = <0x00007f35>;
        };
        usb {
            hub {
                ethernet {
                    mac-address = [ffffffb8 27 ffffffeb 49 ffffff9b 41];
                };
            };
        };
        vc_mem {
            reg = <0x3dc00000 0x00000002 0x00000003>;
        };
    };
    chosen {
        bootargs = "dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2709.boardrev=0xa01041 bcm2709.serial=0xc7499b41 smsc95xx.macaddr=B8:27:EB:49:9B:41 bcm2708_fb.fbswap=1 bcm2709.uart_clock=3000000 bcm2709.disk_led_gpio=47 bcm2709.disk_led_active_low=0 sdhci-bcm2708.emmc_clock_freq=50000000 vc_mem.mem_base=0x3dc00000 vc_mem.mem_size=0x3f000000  dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait";
    };
    aliases {
        soc = "/soc";
        spi0 = "/soc/[email protected]";
        i2c0 = "/soc/[email protected]";
        i2c1 = "/soc/[email protected]";
        i2s = "/soc/[email protected]";
        gpio = "/soc/gpio";
        intc = "/soc/interrupt-controller";
        leds = "/soc/leds";
        sound = "/sound";
    };
    memory {
        device_type = "memory";
        reg = <0x00000000 0x736f6300>;
    };
    soc {
        compatible = "simple-bus";
        #address-cells = <0x00000001>;
        #size-cells = <0x00000001>;
        ranges = <0x7e000000 0x00000004 0x00000004>;
        linux,phandle = <0x00000012>;
        phandle = <0x00000012>;
        interrupt-controller {
            compatible = "brcm,bcm2708-armctrl-ic";
            reg = <0x7e00b200 0x00000097>;
            interrupt-controller;
            #interrupt-cells = <0x00000002>;
            linux,phandle = <0x00000001>;
            phandle = <0x00000001>;
        };
        gpio {
            compatible = "brcm,bcm2835-gpio";
            reg = <0x7e200000 0x000000bd>;
            interrupts = <0x00000002 0x00000003 0x00000004 0x00000000>;
            gpio-controller;
            #gpio-cells = <0x00000002>;
            interrupt-controller;
            #interrupt-cells = <0x00000002>;
            linux,phandle = <0x00000008>;
            phandle = <0x00000008>;
            spi0_pins {
                brcm,pins = <0x00000007 0x0000000b 0x00000004 0x00000004 0x00000004>;
                brcm,function = <0x00000004>;
                linux,phandle = <0x00000004>;
                phandle = <0x00000004>;
            };
            i2c0 {
                brcm,pins = <0x00000000 0x000000ee>;
                brcm,function = <0x00000004>;
                linux,phandle = <0x00000006>;
                phandle = <0x00000006>;
            };
            i2c1 {
                brcm,pins = <0x00000002 0x000000ee>;
                brcm,function = <0x00000004>;
                linux,phandle = <0x00000007>;
                phandle = <0x00000007>;
            };
            i2s {
                brcm,pins = <0x00000012 0x00000003 0x00000003 0x00000003>;
                brcm,function = <0x00000004>;
                linux,phandle = <0x00000002>;
                phandle = <0x00000002>;
            };
        };
        [email protected] {
            compatible = "brcm,bcm2708-i2s";
            reg = <0x7e203000 0x00000003 0x78000000 0x64697361>;
            dma-names = "tx", "rx";
            status = "disabled";
            #sound-dai-cells = <0x00000000>;
            pinctrl-names = "default";
            pinctrl-0 = <0x00000002>;
            linux,phandle = <0x0000000d>;
            phandle = <0x0000000d>;
        };
        [email protected] {
            compatible = "brcm,bcm2708-spi";
            reg = <0x7e204000 0x000000bd>;
            interrupts = <0x00000002 0x00000136>;
            clocks = <0x00000003>;
            #address-cells = <0x00000001>;
            #size-cells = <0x00000000>;
            status = "disabled";
            pinctrl-names = "default";
            pinctrl-0 = <0x00000004>;
            linux,phandle = <0x0000000e>;
            phandle = <0x0000000e>;
            [email protected] {
                compatible = "spidev";
                reg = <0x00000000>;
                #address-cells = <0x00000001>;
                #size-cells = <0x00000000>;
                spi-max-frequency = <0x0007a120>;
            };
            [email protected] {
                compatible = "spidev";
                reg = <0x00000001>;
                #address-cells = <0x00000001>;
                #size-cells = <0x00000000>;
                spi-max-frequency = <0x0007a120>;
            };
        };
        [email protected] {
            compatible = "brcm,bcm2708-i2c";
            reg = <0x7e205000 0x000000bd>;
            interrupts = <0x00000002 0x00000136>;
            clocks = <0x00000005>;
            #address-cells = <0x00000001>;
            #size-cells = <0x00000000>;
            status = "disabled";
            pinctrl-names = "default";
            pinctrl-0 = <0x00000006>;
            clock-frequency = <0x000186a0>;
            linux,phandle = <0x0000000f>;
            phandle = <0x0000000f>;
        };
        [email protected] {
            compatible = "brcm,bcm2708-i2c";
            reg = <0x7e804000 0x000000bd>;
            interrupts = <0x00000002 0x00000136>;
            clocks = <0x00000005>;
            #address-cells = <0x00000001>;
            #size-cells = <0x00000000>;
            status = "disabled";
            pinctrl-names = "default";
            pinctrl-0 = <0x00000007>;
            clock-frequency = <0x000186a0>;
            linux,phandle = <0x00000010>;
            phandle = <0x00000010>;
        };
        leds {
            compatible = "gpio-leds";
            linux,phandle = <0x00000013>;
            phandle = <0x00000013>;
            act {
                label = "ACT";
                linux,default-trigger = "mmc0";
                gpios = <0x00000008 0x00000004 0x00000004>;
                linux,phandle = <0x00000011>;
                phandle = <0x00000011>;
            };
        };
    };
    clocks {
        compatible = "simple-bus";
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        i2c {
            compatible = "fixed-clock";
            reg = <0x00000001>;
            #clock-cells = <0x00000000>;
            clock-frequency = <0x0ee6b280>;
            linux,phandle = <0x00000005>;
            phandle = <0x00000005>;
        };
        [email protected] {
            compatible = "fixed-clock";
            reg = <0x00000002>;
            #clock-cells = <0x00000000>;
            clock-output-names = "spi";
            clock-frequency = <0x0ee6b280>;
            linux,phandle = <0x00000003>;
            phandle = <0x00000003>;
        };
    };
    timer {
        compatible = "arm,armv7-timer";
        clock-frequency = <0x0124f800>;
        interrupts = <0x00000003 0x00000003 0x00000002 0x00000003 0x00000003 0x00000003 0x00000003 0x00000001>;
    };
    cpus {
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        linux,phandle = <0x00000014>;
        phandle = <0x00000014>;
        [email protected] {
            device_type = "cpu";
            compatible = "arm,cortex-a7";
            reg = <0x00000f00>;
            clock-frequency = <0x35a4e900>;
            linux,phandle = <0x00000009>;
            phandle = <0x00000009>;
        };
        [email protected] {
            device_type = "cpu";
            compatible = "arm,cortex-a7";
            reg = <0x00000f01>;
            clock-frequency = <0x35a4e900>;
            linux,phandle = <0x0000000a>;
            phandle = <0x0000000a>;
        };
        [email protected] {
            device_type = "cpu";
            compatible = "arm,cortex-a7";
            reg = <0x00000f02>;
            clock-frequency = <0x35a4e900>;
            linux,phandle = <0x0000000b>;
            phandle = <0x0000000b>;
        };
        [email protected] {
            device_type = "cpu";
            compatible = "arm,cortex-a7";
            reg = <0x00000f03>;
            clock-frequency = <0x35a4e900>;
            linux,phandle = <0x0000000c>;
            phandle = <0x0000000c>;
        };
    };
    __overrides__ {
        arm_freq = <0x00000009 0x6e63793a 0x66726571 0x636c6f63 0x30000000 0x75656e63 0x00000059 0x00000003 0x73746174 0x0000004f 0x00000003 0x73746174 0x000001ae 0x00000003 0x6770696f 0x000001cd 0x6661756c 0x00000002 0x00000003 0x00000003 0x00000002 0x735f5f00>;
        i2s = [00 00 00 0d 73 74 61 74 75 73 00];
        spi = [00 00 00 0e 73 74 61 74 75 73 00];
        i2c0 = [00 00 00 0f 73 74 61 74 75 73 00];
        i2c1 = [00 00 00 10 73 74 61 74 75 73 00];
        act_led_gpio = <0x00000011 0x0000000c 0x733a3800>;
        act_led_activelow = <0x00000011 0x0000001a 0x782c6465>;
        act_led_trigger = [00 00 00 11 6c 69 6e 75 78 2c 64 65 66 61 75 6c 74 2d 74 72 69 67 67 65 72 00];
    };
    sound {
        linux,phandle = <0x00000015>;
        phandle = <0x00000015>;
    };
    __symbols__ {
        soc = "/soc";
        intc = "/soc/interrupt-controller";
        gpio = "/soc/gpio";
        spi0_pins = "/soc/gpio/spi0_pins";
        i2c0_pins = "/soc/gpio/i2c0";
        i2c1_pins = "/soc/gpio/i2c1";
        i2s_pins = "/soc/gpio/i2s";
        i2s = "/soc/[email protected]";
        spi0 = "/soc/[email protected]";
        i2c0 = "/soc/[email protected]";
        i2c1 = "/soc/[email protected]";
        leds = "/soc/leds";
        act_led = "/soc/leds/act";
        clk_i2c = "/clocks/i2c";
        clk_spi = "/clocks/[email protected]";
        cpus = "/cpus";
        v7_cpu0 = "/cpus/[email protected]";
        v7_cpu1 = "/cpus/[email protected]";
        v7_cpu2 = "/cpus/[email protected]";
        v7_cpu3 = "/cpus/[email protected]";
        sound = "/sound";
    };
};
The only thing usefull in that tree is the model and the bootargs. As the saying goes: garbage in, garbage out. Next up: building a correct dtb file from linux sources.

Return to “Bare metal, Assembly language”