Spelunking the FreeBSD ARM FDT

The FDT is the "Flattened Device Tree", a simple device tree used in embedded FreeBSD, for example on a Pi.  Every architecture has a DTS file, which contains a human-readable list of hardware for that architecture.   For example, the Pi FTD is here.  You should notice that there are declarations for:

  • cpu
  • axi (the system bus)
  • time & watchdog
  • gpio: GPIO
  • dma: DMA controller
  • vc_mbox
  • uart; serial controller
  • sdhci; SD card controller
  • memory
  • display
  • leds; the GPIO leds
  • power regulators

In other words, all the hardware in the Pi.  If you look at this datasheet from Broadcom, you should see that the hardware declared in the FDT file is the hardware on the Pi's SOC chip, the Broadcom BCM2835.

In my case, I'm specifically interested in RS-232 using the GPIO pins 14 and 15.  The FDT file contains this:

/* UART0 */
pins_uart0_a: uart0_a {
	broadcom,pins = <14>, <15>;
	broadcom,function = "ALT0";
};

Which specifies that uart0 binds GPIO pins 14 and 15.   If you look in the datasheet, on page 101, you'll see that GPIO pins 14 and 15, in ALT0 mode are serial TX and RX respectively.

If you have FreeBSD up on a Pi, and you have the /dev/openfirm device compiled in to your kernel, you can find uart0 using /usr/sbin/ofwdump.

The output "ofwdump -a" on my Pi shows:

root@raspberry-pi:/etc # ofwdump -a
Node 0x48: 
  Node 0xf8: system
  Node 0x150: cpus
    Node 0x15c: cpu@0
  Node 0x18c: axi
    Node 0x1f8: interrupt-controller
    Node 0x29c: timer
    Node 0x344: armtimer
    Node 0x3bc: watchdog0
    Node 0x41c: gpio
      Node 0x538: bsc0_a
      Node 0x570: bsc0_b
      Node 0x5a8: bsc0_c
      Node 0x5e0: bsc1_a
      Node 0x618: bsc1_b
      Node 0x650: gpclk0_a
      Node 0x688: gpclk0_b
      Node 0x6c0: gpclk0_c
      Node 0x6f8: gpclk0_d
      Node 0x730: gpclk1_a
      Node 0x768: gpclk1_b
      Node 0x7a0: gpclk1_c
      Node 0x7d8: gpclk1_d
      Node 0x810: gpclk2_a
      Node 0x848: gpclk2_b
      Node 0x880: spi0_a
      Node 0x8c4: spi0_b
      Node 0x908: pwm0_a
      Node 0x93c: pwm0_b
      Node 0x970: pwm0_c
      Node 0x9a4: pwm1_a
      Node 0x9d8: pwm1_b
      Node 0xa0c: pwm1_c
      Node 0xa40: pwm1_d
      Node 0xa74: uart0_a
      Node 0xaac: uart0_b
      Node 0xae4: uart0_c
      Node 0xb1c: uart0_fc_a
      Node 0xb58: uart0_fc_b
      Node 0xb94: uart0_fc_c
      Node 0xbd0: pcm_a
      Node 0xc10: pcm_b
      Node 0xc50: sm_addr_a
      Node 0xc9c: sm_addr_b
      Node 0xce8: sm_ctl_a
      Node 0xd24: sm_ctl_b
      Node 0xd60: sm_data_8bit_a
      Node 0xdb8: sm_data_8bit_b
      Node 0xe10: sm_data_16bit
      Node 0xe68: sm_data_18bit
      Node 0xea8: bscsl
      Node 0xee0: spisl
      Node 0xf20: spi1
      Node 0xf68: uart1_a
      Node 0xfa0: uart1_b
      Node 0xfd8: uart1_c
      Node 0x1010: uart1_fc_a
      Node 0x104c: uart1_fc_b
      Node 0x1088: uart1_fc_c
      Node 0x10c4: spi2
      Node 0x110c: arm_jtag_trst
      Node 0x1148: arm_jtag_a
      Node 0x1190: arm_jtag_b
      Node 0x11d8: reserved
    Node 0x1238: dma
    Node 0x12f8: mbox
    Node 0x1384: sdhci
    Node 0x1414: uart0
    Node 0x14c8: vchiq
    Node 0x1530: usb
      Node 0x15e0: hub
        Node 0x1638: ethernet
  Node 0x16a0: memory
  Node 0x16d8: display
  Node 0x176c: leds
    Node 0x1790: ok
  Node 0x17f4: regulator
    Node 0x18ec: regulator@0
    Node 0x1998: regulator@3
  Node 0x1a48: aliases
  Node 0x1a70: chosen

