User avatar
Milliways
Posts: 746
Joined: Fri Apr 25, 2014 12:18 am
Location: Sydney, Australia

/proc/device-tree/soc/ranges documentation

Sun Sep 26, 2021 5:41 am

A number of popular libraries use /proc/device-tree/soc/ranges to determine the peripheral base address.

Is there any documentation for this?
Is it specific to Raspberry Pi OS?

cleverca22
Posts: 4644
Joined: Sat Aug 18, 2012 2:33 pm

Re: /proc/device-tree/soc/ranges documentation

Sun Sep 26, 2021 6:14 am

https://www.devicetree.org/specifications/

and from my own comments on a dts file:

Code: Select all

/ {
  #address-cells = <0x01>;
  #size-cells = <0x01>;
  soc {
    compatible = "simple-bus";
    #address-cells = <0x01>;
    #size-cells = <0x01>;
    //        child       parent       length
    ranges = <0x7e000000 0x3f000000 0x1000000 /* map the MMIO space to 0x3f000000 in arm, 16mb long */
              0x40000000 0x40000000 0x1000>; /* identity map the local_intc, 0x1000 bytes long */
    dma-ranges = <0xc0000000 0x00 0x3f000000>; /* map arm physical 0 to the uncached alias, 1008mb long */
size-cells and address-cells refers to how many 32bit ints make up a given number
ranges will then have sets of 3 numbers
* the child address (using the childs #address-cells)
* the parent address (using the parents #address-cells)
* the size of the range (using the childs? #size-cells)

in the example i quoted above, it says that a 16mb region, starting at 0x7e00_0000 has been mapped to 0x3f00_0000 in the arm physical space
so any time you see a register inside the soc node, you must map it over in that direction

dma-ranges is for the reverse translation, you have a 1008mb chunk of ram, starting at 0 physical on the arm side
when doing dma, you need to add 0xc0000000 to the address, before passing it to the hw for dma action

the above example is simple, because everything is 32bit, but things get more complicated when you move to pi4 and 64bit, not even the official libraspberrypi is following the correct rules to parse the ranges file!, it just assumes certain sizes based on the length

Code: Select all

[nix-shell:~/apps/rpi/linux-5.14]$ vi arch/arm/boot/dts/bcm2711.dtsi
/ {
        compatible = "brcm,bcm2711";

        #address-cells = <2>; 
        #size-cells = <1>; 
        soc {
                /*   
                 * Defined ranges:
                 *   Common BCM283x peripherals
                 *   BCM2711-specific peripherals
                 *   ARM-local peripherals
                 */
                ranges = <0x7e000000  0x0 0xfe000000  0x01800000>,
                         <0x7c000000  0x0 0xfc000000  0x02000000>,
                         <0x40000000  0x0 0xff800000  0x00800000>;
                /* Emulate a contiguous 30-bit address range for DMA */
                dma-ranges = <0xc0000000  0x0 0x00000000  0x40000000>;
for this pi4 file, the parent address space is now using 64bit ints for the addresses
but device-tree is 32bit max, so you need 2 ints in a list, to make up a 64bit addr
the first entry maps a 24mb chunk of MMIO from 0x7e to 0xfe
and the extra 32bits are basically a complete waste for this /soc node, it could have done without them

Code: Select all

        scb {
                compatible = "simple-bus";
                #address-cells = <2>;
                #size-cells = <2>;

                ranges = <0x0 0x7c000000  0x0 0xfc000000  0x0 0x03800000>,
                         <0x6 0x00000000  0x6 0x00000000  0x0 0x40000000>;
but this second bus (where pci-e lives) is using 64bit addresses in the parent space
so everything must use 64bit addressing, when referencing that shared parent

User avatar
Milliways
Posts: 746
Joined: Fri Apr 25, 2014 12:18 am
Location: Sydney, Australia

[SOLVED] /proc/device-tree/soc/ranges documentation

Sun Sep 26, 2021 8:01 am

Thanks,
I had kind of figured some of this out, but was (and still am) confused by the Pi4.
I had written some code to print out but will enhance with additional properties.

I will have to do some more reading of the spec, but my initial interpretation is that ranges would be required by any DT that accessed the Pi peripherals.

Some links I had read implied that other OS may not use this.

cleverca22
Posts: 4644
Joined: Sat Aug 18, 2012 2:33 pm

Re: /proc/device-tree/soc/ranges documentation

Sun Sep 26, 2021 8:05 am

in an ideal world (what linux does), you would only ever access a device via the reg= addr in the DT, and you would translate it thru every ranges= you encounter, so the translations can be stacked several deep

but if you know the hardware, and that the mmio is a solid block of 16mb, you can just skip half of that, and only use the mmio base from the ranges


also of note, that mmio base is purely a software construct

Code: Select all

  // first pass, map everything to the framebuffer, to act as a default
  for (int i=0; i<1024 ; i += 16) {
    mapBusToArm(0xc0000000 | fb_phys_addr, i * 1024 * 1024);
  }
  
  // second pass, map the lower 64mb as plain ram 
  for (int i=0; i<64 ; i += 16) {
    mapBusToArm(0xc0000000 | (i * 1024 * 1024), i * 1024 * 1024);
  } 
    
  for (int i=112; i<512 ; i += 16) {
    mapBusToArm(0xc0000000 | (i * 1024 * 1024), i * 1024 * 1024);
  }
  
  // add mmio
  mapBusToArm(0x7e000000, 0x20000000);
  mapBusToArm(0x7e000000, 0x3f000000);
  
  // add framebuffer
  mapBusToArm(0xc0000000 | fb_phys_addr, fb_phys_addr);
this code sets up a bunch of ram, and adds 2 duplicate copies of the MMIO at both the pi1 and pi2 addr!

Return to “Advanced users”