Published at:
https://jkridner.wordpress.com/2018/01/17/building-a-device-tree-overlay-for-your-new-pocketcape-design/

Much has been made of the complexities of the Linux device tree
configuration mechanism–it is both a savior and a curse. It saves us from
needing to maintain custom kernel logic for every possible board and
daughterboard (Cape <https://beagleboard.org/cape> or PocketCape) setup and
curses us with a new syntax to configure all of the specifics of any given
chunk of hardware. While the ultimate goal really should be to hide end
users from the complexities of this new syntax and the data structures of
any given device, even casual users should build up some basic
understanding. To that end, please take a look at some of my thoughts
below, but don’t feel like you have to understand every word. That is,
unless you’ve just developed a new PocketCape and are about to punish
reward the world with your amazing new hardware. For those folks, lets work
together to make sure users of this rapidly expanding ecosystem have an
amazing experience.

First, a bit of a history lesson… From the launch of BeagleBone, we defined
in the System Reference Manual
<https://github.com/beagleboard/beaglebone-black/wiki/System-Reference-Manual#82_EEPROM>
a strategy of including I2C-based EEPROMs on all Capes such that those
boards could be automatically discovered and appropriate pin configurations
could be made. The software implemented by the BeagleBoard.org
community, Pantelis
Antoniou in particular <https://lwn.net/Articles/531783/>, to handle Capes
ended up not using all of the individual pin configuration details out of
the EEPROM, but instead relied on just the board name and version fields
identifying a particular set of modifications to the running device tree.
The CapeMgr module in the kernel would search for valid EEPROMs and pull
the appropriate overlay out of /lib/firmware.

For many hardware developers, the complexity of creating a device tree
overlay for their hardware felt too intimidating. To help those developers,
the BeagleBoard.org community, Charles Steinkuehler in particular
<https://beagleboard.org/discuss?place=msg%2Fbeagleboard%2FvOpZ-PkUgig%2F3c7W6-pa6OoJ>,
introduced a concept of a universal Cape that enabled as many drivers as
possible and utilized Pantelis’ pinmux helpers to dynamically select which
function was routed out to the pins by running some command-line scripts or
writing to some sysfs entries. This was eventually merged into the default
base board configuration such that no overlay actually needed to be loaded
for the dynamic pin configuration and the beaglebone-universal-io
config-pin utility is now maintained in a BeagleBoard.org github repo
<https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io>.
While this doesn’t automatically configure the hardware for Capes, simple
command-line instructions can be used at run-time to talk to the hardware
on many Capes or prototype wiring configurations.

Note: One issue with the universal Cape approach is that it locks up some
peripherals needed by some other drivers, so we still need to update the
device tree.

Another notable change in how BeagleBoard.org Debian images now handle
Capes is that device tree overlays are now handled in u-boot
<https://beagleboard.org/discuss?place=msg%2Fbeagleboard%2F1ahosuHBUTo%2FDvVeVrvsAwAJ>.
The CapeMgr kernel module has some great benefits for debugging things at
run-time and even loading overlays for hardware whose interface isn’t
configure until run-time, such as FPGAs or the PRUs. Still, loading the
overlays in the u-boot bootloader before the kernel is loaded provides us
with the ability to configure LCDs at boot and, perhaps more critically,
prevent some drivers from ever even being loaded. While drivers should
typically handle the case of being disable, some driver authors simply
never handle that case. Besides, loading and then unloading drivers would
simply waste time.

For better or worse, not all Capes include the configuration EEPROMs. Even
the BeagleBoard.org Robotics Cape, one of our official BeagleBoard.org Capes
<https://github.com/beagleboard/capes>, is currently without this EEPROM. A
configuration file, /boot/uEnv.txt, must therefore be edited to notify the
bootloader that a particular overlay needs to be loaded. The potential here
is that editing the text file in error can result in your board not
booting. Recovering from that error will require you to boot your board by
another means, such as via the SD card, USB, or serial. Once booted, you
can then mount and re-edit this file to fix your error. I personally do not
see many drawbacks of including the Cape configuration EEPROMs on all
boards, but cost has been cited as one concern as many of these boards face
pricing pressures to make them as affordable as possible.

As of today, the PocketBeagle System Reference Manual
<https://github.com/beagleboard/pocketbeagle/wiki/System-Reference-Manual#80-pocketcape-support->
doesn’t yet include any detailed recommendations on PocketCape design
requirements. Instead, we’ve been watching the best practices of early
developers and are seeking to document them. In fact, much of the first
available expansion hardware for PocketBeagle comes from the over 250
mikroBUS Click boards <https://www.mikroe.com/click> already in existence
that can be easily wired up to PocketBeagle and for which software support
is starting to emerge
<https://github.com/beagleboard/pocketbeagle/wiki/mikroBus%E2%84%A2-Click-Boards>.
The most fundamental aspect of this software support is creating a device
tree overlay entry that can be utilized to configure the drivers for the
board.

For my example, I’m going to look at the “simple gaming” hack-up board I
did for Maker Faire New York. You can find the project entry at
bbb.io/+f96db4 <https://beagleboard.org/+f96db4>, but the breadboard view
associated with my latest prototype is below.



Ignoring the battery charger for now, for which I haven’t added support,
there are 3 key elements requiring drivers: the LCD, the keyboard buttons
and the LEDs. Each of these can be tested using run-time configurations,
but let’s look at the steps required to create the device tree overlay.

The first thing we must do is free up any of the pins we need from the
pinmux helpers. While there are a few different places to find the device
tree entries for PocketBeagle, you can always find it in the BeagleBoard.org
Github repository for the particular Linux kernel you are using in the
provided Debian images
<https://github.com/beagleboard/linux/blob/4.14/arch/arm/boot/dts/am335x-pocketbeagle.dts>.
That’s where you’ll find all of the pinmux helpers you’ll need to disable.
In the overlay, you’ll see we point the fragment at the “ocp”
(on-chip-peripherals) entry one level up the hierarchy from where the
pinmux helper drivers are loaded. Then we simply set each of their status
entries to “disabled”. While this doesn’t remove these nodes, it prevents
the drivers from being loaded.

/*
 * Free up the pins used by the cape from the pinmux helpers.
*/
fragment@0 {
  target = <&ocp>;
  __overlay__ {
    P1_04_pinmux { status = "disabled"; }; /* LEDs - left */
    P2_03_pinmux { status = "disabled"; }; /* LEDs - right */
    P1_06_pinmux { status = "disabled"; }; /* LCD - CS */
    P1_08_pinmux { status = "disabled"; }; /* LCD - SCLK */
    P1_10_pinmux { status = "disabled"; }; /* LCD - MISO */
    P1_12_pinmux { status = "disabled"; }; /* LCD - MOSI */
    P2_01_pinmux { status = "disabled"; }; /* LCD - LED */
    P2_17_pinmux { status = "disabled"; }; /* LCD - DC */
    P2_19_pinmux { status = "disabled"; }; /* LCD - RST */
    P2_02_pinmux { status = "disabled"; }; /* keys - down */
    P2_04_pinmux { status = "disabled"; }; /* keys - right */
    P2_06_pinmux { status = "disabled"; }; /* keys - up */
    P2_08_pinmux { status = "disabled"; }; /* keys - left */
    P2_18_pinmux { status = "disabled"; }; /* keys - enter */
    P2_20_pinmux { status = "disabled"; }; /* keys - one */
    P2_22_pinmux { status = "disabled"; }; /* keys - esc */
    P2_24_pinmux { status = "disabled"; }; /* keys - five */
  };
};


For the next section of the overlay, I could have put part of it in my
previous snippet, but I wanted to make sure not to gloss over something
that caused me a fair bit of initial confusion. In addition to the pinmux
helpers, there are also some gpio helpers loaded to allocate the gpio pins
for sysfs. Sysfs exposes the pins directly to userspace programs through
the /sys/class/gpio interface. The part that confused me was that these
gpio entries are not each specified as individual driver instances, but
instead are provided as property nodes for a single instance of
gpio-of-helper called cape-universal. That means that I must disable all of
cape-universal and create a new instance of it only specifying the gpios
that I want to export. Unfortunately, this makes it verbose, but it is
fairly simple to copy-and-paste-and-delete the required lines for your
hardware. In the code snippet below, I’ve truncated it a bit below for
brevity, but you can see the full version in the Github entry
<https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/PB-simplegaming.dts>.
I’m not sure if this will be best for compatibility with userspace
applications or not, but, for now, I’ve simply specified the new name as
“cape-universal@1” in the hopes that any scripts can simply search for the
currently active instance

/*
 * Free up the gpios used by the cape-universal gpio helpers.
 */
fragment@1 {
  target = <&ocp>;
  __overlay__ {
    cape-universal { status = "disabled"; };
  };
};

/*
 * Make a new set of gpio helpers.
 */
fragment@2 {
  target = <&ocp>;
  __overlay__ {
    cape-universal@1 {
      compatible = "gpio-of-helper";
      status = "okay";
      pinctrl-names = "default";
      pinctrl-0 = <>;

      P1_02 {
        gpio-name = "P1_02";
        gpio = <&gpio2 23 0>;
        input;
        dir-changeable;
      };

      P1_20 {
        gpio-name = "P1_20";
        gpio = <&gpio0 20 0>;
        input;
        dir-changeable;
      };
      .
      .
      .
      P2_35 {
        gpio-name = "P2_35";
        gpio = <&gpio2 22 0>;
        input;
        dir-changeable;
      };
    };
  };
};


Now that we’ve got our gpios back, we can start having some more fun by
allocating drivers for our hardware. We’ll start with the LCD. One of the
really nice things about using Linux is that for most of the hardware out
there, we can probably find a suitable driver for it without needing to
code one up from scratch. For SPI and I2C based LCDs, the BeagleBoard.org
community, Matt Porter in particular
<https://elinux.org/images/1/19/Passing_Time_With_SPI_Framebuffer_Driver.pdf>,
produced a solution for adding framebuffer support for these displays. This
has evolved into the FBTFT project
<https://github.com/beagleboard/linux/tree/4.14/drivers/staging/fbtft> and
you can find quite a bit of information on the FBTFT project wiki
<https://github.com/notro/fbtft/wiki>. It happens that the tinydrm driver
<https://github.com/notro/tinydrm/wiki> in the kernel will be the ultimate
home for drivers for these small LCD panels, but the FBTFT project is a
good place to start to get something working.

In the snippet below, the first thing I must do is disable the spidev
driver instances used to provide userspace access to the SPI peripheral we
plan to use for our LCD; I pulled the “channel@0” and “channel@1” names out
of the primary device tree. The next thing I do is to create an instance of
the SPI driver I want to use with the pin resources, including modes, and
properties needed to configure the driver. These properties are often
documented for various drivers under the kernel source Documentation
devicetree directory
<https://github.com/beagleboard/linux/tree/4.14/Documentation/devicetree>,
but you can often find good examples exist elsewhere
<https://github.com/notro/fbtft/wiki/FBTFT-RPI-overlays>.

/*
 * Free up the SPI port used by the cape and reallocate it for the LCD.
 */
fragment@3 {
  target = <&spi0>;
  __overlay__ {
    #address-cells = <1>;
    #size-cells = <0>;
    status = "okay";

    channel@0 {
      status = "disabled";
    };
    channel@1 {
      status = "disabled";
    };

    adafruit18: adafruit18@0{
      compatible = "sitronix,st7735r";
      pinctrl-names = "default";
      pinctrl-0 = <
        &P1_06_spi_cs_pin   /* CS */
        &P1_08_spi_sclk_pin /* SCLK */
        &P1_10_spi_pin      /* MISO */
        &P1_12_spi_pin      /* MOSI */
        &P2_19_gpio_pin     /* RST */
        &P2_17_gpio_pin     /* DC */
        &P2_01_gpio_pin     /* LED */
      >;
      reg = <0>;
      buswidth = <8>;
      reset-gpios = <&gpio0 27 0>;
      dc-gpios = <&gpio2 1 0>;
      led-gpios = <&gpio1 18 1>;
      debug = <1>;
      spi-max-frequency = <32000000>;
      rotate = <0>;
      bgr;
      fps = <30>;
    };
  };
};

The final overlay snippet simply loads the gpio-keys and gpio-leds drivers
for the buttons and LEDs. Sure, you could use the basic gpio userspace
driver, but both of these drivers provide some real benefit to end users.
The gpio-keys driver produces keyboard events when the buttons are pressed,
meaning that I can create keyboard bindings in applications like MAME
<https://github.com/notro/fbtft/wiki/MAME> without needing to modify its
source code. The gpio-leds driver enables me to associate many triggers to
these new LEDs, again, without needing to write any new code.

Because the overlay has access to the symbols in the primary device tree, I
simply reference the pin modes, eliminating the need to look up some
register addresses and values. I’ve truncated the detailed setup of the
buttons, but you can find the Linux keyboard scancodes by searching the
Internet or the kernel source tree
<https://github.com/beagleboard/linux/blob/4.14/drivers/tty/vt/defkeymap.map>
.

/*
 * Load the drivers for the buttons and LEDs.
 */
fragment@4 {
  target-path="/";
  __overlay__ {
    gpio-keys {
      compatible = "gpio-keys";
      autorepeat;
      pinctrl-names = "default";
      pinctrl-0 = <
        &P2_02_gpio_pu_pin /* down */
        &P2_04_gpio_pu_pin /* right */
        &P2_06_gpio_pu_pin /* up */
        &P2_08_gpio_pu_pin /* left */
        &P2_18_gpio_pu_pin /* enter */
        &P2_20_gpio_pu_pin /* one */
        &P2_22_gpio_pu_pin /* esc */
        &P2_24_gpio_pu_pin /* five */
      >;

      left {
        label = "left";
        linux,code = <105>;
        gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
      };
      .
      .
      .
      enter {
        label = "enter";
        linux,code = <28>;
        gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
      };
    };

    capeleds {
      compatible = "gpio-leds";
      pinctrl-names = "default";
      pinctrl-0 = <         &P1_04_gpio_pin /* left */
&P2_03_gpio_pin /* right */       >;

      led@1 {
        label = "gamingpocketcape::left";
        gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>;
        default-state = "off";
      };

      led@2 {
        label = "gamingpocketcape::right";
        gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>;
        default-state = "off";
      };
    };
  };
};

That’s it! You can see the full file at
https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/PB-simplegaming.dts.
If you are building and plan to distribute your own Cape or PocketCape
hardware, you are strongly encouraged to read and make a Github fork of
https://github.com/beagleboard/bb.org-overlays and then submit a pull
request to allow users to easily enable and use your hardware.

While we still have a good way to go to fully spell out all the
recommendations for PocketCape developers, but this is an important start.
We are working to determine if recommending identifying EEPROMs on
PocketCapes is the best suggestion for all parties, but knowing that none
of the mikroBus Click boards include these mean that it can’t be our
exclusive solution.

Before making your PocketCape commercially available, I highly recommend
you at least check out the BeagleBoard.org Approved program
<https://beagleboard.org/approved> and engage with our community developers
<https://beagleboard.org/discuss> on producing the best experience possible.


-- 
https://beagleboard.org/about

-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups 
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beagleboard/CA%2BT6QPmSS1fiPpmxAk_5j%2BK1ga3tiJpi9Ce9HNTs26VM69K00Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to