The list of devices on my Pi matches the list in the FTD (here).

I can also use devinfo to find the devices that are actuallly found in my system.  Here's the output, with the USB stuff removed:

root@raspberry-pi:/etc # devinfo -r
nexus0
  fdtbus0
    simplebus0
      intc0
          I/O memory:
              0x2000b200-0x2000b3ff
      systimer0
          Interrupt request lines:
              8
              9
              10
              11
          I/O memory:
              0x20003000-0x20003fff
      bcmwd0
          I/O memory:
              0x2010001c-0x20100027
      gpio0
          Interrupt request lines:
              57
          I/O memory:
              0x20200000-0x202000af
        gpioc0
        gpiobus0
      bcm_dma0
          Interrupt request lines:
              24
              25
              26
              27
              28
              29
              30
              31
              32
              33
              34
              35
          I/O memory:
              0x20007000-0x20007fff
      mbox0
          Interrupt request lines:
              1
          I/O memory:
              0x2000b880-0x2000b8bf
      sdhci_bcm0
          Interrupt request lines:
              70
          I/O memory:
              0x20300000-0x203000ff
        mmc0
          mmcsd0
      uart0
          Interrupt request lines:
              65
          I/O memory:
              0x20201000-0x20201fff
      dwcotg0
          Interrupt request lines:
              17
          I/O memory:
              0x20980000-0x2099ffff
        usbus0
          uhub0
            uhub1
              smsc0
                miibus0
                  ukphy0
              ukbd0
    fb0
    simplebus1

If I check the dmesg output I see that I do indeed have a uart0 that FreeBSD found on boot:

root@raspberry-pi:/dev # dmesg | grep uart
uart0: <PrimeCell UART (PL011)> mem 0x20201000-0x20201fff irq 65 on simplebus0

Verifying with ofwdump:

root@raspberry-pi:/etc # ofwdump -p uart0
Node 0x1414: uart0
  compatible:
    62 72 6f 61 64 63 6f 6d 2c 62 63 6d 32 38 33 35 2d 75 61 72 
    74 00 62 72 6f 61 64 63 6f 6d 2c 62 63 6d 32 37 30 38 2d 75 
    61 72 74 00 61 72 6d 2c 70 6c 30 31 31 00 61 72 6d 2c 70 72 
    69 6d 65 63 65 6c 6c 00 
  reg:
    00 20 10 00 00 00 10 00 
  interrupts:
    00 00 00 41 
  interrupt-parent:
    00 00 00 01 
  clock-frequency:
    00 2d c6 c0 
  reg-shift:
    00 00 00 02

You can see that the data ofwdump returns for uart0 matches with the FTD and with uart0 that FreeBSD reported.  The IRQ that ofwdump returns is 0x41, which is 65 in base-10; exactly what's expected.

If you look at the bottom of the FTD file, you will see that uart0 is bound to stdin and stdout:

chosen {
		bootargs = "";			/* Set by VideoCore */
		stdin = "uart0";
		stdout = "uart0";
	};

There is a description of the "/chosen" node in the FDT here and here from devicetree.org.

For more information, there is this excellent presentation, this FreeBSD Wiki page, and this white paper.   There is a wiki here, with quite a lot of good information on Flattened Device Tree.

Looking at the /dev/ tree I see:

crw------- 1 root wheel 0x1f Apr 27 13:42 ttyu0
crw------- 1 root wheel 0x20 Apr 27 21:42 ttyu0.init
crw------- 1 root wheel 0x21 Apr 27 21:42 ttyu0.lock
crw-rw---- 1 uucp dialer 0x22 Apr 27 21:42 cuau0
crw-rw---- 1 uucp dialer 0x23 Apr 27 21:42 cuau0.init
crw-rw---- 1 uucp dialer 0x24 Apr 27 21:42 cuau0.lock

I these devices are the sio device, bound to uart0.

/dev/ttyu0 was declared in the /etc/ttys.  The build script here was used to create my Pi install, and the specific line that declares this tty was;

ttyu0 "/usr/libexec/getty 3wire.115200" dialup on secure

If you're interested in what "3wire.115200" actually means, it's declared in /etc/gettytab.  The details of setting up tty devices in FreeBSD are here, in the FreeBSD Handbook.

 

Leave a Reply