BSP Manual - phyCORE-AM335x (L-818e.A7)

Table of Contents

phyCORE-AM335x BSP Manual (L-818.A7)
Document TitlephyCORE-AM335x BSP Manual (L-818.A7)
Document TypeBSP Manual
Yocto PageL-813e.A8 Yocto Reference Manual
Article NumberL-818e.A7
Release Date17.05.2019
Is Branch ofphyCORE-AM335x BSP Manual (L-818.Ax) Head

Introduction to Yocto

Please read the Yocto Reference Manual (L-813e.A8) for a better understanding of Yocto and this BSP.

Introduction to the BSP

Supported Hardware

For information on which boards and modules are supported by the release of PHYTEC’s AM335x unified BSP described herein, visit our web page at http://www.phytec.de/produkte/software/yocto/phytec-unified-yocto-bsp-releases/. Click the corresponding BSP release and look for the ordering number of your module in the column "Hardware Article Number". Now you can find the correct machine name in the corresponding cell under "Machine Name".

Building the BSP

This section will guide you through the general build process of the unified AM335x BSP using the phyLinux script. If you want to use our software without phyLinux and the Repo tool managed environment instead, you can find all Gitrepositories on:

https://git.phytec.de

barebox repository used:

Our barebox version is based on the barebox mainline and adds only a few patches which will be sent upstream in future releases.

Linux kernel repository used:

https://git.phytec.de/linux-mainline

Our AM335x kernel is based on the upstream kernel repository. As not all features are supported mainline, we added our own patch stack on top. As we share our code base with many of our other PHYTEC SoMs, you might also find patches for other platforms in the used branch. Link to the upstream kernel repository:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

To find out which tag is used for a specific board, take a look at your BSP source folder under:

meta-phytec/recipes-bsp/barebox/barebox_*.bb
meta-phytec/recipes-kernel/linux/linux-mainline_*.bb

Get the BSP

  • Create a fresh project directory:
host$ mkdir ~/yocto
  • Download and run the phyLinux script:

host$ cd ~/yocto 
host$ wget https://download.phytec.de/Software/Linux/Yocto/Tools/phyLinux 
host$ chmod +x phyLinux 
host$ ./phyLinux init

Basic Set-Up

There are a few important steps which have to be done before the main build process.

Finding the Right Software Platform

The AM335x BSP is a unified BSP, which means it supports a set of different PHYTEC carrier boards (CB) with different Systems on Module (SOMs). Sometimes it is not easy to find the right software for your PHYTEC board. So if you need to figure out the corresponding machine name of your board, have a look at Phytec Unified Yocto BSP Release and click on the corresponding BSP release, or refer to the files in the source folder of the BSP:

meta-phytec/conf/machine/*.conf

phycore-r2-am335x-1.conf machine configuration file:where you can find the platform name to the corresponding product IDs. All this information is also displayed by the phyLinux script:

#@TYPE: Machine 
#@NAME: phycore-r2-am335x-1 
#@DESCRIPTION: PHYTEC phyCORE-AM335x R2 512MiB RAM, 512MiB NAND flash, 8MiB SPI, PCM-953 (Kit), PM 
#@ARTICLENUMBERS: PCM-060-12102F04I.A0, KPCM-060-SYS-LIN.A0 
#@SUPPORTEDIMAGE: phytec-qt5demo-image/yogurt

Machine phycore-r2-am335x-1 represents the PCM-953 (Kit) CB with the PCM-060-12102F04I.Ax SOM.

Selecting a Software Platform

To select the correct SoC, BSP version, and platform call:

host$ ./phyLinux init

It is also possible to pass this information directly using command line parameters:

host$ MACHINE=phyboard-regor-am335x-1 ./phyLinux init -p am335x -r PD19.1.0

Starting the Build Process

Please read section Initialization in the Yocto Reference Manual for more information.

Refer to Start the Build.

BSP Images

All images generated by Bitbake are deployed to yocto/build/deploy/images/<machine>.

The following list shows, for example, all files generated for the AM335x SoC, phycore-r2-am335x-1 machine:

  • Barebox: barebox.bin
  • Barebox configuration: barebox.config
  • Barebox PBL
    • for memory boot devices (MMC, NAND): MLO
    • for memory boot devices (SPI): MLO.spi
    • for peripheral boot devices (EMAC, UART): MLO.per
  • Kernel: zImage
  • Kernel device tree file: zImage-am335x-phycore-nand-eeprom-rtc-spi-tmp.dtb
  • Kernel configuration: zImage.config
  • Root filesystem: phytec-qt5demo-image-phycore-r2-am335x-1.tar.gz, phytec-qt5demo-image-phycore-r2-am335x-1.ubifs, phytec-qt5demo-image-phycore-r2-am335x-1.ext4
  • SD card image: phytec-qt5demo-image-phycore-r2-am335x-1.sdcard

Booting the System

Boot Mode Settings

This page lists the jumper/switches settings for different boot modes on the carrier boards. The jumper and switches change the SYSBOOT pins of the AM335x controller.

The AM335x ROM code has a dedicated boot order for each setting. If the first boot setup fails, the ROM loader tries the next one.

A list with all settings of the SYSBOOT pins and the boot order can be found in the AM335x Technical Reference Manual (Revision P), Chapter 26.1.6.2.1:

https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf

phyCORE-AM335x RDK carrier board (PCM953)

Not all possible combinations are listed below. Check the schematics for more possibilities.

Boot selection is done with dip switch S5 on the carrier board.

Setting dip switch 1 to off sets the default boot setting from SOM, which should be NAND boot.

Reset by unplugging the power to boot with the modified boot settings.

NAND Boot

Boot order: NAND, NANDI2C, MMC0, UART0

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |on |on |off|off|on |off|off|

SD-card Boot

Boot order: MMC0, SPI0, UART0, USB0

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |on |on |on |off|on |off|off|

eMMC Boot

Boot order: MMC1 (eMMC), MMC0 (SD), UART0, USB0

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |off|off|on |on |on |off|off|

SPI Boot

Boot order: SPI0, MMC0, EMAC1, UART0

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |on |off|off|on |on |off|off|

UART Boot

Boot order: UART0, SPI0, NAND, NANDI2C

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |off|on |off|off|off|off|off|

Ethernet Boot

Boot order: EMAC1, SPI0, NAND, NANDI2C

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---------------------------------
|on |off|on |on |off|off|on |off|

phyBOARD-WEGA-AM335x (PBA-CD-02)

On the phyBOARD-WEGA, only two boot modes can be selected with the S4 switch.

NAND Boot

Boot order: NAND, NANDI2C, MMC0, UART0

| 1 |
-----
|off|

SD-card Boot

Boot order: MMC0, SPI0, UART0, USB

| 1 |
-----
|off|

phyBOARD-REGOR-AM335x (PBA-C-08)

On the phyBOARD-REGOR, only two boot modes can be selected with the S4 switch.

NAND Boot

Boot order: NAND, NANDI2C, MMC0, UART0

| 1 |
-----
|off|

SD-card Boot

Boot order: MMC0, SPI0, UART0, USB

| 1 |
-----
|on |

Beaglebone black

Boot order: MMC1(eMMC), MMC0(SD), USB, UART

When pressing the button "S2" while power on, the device boot order is:

Boot order: MMC0(SD), USB, UART

Booting from NAND Flash

NAND is the default boot source. To update the software of the NAND Flash, see Updating the Software.

Booting from SD Card

Booting from an SD card is useful in several situations, for example, if the board does not start due to a damaged bootloader. To boot from an SD card, the SD card must be formatted in a special way as the ROM loader expects the first stage bootloader in a FAT partition.

Bitbake, a tool integrated into Yocto, creates an SD card image at the end of the BSP build. This image has the ending *.sdcard and can be found under build/deploy/images/<MACHINE>/<IMAGENAME>-<MACHINE>.sdcard. It contains all BSP files, in correctly formatted partitions, and can be copied to the SD card easily using the single Linux command dd.

You can also find ready-to-use *.sdcard images on our FTP server.

To create your bootable SD card with the dd command, you must have root privileges. Because of that, you must be very careful when selecting the destination device for the dd command! All files on the selected destination device will be erased immediately without any further query! Consequently, selecting the wrong device can also erase your hard drive!

To create your bootable SD card, you must first find the correct device name of your SD card and possible partitions. Then unmount the partitions before you start copying the image to the SD card.

  • In order to get the correct device name, first remove your SD card and execute ls /dev.
  • Now insert your SD card and execute ls /dev again.
  • Compare the two outputs to find the new device name(s) listed in the second output. These are the device names of the SD card (device and partitions if the SD card is formatted).
  • In order to verify the device names found, execute the command dmesg. Within the last lines of its output, you should also find the device names, for example sde (depending on your system).

Now that you have the device name /dev/<your_device> (e.g. /dev/sde), you can recognize the partitions which must be unmounted if the SD card is formatted, too. In this case, you will also find /dev/<your_device> with an appended number (e.g. /dev/sde1) in the output. These represent the partition(s) to be unmounted.

  • Unmount all partitions with:
host$ umount /dev/<your_device><number>
  • After having unmounted all devices with an appended number (<your_device><number>), you can create your bootable SD card with:

host$ sudo dd if=<IMAGENAME>-<MACHINE>.sdcard of=/dev/<your_device> bs=1MB conv=fsync

using the device name (<your_device>) without appended number (e.g. sde) which stands for the whole device.

The parameter conv=fsync forces a sync operation on the device before dd returns. This ensures that all blocks are written to the SD card and are not still in memory.

Booting from eMMC

An eMMC image is an extended SD Card image. The difference is that the ROM code shouldn't load the MLO from a FAT partition on eMMCs. Instead, it loads raw binaries from the given addresses.

eMMC images are available for supported modules with the suffic *.emmc on our FTP server.

Booting from UART

If no SD card slot is available, it is also useful to be able to boot at least the bootloader from UART. This is possible with the UART0 interface of the AM335x. Make sure that the Boot Mode Settings is set correctly to serial. The boot mode is set correctly if you see a lot of "C" characters on the console output after booting.

The following script facilitates booting from serial. But this can also be done directly from a serial terminal program like minicom by first loading the MLO.per (first stage bootloader for peripheral boot) and then the barebox.bin file over xmodem.

When using the script, please close all serial terminal programs.

#!/bin/sh
SERIAL=/dev/<ttyXX>
FILEPATH=<path>
MLO=$FILEPATH/MLO.per
BAREBOX=$FILEPATH/barebox.bin
 
stty -F $SERIAL 115200
sx -vv $MLO < $SERIAL > $SERIAL
sx -vv $BAREBOX < $SERIAL > $SERIAL
minicom -w -D $SERIAL

Change the SERIAL variable to the correct tty device on your host and adapt the FILEPATH to your needs.

After the MLO.per and barebox.bin files are transferred over serial to the target, the minicom starts with showing the barebox.bin output and you will get to the barebox prompt.

Booting from SPI NOR Flash

The phyCORE-AM335x modules are optionally equipped with SPI NOR Flash. To boot from SPI Flash, select the correct boot mode as described in the hardware manual of your PHYTEC board. The SPI Flash is usually quite small so that only the two bootloaders, the Linux kernel and the device tree, can be stored. The root filesystem is taken from NAND Flash by default. How to flash the SPI NOR is described in section Updating the Software.

Booting a Bootloader from Network

AM335x's ROM code can boot an MLO from the first port of the EMAC interface, using the standard TCP/IP network boot protocols BOOTP and TFTP.

Not all AM335x boards are able to boot from network.

The following tools will be needed to boot the MLO (barebox) from Ethernet:

  1. a BOOTP/DHCP server
  2. a TFTP server and
  3. a tool for starting/stopping a service.
  • For Ubuntu, install:
host$ sudo apt install isc-dhcp-server tftpd-hpa xinetd

After the installation of the packages, you have to configure the DHCP and TFTP server.

Configurations for the DHCP server

  • Edit /etc/dhcp/dhcpd.conf:
# Basic boot sequence: AM335x ROM -> MLO -> barebox -> kernel
subnet 192.168.3.0 netmask 255.255.255.0
{
  # The filenames must correspond to the barebox and MLO files which are placed in the /tftpboot directory
  range dynamic-bootp 192.168.3.11 192.168.3.100;
  ignore-client-uids true;
  if substring (option vendor-class-identifier, 0, 10) = "AM335x ROM"
  {
    filename "MLO";
  }
  elsif substring (option vendor-class-identifier, 0, 18) = "am335x barebox-mlo"
  {
    filename "barebox.bin";
  }
  range 192.168.3.101 192.168.3.199;
}

Set up for the TFTP server

  • Edit /etc/xinetd.d/tftp:
service tftp
{
	protocol = udp
	port = 69
	socket_type = dgram
	wait = yes
	user = root
        server = /usr/sbin/in.tftpd
	server_args = -s /tftpboot
	disable = no
}
  • Create a directory to store the TFTP files:
host$ sudo mkdir /tftpboot
host$ sudo chmod -R 777 /tftpboot
host$ sudo chown -R nobody /tftpboot
  • Edit /etc/default/isc-dhcp-server to bind the server to a single network interface:
INTERFACES="enp0s31f6"
  • Configure a static IP address for the appropriate interface:

host$ ip addr show enp0s31f6

You will receive output like:

2: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
   link/ether ff:ff:ff:ff:ff:ff brd ff:ff:ff:ff:ff:ff
   inet 192.168.3.10/16 brd 192.168.255.255 scope global enp0s31f6
      valid_lft forever preferred_lft forever
   inet6 ffff::ffff:ffff:ffff:ffff/64 scope link 
      valid_lft forever preferred_lft forever
  • Copy your barebox images to the /tftpboot directory.

  • Restart the services to pick-up the configuration changes:
host$ systemctl restart isc-dhcp-server
host$ systemctl restart tftpd-hpa
  • Now connect the first port of the board to your host system, configure the board to network boot and start it.

Booting the Kernel from Network

Booting from a network means loading the kernel over TFTP and the root filesystem over NFS. The bootloader itself must already be loaded from any other boot device available.

Development Host Preparations

On the development host, a TFTP server must be installed and configured. An example on how to set up a TFTP server can be found in the section above: Booting a Bootloader from Network. Usually, TFTP servers use the /tftpboot directory to fetch files from. If you built your own images, please copy them from the BSP’s build directory to the /tftpboot directory.

We also need a network connection between the embedded board and the TFTP server. The server should be set to IP 192.168.3.10 and netmask 255.255.255.0, or a DHCP server can be used instead. Setting up a DHCP server is also explained in the section: Booting a Bootloader from Network.

After the installation of the TFTP server, an NFS server needs to be installed. The NFS server is not restricted to a certain file system location, so all we have to do on most distributions is to modify the file /etc/exports and export our root filesystem to the embedded network. In this example, the whole work directory file is exported and the ”lab network” address of the development host is 192.168.3.10. This means the IP addresses have to be adapted to the local needs:

/home/<user>/<rootfspath> 192.168.3.10/255.255.255.0(rw,no_root_squash,sync,no_subtree_check)

where <user> must be replaced with your home directory name. The <rootfspath> can be set to a folder which contains a rootfs tar.gz image extracted with sudo.

Preparations on the Embedded Board

  • To find out the Ethernet settings in the bootloader of the target, type:
bootloader$ devinfo eth0

With your development host set to IP 192.168.3.10 and netmask 255.255.255.0, the target should return:

Parameters:
  ethaddr: 98:5d:ad:c9:61:d9 (type: MAC)
  gateway: 192.168.3.10 (type: ipv4)
  ipaddr: 192.168.3.11 (type: ipv4)
  linux.bootargs: ip=192.168.3.11:192.168.3.10:192.168.3.10:255.255.255.0::: (type: string)
  linux.devname:  (type: string)
  mode: static (type: enum) (values: "dhcp", "static", "disabled")
  netmask: 255.255.255.0 (type: ipv4)
  serverip: 192.168.3.10 (type: ipv4)
  • The network configuration is set over the nv variables. To list the nv variables:

bootloader$ nv
  • Change a value of a nv variable with the command

nv <variable>=<value>

For example you can change the IP address to DHCP instead of using a static one.

  • Configure:
bootloader$ nv dev.eth0.mode=dhcp
  • Further information can be found in the barebox documentation:
https://www.barebox.org/doc/latest/user/networking.html#network-configuration
  • Type saveenv if you made any changes.
  • Activate settings with 'ifup eth0'
  • Set up paths for images and NFS in the file /env/boot/net.

Please note that these modifications will only affect the bootloader settings. For information on modifying the IP setting in Linux, please refer to chapter Network.

Booting the Embedded Board

  • To boot from the network call:
bootloader$ boot net

or restart the board and press m to stop autoboot.

You will get a menu:

Main menu
      1: Boot default
      2: Detect bootsources
      3: Settings
      4: Save environment
      5: Shell
      6: Reset
  • Press 2 and select net in order to boot the board from network.

Custom Boot Setup

You may have custom boot requirements that are not covered by the four available boot files (nand, net, mmc, spi). If this is the case, you can create your own custom boot entry specifying the kernel and root filesystem location.

  • First create your own boot entry in barebox named, in the example below, "custom":
bootloader$ edit /env/boot/custom
  • Use the following template to specify the location of the Linux kernel and root filesystem:
#!/bin/sh
 
global.bootm.image="<kernel_loc_bootm.image>"
global.bootm.oftree="<dts_loc_bootm.oftree>"
 
nfsroot="<nfs_root_path>"
bootargs-ip
/env/init/config-expansions
 
global.linux.bootargs.dyn.root="<rootfs_loc_dyn.root>"

Please note that the text in <> such as <kernel_loc_bootm.image>, <rootfs_loc_dyn.root>, and <nfs_root_path> are intended to be replaced with user specific values as described in the following example.

<kernel_loc_bootm.image> specifies the location of the Linux kernel image and can be:

/dev/nand0.root.ubi.kernel - To boot the Linux kernel from NAND Flash
/dev/m25p0.kernel - To boot the Linux kernel form SPI NOR Flash
/mnt/tftp/zImage - To boot the Linux kernel via TFTP 
/boot/zImage - To boot the Linux kernel from SD/MMC card

<dts_loc_bootm.oftree> specifies the location of the device tree binary and can be:

/dev/nand0.root.ubi.oftree - To boot the device tree binary from NAND Flash
/dev/m25p0.oftree - To boot the device tree binary from SPI NOR Flash
/mnt/tftp/oftree - To boot the device tree binary via TFTP 
/boot/oftree - To boot the device tree binary from SD/MMC card 

<rootfs_loc_dyn.root> specifies the location of the root filesystem and can be:

root=ubi0:root ubi.mtd=root rootfstype=ubifs - To mount the root filesystem from NAND Flash
root=/dev/nfs nfsroot=$nfsroot,vers=3,udp rw consoleblank=0 - To mount the root filesystem via NFS 
root=/dev/mmcblk0p2 rootwait - To mount the root filesystem from SD/MMC card 

<nfs_root_path> is only required if mounting the root filesystem from NFS is desired. Replace with the following:

nfsroot="/home/${global.user}/nfsroot/${global.hostname}"
  • After completing the modifications, exit the editor using CTRL+D and save the environment:
bootloader$ saveenv
  • To run your custom boot entry from the barebox shell, enter:
bootloader$ boot custom

If you want to configure the bootloader to always boot from "custom", you need to create the /env/nv/boot.default file. Here, you can just insert "custom" and save it. Otherwise, the boot sources and boot order is defined in /env/init/bootsource.

Updating the Software

This chapter explains how to use the barebox bootloader to update the images in NAND, eMMC, and SPI NOR Flashes.

Updating from Network

AM335x boards that have an Ethernet connector can be updated over network. As the bootloader only supports the first Ethernet port, the development host has to be connected to the first Ethernet port of the target. Be sure to set up the development host correctly. The IP needs to be set to 192.168.3.10, the netmask to 255.255.255.0, and a TFTP server needs to be available.

Updating NAND Flash from Network

To update the first stage bootloader MLO, you may use the barebox_update command. This provides a handler which automatically erases and flashes copies of the MLO image into the first four blocks of the NAND Flash. This makes the system more robust against ECC issues. If one block is corrupted, the ROM loader does use the next block.

  • Type:
bootloader$ barebox_update -t MLO.nand /mnt/tftp/MLO

On startup, the TFTP server is automatically mounted to /mnt/tftp. So copying an image from TFTP to flash can be done in one step. Do not get confused when doing an ls on the /mnt/tftp folder. The TFTP protocol does not support anything like ls so the folder will appear to be empty.

The barebox as second stage bootloader can also be updated with a barebox_update command. But it is only stored once in the flash.

  • Type:
bootloader$ barebox_update -t nand /mnt/tftp/barebox.bin

We also recommend erasing the old barebox environment. Otherwise, the new barebox will use the old environment.

  • First erase the old environment with:
bootloader$ erase /dev/nand0.bareboxenv.bb

After erasing the environment, you have to reset your board. Otherwise, the barebox will still use the old environment.

  • To reset your board in order to get the new barebox running, type:
bootloader$ reset
  • Create UBI volumes for Linux kernel, oftree, and root filesystem in NAND:
bootloader$ ubiformat /dev/nand0.root
bootloader$ ubiattach /dev/nand0.root
bootloader$ ubimkvol -t static /dev/nand0.root.ubi kernel 8M
bootloader$ ubimkvol -t static /dev/nand0.root.ubi oftree 1M
bootloader$ ubimkvol -t dynamic /dev/nand0.root.ubi root 0
  • Now get the Linux kernel and oftree from your TFTP server and store it in the NAND Flash:
bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /mnt/tftp/zImage
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /mnt/tftp/oftree
  • To flash Linux’s root filesystem to NAND, use:
bootloader$ cp -v /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root
  • Change the boot configuration of your board to NAND boot if necessary.
  • Reset your board.

Updating eMMC from Network

From a high-level point of view, an eMMC device is like an SD card. Therefore, it is possible to flash the image <name>.sdcard from the Yocto build system directly to the eMMC. The image contains the bootloader, kernel, device tree, and root filesystem.

  • To flash the SD card image, use:
bootloader$ cp -v /mnt/tftp/<name>.sdcard /dev/mmc1
After flashing the SD card image, the root filesystem does not use all available space on the device.
  • The AM335x expects four copies of the MLO as raw binaries between the MBR and boot partition. Flashing it on the correct addresses can be done with the barebox_update command:
bootloader$ barebox_update -t MLO.emmc /mnt/tftp/MLO

Another way is to flash the <name>.emmc image to the eMMC. This one includes the MLO images between MBR and boot partition.

  • To reset your board in order to get the new barebox running, type:
bootloader$ reset
  • To update the kernel and device tree, use:
bootloader$ ls /mnt/mmc1.0
bootloader$ cp /mnt/tftp/zImage /mnt/mmc1.0/
bootloader$ cp /mnt/tftp/oftree /mnt/mmc1.0/

Updating SPI NOR Flash from Network

The MLO for the SPI NOR Flash has to be byte-swapped. There is a handler for the barebox_update command to make this on the fly. Thus, a special MLO image is not required.

  • To update the first stage bootloader in the SPI Flash from network, use:
bootloader$ barebox_update -t MLO.spi /mnt/tftp/MLO
  • After that, use the following command to flash the barebox:
bootloader$ barebox_update -t spi /mnt/tftp/barebox.bin

We recommend erasing the environment of the old barebox. Otherwise, the new barebox will still use the old environment:

  • First, erase the old environment:
bootloader$ erase /dev/m25p0.bareboxenv

After erasing the environment, you have to reset your board. Otherwise the barebox will still use the old environment:

  • To reset your board in order to get the new barebox running, type:
bootloader$ reset
  • The kernel and oftree are then updated with the regular erase and cp commands:
bootloader$ erase /dev/m25p0.kernel
bootloader$ cp /mnt/tftp/zImage /dev/m25p0.kernel
bootloader$ erase /dev/m25p0.oftree
bootloader$ cp /mnt/tftp/oftree /dev/m25p0.oftree
  • Change the boot configuration of your board to NOR boot, if necessary, and reset your board.

The root filesystem is too big to fit into the SPI NOR Flash. So the default configuration when booting from SPI is to take the root filesystem from NAND Flash.

When booting from SPI Flash, the AM335x expects the MLO in a big endian format. The barebox_update command, with the MLO.spi type, takes the MLO image and converts it on the fly to the correct format and flashes it to SPI. If you can not use the barebox_update command, you can use the MLO.spi file which also drops out of the image build.

Updating from SD Card

To update an AM335x board from an SD card, the SD card used for updating needs to be mounted after the board is powered and the boot sequence has to be stopped at the bootloader prompt. The SD Card is mounted to:

  • /boot if the board is booted from an SD card
  • /mnt/mmc0.<X> if the board is booted from any other device

Updating NAND Flash from SD Card

To update the images on the NAND Flash from an SD card, the same commands as updating from TFTP are used with just the path parameters adapted.

  • Type:
bootloader$ barebox_update -t MLO.nand /boot/MLO
bootloader$ barebox_update -t nand /boot/barebox.bin

We recommend erasing the environment of the old barebox. Otherwise the new barebox will still use the old environment.

  • First erase the old environment with:
bootloader$ erase /dev/nand0.bareboxenv.bb

After erasing the environment, you have to reset your board. Otherwise the barebox will still use the old environment.

  • To reset your board in order to get the new barebox running type:
bootloader$ reset
  • Create UBI volumes for Linux kernel, oftree, and root filesystem in NAND:
bootloader$ ubiformat /dev/nand0.root
bootloader$ ubiattach /dev/nand0.root

bootloader$ ubimkvol -t static /dev/nand0.root.ubi kernel 8M
bootloader$ ubimkvol -t static /dev/nand0.root.ubi oftree 1M
bootloader$ ubimkvol -t dynamic /dev/nand0.root.ubi root 0
  • Now get the Linux kernel and oftree from your SD card and store it in the NAND Flash:
bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /boot/zImage
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /boot/oftree
  • To flash Linux’s root filesystem to NAND, use:
bootloader$ cp /boot/rootfs.ubifs /dev/nand0.root.ubi.root
  • Change the boot configuration of your board to NAND boot, if necessary, and reset your board.

Updating eMMC from SD Card

Since both eMMC and SD Card images are almost identical, the SD Card image can be flashed to the eMMC.

bootloader$ cp -v /dev/mmc0 /dev/mmc1

The difference between both images is the MLO. This must be updated with the barebox_update command.

bootloader$ barebox_update -t MLO.emmc /mnt/mmc0.0/MLO

We do not recommend this way of updating the eMMC as it is slow and not very reliable.

Updating SPI NOR Flash from SD Card

To update the images on the SPI Flash from an SD card, the same commands as updating from TFTP are used with just the path parameters adapted.

  • Type:
bootloader$ barebox_update -t MLO.spi /boot/MLO 
bootloader$ barebox_update -t spi /boot/barebox.bin

We recommend erasing the environment of the old barebox. Otherwise, the new barebox will still use the old environment.

  • First erase the old environment with:
bootloader$ erase /dev/m25p0.bareboxenv 

After erasing the environment, you have to reset your board. Otherwise, the barebox will still use the old environment.

  • To reset your board in order to get the new barebox running type:
bootloader$ reset
  • The kernel and oftree are then updated with the regular erase and cp commands:
bootloader$ erase /dev/m25p0.kernel
bootloader$ cp /boot/zImage /dev/m25p0.kernel
bootloader$ erase /dev/m25p0.oftree
bootloader$ cp /boot/oftree /dev/m25p0.oftree
  • Change the boot configuration of your board to NOR boot, if necessary.
  • Reset your board.

The root filesystem is too big to fit into the SPI NOR Flash. So the default configuration when booting from SPI is to take the root filesystem from NAND Flash.

When booting from SPI Flash, the AM335x expects the MLO in a big endian format. The barebox_update command, with the MLO.spi type, takes the MLO image and converts it on the fly to the correct format and flashes it to SPI. If you can not use the barebox_update command, you can use the MLO.spi file which also drops out of the image build.

Updating from USB Flash Drive

It is not possible to boot an AM335x board from a USB Flash Drive. However, the barebox bootloader does support USB Flash Drives and is also able to update NAND and SPI NOR Flashes from them.

  • To update from USB Flash Drive, boot the system from any bootable device.
  • Press any key to stop autoboot.
  • Plug in a USB Flash Drive containing the images. Barebox supports vfat and ext4 (read-only).
  • Check the USB bus:
bootloader$ usb

This should print some output similar to:

USB: scanning bus for devices...
Bus 001 Device 001: ID 058f:6387 Intenso Rainbow Line 
Using index 0 for the new disk 
1 USB Device(s) found

If the USB Flash Drive is inserted during boot, it might not be detected the first time. In this case, execute the usb command twice. This will create a device disk0 under /dev and the partitions which can be listed with:

bootloader$ ls /dev/disk0*

You should see:

/dev/disk0 /dev/disk0.0 

By default, all mountable devices get mounted to /mnt/. The USB Flash Drive should be visible as /mnt/disk0 and /mnt/disk0.0. If not, it must be mounted manually:

bootloader$ mkdir /mnt/disk0.0 
bootloader$ mount /dev/disk0.0 /mnt/disk0.0/

Updating NAND Flash from USB Flash Drive

To update the images on the NAND Flash from a USB Flash Drive, the same commands as updating from TFTP are used with just the path parameters adapted.

  • Type:
bootloader$ barebox_update -t MLO.nand /mnt/disk0.0/MLO 
bootloader$ barebox_update -t nand /mnt/disk0.0/barebox.bin

We recommend erasing the environment of the old barebox. Otherwise, the new barebox will still use the old environment.

  • First erase the old environment:
bootloader$ erase /dev/nand0.bareboxenv.bb

After erasing the environment, you have to reset your board. Otherwise, the barebox will still use the old environment.

  • To reset your board in order to get the new barebox running, type:
bootloader$ reset
  • Create UBI volumes for Linux kernel, oftree and root filesystem in NAND:
bootloader$ ubiformat /dev/nand0.root
bootloader$ ubiattach /dev/nand0.root

bootloader$ ubimkvol -t static /dev/nand0.root.ubi kernel 8M
bootloader$ ubimkvol -t static /dev/nand0.root.ubi oftree 1M
bootloader$ ubimkvol -t dynamic /dev/nand0.root.ubi root 0
  • Now get the Linux kernel and oftree from your USB Flash Drive and store it into the NAND Flash:
bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /mnt/disk0.0/zImage 
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /mnt/disk0.0/oftree
  • To flash Linux’s root filesystem to NAND, use:
bootloader$ cp /mnt/disk0.0/rootfs.ubifs /dev/nand0.root.ubi.root
  • Change the boot configuration of your board to NAND boot if necessary.
  • Reset your board.

Updating eMMC from USB Flash Drive

Either flash the SDcard image and MLO from a USB Flash Drive to the eMMC:

bootloader$ cp -v /mnt/disk0.0/image.sdcard /dev/mmc1 
bootloader$ barebox_update -t MLO.emmc /mnt/disk0.0/MLO

or use the eMMC image.

bootloader$ cp -v /mnt/disk0.0/image.emmc /dev/mmc1

Updating SPI NOR Flash from USB Flash Drive

To update the images on the SPI Flash from USB Flash Drive, the same commands as updating from TFTP are used with just the path parameters adapted.

  • Type:
bootloader$ barebox_update -t MLO.spi /mnt/disk0.0/MLO 
bootloader$ barebox_update -t spi /mnt/disk0.0/barebox.bin

We recommend erasing the environment of the old barebox. Otherwise, the new barebox will still use the old environment.

  • First erase the old environment with:
bootloader$ erase /dev/m25p0.bareboxenv

After erasing the environment, you have to reset your board. Otherwise, the barebox will still use the old environment.

  • To reset your board in order to get the new barebox running, type:
bootloader$ reset
  • The kernel and oftree are then updated with the regular erase and cp commands:
bootloader$ erase /dev/m25p0.kernel 
bootloader$ cp /mnt/disk/zImage /dev/m25p0.kernel
bootloader$ erase /dev/m25p0.oftree
bootloader$ cp /boot/oftree /dev/m25p0.oftree
  • Change the boot configuration of your board to NOR boot if necessary.
  • Reset your board.

The root filesystem is too big to fit into the SPI NOR Flash. So the default configuration when booting from SPI will take the root filesystem from NAND Flash.

When booting from SPI Flash, the AM335x expects the MLO in a big-endian format. The barebox_update command, with the MLO.spi type, takes the MLO image and converts it on the fly to the correct format and flashes it to SPI. If you can not use the barebox_update command, you can take the MLO.spi file which also drops out of the image build.

Updating NAND Bootloader from userspace

With sumo (BSP-Yocto-AM335x-PD19.1.0), the BSP includes a script to update the bootloaders in NAND flash. The script is called bbu.sh.

/usr/bin/bbu.sh <MLO> <BOOTLOADER>
MLO             - AM335x CH image format
BOOTLOADER      - barebox image format

The MLO and barebox.bin image have to be available from userspace. For example, use the bootloader images on SD-Card:

target$ mount /dev/mmcblk0p1 /mnt/

Call bbu.sh with the path to the images.

target$ bbu.sh /mnt/MLO /mnt/barebox.bin
Flashing /mnt/MLO to mtd5 partition
Flashing /mnt/MLO to mtd6 partition
Flashing /mnt/MLO to mtd7 partition
Flashing /mnt/MLO to mtd8 partition
Flashing /mnt/barebox.bin to mtd9 partition
Flashing /mnt/barebox.bin to mtd10 partition

RAUC

With sumo, the RAUC (Robust Auto-Update Controller) mechanism support has been added to Yogurt. It controls the procedure of updating a device with new firmware. This includes updating Linux kernel, Device Tree, and rootfs. It does not update the bootloader. For more information about RAUC, see https://rauc.readthedocs.io/en/latest/.

RAUC uses the barebox bootchooser and state framework (see Barebox Bootchooser and Barebox State-Framework for more information). It can be used in different update scenarios. Have a look at the use cases below the example setup used in the BSP.

RAUC on AM335x

With the BSP-Yocto-AM335x-PD19.10, unified AM335x BSP release RAUC (Robust Auto-Update Controller) can be used with NAND flash. It is supported with the phycore-r2-am335x-1 machine (Kit). RAUC can be used in different update scenarios. As an example, we configured the BSP to use an A-B setup with two redundant systems.

RAUC Partition Layout

The partition layout is defined in the /etc/rauc/system.conf file. Shown here is the system_nand.conf from meta-yogurt used for our example setup:

[system]
compatible=@MACHINE@
bootloader=barebox
mountprefix=/mnt/rauc
 
[handlers]
pre-install=/usr/bin/rauc_downgrade_barrier.sh
 
[keyring]
path=ca.cert.pem
 
#System A
[slot.rootfs.0]
device=/dev/ubi0_2
type=ubifs
bootname=system0
 
[slot.kernel.0]
device=/dev/ubi0_0
type=ubivol
parent=rootfs.0
 
[slot.dtb.0]
device=/dev/ubi0_1
type=ubivol
parent=rootfs.0
 
#System B
[slot.rootfs.1]
device=/dev/ubi0_5
type=ubifs
bootname=system1
 
[slot.kernel.1]
device=/dev/ubi0_3
type=ubivol
parent=rootfs.1
 
[slot.dtb.1]
device=/dev/ubi0_4
type=ubivol
parent=rootfs.1

There is no configuration for the barebox since a barebox update with RAUC is not supported.

Updates with RAUC use an openSSL certificate to verify the validity of an image. The BSP includes a certificate which can be used for development. In a productive system, however, it is highly recommend to use a self-created key and certificate.

Initialize NAND Flash for RAUC

To use RAUC, the NAND flash first needs to be initialized and flashed. To initialize the NAND flash to use with RAUC, the partitioning scheme from the system.conf file needs to be created. Use the /env/bin/create_nand_partitions script for that. If this script does not exist on your barebox, please make sure that you first perform the steps described in How to setup RAUC for your Machine.

  • Run:
bootloader$ create_nand_partitions

Performing this step formats the root UBI partition of the NAND flash and deletes all its content.

  • Now an initial system needs to be flashed to the new partitions. To flash the initial image from network, run:
bootloader$ init_flash_from_tftp

Make sure that the kernel, devicetree, and root filesystem are available via a TFTP server as zImage, oftree, and root.ubifs (see Updating from Network).

Creating RAUC Bundles

To update your system with RAUC, a RAUC bundle (.raucb) needs to be created. It contains all required images and scripts for the update and a RAUC manifest.raucm that describes the content of the bundle for the RAUC update on the target. The BSP includes a Yocto target that lets you build a RAUC bundle from your Yocto build.

To create the bundle with Yocto, run:

host$ bitbake phytec-qt5demo-bundle

in your Yocto build.

This results in the creation of a .raucb bundle file in the deploy/images/<machine-name>/phytec-qt5demo-bundle-<machine-name>.raucb file which can be used for an update described in the next chapter. There is no need to create a manifest.raucm manually as it is created automatically during the build of the bundle. But as a reference, the created manifest would look something like:

[update]
compatible=phycore-r2-am335x-1
version=r0
description=PHYTEC rauc bundle based on BSP-Yocto-AM335x-PD19.1.0
build=20181210110005
 
[image.rootfs]
sha256=1b85f3a380f970f4e3aa640406f3cab9848febdc7f2897884a12de020c8a082b
size=128894976
filename=phytec-qt5demo-image-phycore-r2-am335x-1.ubifs
 
[image.kernel]
sha256=6d615338c776be130fdf7c936a1f758a5319fb6c6a62633c2c50e18fa37d0add
size=7263456
filename=zImage-phycore-r2-am335x-1.bin.img
 
[image.dtb]
sha256=99e18db4610add53a3c25172ada03d786cdabe330684ddd06bc2bba73d43781a
size=40943
filename=am335x-phycore-nand-eeprom-rtc-spi-tmp.dtb.img

For more information about the manifest format, see https://rauc.readthedocs.io/en/latest/reference.html#manifest.

Currently, there is a bundle target for the phytec-qt5demo-image (phytec-qt5demo-bundle) and the phytec-headless-image (phytec-headless-bundle).

Update NAND Flash with RAUC

To update the NAND flash with RAUC, the RAUC bundle file previously created first needs to be copied to the board or to a memory device which can be mounted in Linux. One way is to copy the bundle file with scp, but make sure that there is enough space left on the board's filesystem. To do this, boot the target board to Linux and connect it via Ethernet to your host PC.

  • Run on the host:
host$ scp phytec-qt5demo-bundle-phycore-r2-am335x-1.raucb root@192.168.3.11:/home/root/
  • On the target, you can verify the bundle:
target$ rauc info phytec-qt5demo-bundle-phycore-r2-am335x-1.raucb

and get output similar to this:

rauc-Message: Reading bundle: phytec-qt5demo-bundle-phycore-r2-am335x-1.raucb
rauc-Message: Verifying bundle... 
Compatible:     'phycore-r2-am335x-1'
Version:        'r0'
Description:    'PHYTEC rauc bundle based on AM335x-PD19.1.0'
Build:          '20181210110005'
Hooks:          ''
3 Images:
(1)     phytec-qt5demo-image-phycore-r2-am335x-1.ubifs
        Slotclass: rootfs
        Checksum:  1b85f3a380f970f4e3aa640406f3cab9848febdc7f2897884a12de020c8a082b
        Size:      128894976
        Hooks:     
(2)     zImage-phycore-r2-am335x-1.bin.img
        Slotclass: kernel
        Checksum:  6d615338c776be130fdf7c936a1f758a5319fb6c6a62633c2c50e18fa37d0add
        Size:      7263456
        Hooks:     
(3)     am335x-phycore-nand-eeprom-rtc-spi-tmp.dtb.img
        Slotclass: dtb
        Checksum:  99e18db4610add53a3c25172ada03d786cdabe330684ddd06bc2bba73d43781a
        Size:      40943
        Hooks:     
0 Files
 
Certificate Chain:
 0 Subject: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH Development-1
   Issuer: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Developme
nt
   SPKI sha256: E2:47:5F:32:05:37:04:D4:8C:48:8D:A6:74:A8:21:2E:97:41:EE:88:74:B5:F4:65:
75:97:76:1D:FF:1D:7B:EE
 1 Subject: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Developm
ent
   Issuer: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Developme
nt
   SPKI sha256: AB:5C:DB:C6:0A:ED:A4:48:B9:40:AC:B1:48:06:AA:BA:92:09:83:8C:DC:6F:E1:5F:
B6:FB:0C:39:3C:3B:E6:A2
  • To check the current state of the system, run:
target$ rauc status

and get output similar to:

Compatible:  phycore-r2-am335x-1
Variant:     (null)
Booted from: system0
Activated:   rootfs.1
slot states:
  dtb.1: class=dtb, device=/dev/ubi0_4, type=ubivol, bootname=(null)
      state=inactive, description=, parent=rootfs.1, mountpoint=(none)
  kernel.1: class=kernel, device=/dev/ubi0_3, type=ubivol, bootname=(null)
      state=inactive, description=, parent=rootfs.1, mountpoint=(none)
  rootfs.0: class=rootfs, device=/dev/ubi0_2, type=ubifs, bootname=system0
      state=booted, description=, parent=(none), mountpoint=(none)
      boot status=bad
  kernel.0: class=kernel, device=/dev/ubi0_0, type=ubivol, bootname=(null)
      state=active, description=, parent=rootfs.0, mountpoint=(none)
  rootfs.1: class=rootfs, device=/dev/ubi0_5, type=ubifs, bootname=system1
      state=inactive, description=, parent=(none), mountpoint=(none)
      boot status=good
  dtb.0: class=dtb, device=/dev/ubi0_1, type=ubivol, bootname=(null)
      state=active, description=, parent=rootfs.0, mountpoint=(none)
  • To update the currently inactive system with the downloaded bundle, run:
target$ rauc install phytec-qt5demo-bundle-phycore-r2-am335x-1.raucb

and reboot afterwards:

target$ reboot

When you update from a USB stick, make sure to remove the stick after a successful update before reboot. If not, an atomatic update will be started after each boot

With a successful update, RAUC automatically switches the active system to the newly updated system. Now during reboot, RAUC counts the boot attempts of the kernel and if it fails more often than specified in the state framework of the system, RAUC switches back to the old system and marks the new system as bad. If the boot attempt to the kernel is successful, the new system is marked as good and now the old system can be updated with the same instructions. After two successful rauc install and reboot, both systems are updated.

Change the active Boot Slot

It is possible to switch the active system manually:

target$ rauc status mark-active other

Now after a reboot or power cycle, the kernel starts from the alternate system.

Use Case 1: Automatic Update from USB Flash Drive with RAUC

One of the most prominent use cases for RAUC might be an automatic update system from a USB flash drive. This use case is implemented in the BSP as a reference example. We combine only standard Linux mechanisms with RAUC to build the system. The kernel notifies udev when a device gets plugged into the USB port. We use a custom udev rule to trigger a systemd service when this event happens.

10-update-usb.rules udev rule:

KERNEL!="sd[a-z][0-9]", GOTO="media_by_label_auto_mount_end"
 
# Trigger systemd service
ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="update-usb@%k.service"
 
# Exit  
LABEL="media_by_label_auto_mount_end"

The service auto mounts the USB flash drive and notifies the application.

update-usb@.service systemd service file:

[Unit]
Description=usb media RAUC service
After=multi-user.target
Requires=rauc.service
 
[Service]
Type=oneshot
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket
ExecStartPre=/bin/mkdir -p /media/%I
ExecStartPre=/bin/mount -t auto /dev/%I /media/%I
ExecStart=/usr/bin/update_usb.sh %I
ExecStop=/bin/umount -l /media/%i
ExecStopPost=-/bin/rmdir /media/%I

In our reference implementation, we simply use a bash script for the application logic.

update_usb.sh update script:

#!/bin/sh
 
MOUNT=/media/$1
 
NUMRAUCM=$(find ${MOUNT}/*.raucb -maxdepth 0 | wc -l)
 
[ "$NUMRAUCM" -eq 0 ] && echo "${MOUNT}*.raucb not found" && exit
[ "$NUMRAUCM" -ne 1 ] && echo "more than one ${MOUNT}/*.raucb" && exit
 
rauc install $MOUNT/*.raucb
if [ "$?" -ne 0 ]; then
	echo "Failed to install RAUC bundle."
else
	echo "Update successful."
fi
exit $?

The update logic could be integrated into an application by using systemd's D-Bus API. RAUC also does not need to be called by its command line interface but can be integrated with D-Bus.

Use Case 2: Security measurement: downgrade barrier

As a second reference example, we will implement a security mechanism: a downgrade barrier. When you detect a security vulnerability on your system, you will fix it and update your system. The systems with the new software will now be secure again. If an attacker gets ahold of the old software update bundle, which has still a valid signature, the attacker might have the possibility to install the old software and still take advantage of the previously fixed security vulnerability. To prevent this from happening, you could revoke the update certificate for every single update and create a new one. This might be difficult to handle, depending on the environment. A simpler solution would be to allow updates only in one direction using a version check.

rauc_downgrade_barrier.sh in meta-yogurt:

#!/bin/sh
 
VERSION_FILE=/etc/rauc/downgrade_barrier_version
MANIFEST_FILE=${RAUC_UPDATE_SOURCE}/manifest.raucm
 
[ ! -f ${VERSION_FILE} ] && exit 1
[ ! -f ${MANIFEST_FILE} ] && exit 2
 
VERSION=`cat ${VERSION_FILE} | cut -d 'r' -f 2`
BUNDLE_VERSION=`grep "version" -rI ${MANIFEST_FILE} | cut -d 'r' -f 3`
 
# check from empty or unset variables
[ -z "${VERSION}" ] && exit 3
[ -z "${BUNDLE_VERSION}" ] && exit 4
 
# developer mode, allow all updates if version is r0
[ ${VERSION} -eq 0 ] && exit 0
 
# downgrade barrier
if [ ${VERSION} -gt ${BUNDLE_VERSION} ]; then
        echo "Downgrade barrier blocked rauc update! CODE5\n"
else
        exit 0
fi
exit 5

The script is installed on the target but it is not activated. You need to remove the developer mode line in the script to activate it.

How to setup RAUC for your Machine

On the phyCORE-AM335x Evaluation Kit, corresponding with the Yocto machine phycore-r2-am335x-1, RAUC support is already enabled and the instructions used in the previous chapters can be used out of the box. For other machines, this section describes how to enable RAUC support for your board.

First, you need to add the state framework configuration to the barebox device tree. Check out the BSP Customization chapter in the Yocto reference manual. You have to include the am335x-phytec-state.dtsi file to your barebox device tree by adding #include "am335x-phytec-state.dtsi" to the includes. Afterwards, rebuild the image.

Be aware that by adding the state framework configuration, the EEPROM is partly occupied and can no longer be used for user-specific purposes.

The following device tree snippet shows the state framework configuration used with the BSP. As you can see, the EEPROM is used as a backend for the state information. Next to the bootchooser setup it is also possible to store a MAC Address with the state framework in the EEPROM.

/ {
        aliases {
                am335x_phytec_mac_state = &am335x_phytec_mac_state;
                state = &am335x_phytec_boot_state;
        };
 
        am335x_phytec_mac_state: am335x_phytec_mac_state {
                magic = <0x3f45620e>;
                compatible = "barebox,state";
                backend-type = "raw";
                backend = <&backend_state_mac_eeprom>;
                backend-stridesize = <40>;
                keep-previous-content;
 
                #address-cells = <1>;
                #size-cells = <1>;
                mac0 {
                        reg = <0x0 0x6>;
                        type = "mac";
                };
                mac1 {
                        reg = <0x6 0x6>;
                        type = "mac";
                };
 
        };
 
        am335x_phytec_boot_state: am335x_phytec_boot_state {
                magic = <0x883b86a6>;
                compatible = "barebox,state";
                backend-type = "raw";
                backend = <&backend_state_update_eeprom>;
                backend-stridesize = <54>;
 
                #address-cells = <1>;
                #size-cells = <1>;
                bootstate {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        last_chosen {
                                reg = <0x0 0x4>;
                                type = "uint32";
                        };
                        system0 {
                                #address-cells = <1>;
                                #size-cells = <1>;
                                remaining_attempts {
                                        reg = <0x4 0x4>;
                                        type = "uint32";
                                        default = <3>;
                                };
                                priority {
                                        reg = <0x8 0x4>;
                                        type = "uint32";
                                        default = <21>;
                                };
                        };
                        system1 {
                                #address-cells = <1>;
                                #size-cells = <1>;
                                remaining_attempts {
                                        reg = <0x10 0x4>;
                                        type = "uint32";
                                        default = <3>;
                                };
                                priority {
                                        reg = <0x14 0x4>;
                                        type = "uint32";
                                        default = <20>;
                                };
                        };
                };
        };
};
 
&eeprom {
        status = "okay";
        partitions {
                compatible = "fixed-partitions";
                #size-cells = <1>;
                #address-cells = <1>;
                backend_state_mac_eeprom: state@0 {
                        reg = <0x000 0x100>;
                        label = "state-eeprom";
                };
                backend_state_update_eeprom: state@100 {
                        reg = <0x100 0x150>;
                        label = "update-eeprom";
                };
        };
};

The next steps do not require a rebuild of the image and can be performed on a running system. To be able to boot from two systems alternately, the bootchooser needs to be aware of the state framework configuration. For the second system, a different boot script is required. To fulfill these requirements, boot your board and stop the boot process in the barebox.

  • Create the NAND boot script for the second system with:
bootloader$ edit /env/boot/nand2

and insert the following to the file:

#!/bin/sh
 
[ ! -e /dev/nand0.root.ubi ] && ubiattach /dev/nand0.root
 
global.bootm.image="/dev/nand0.root.ubi.kernel2"
global.bootm.oftree="/dev/nand0.root.ubi.oftree2"
 
global.linux.bootargs.dyn.root="root=ubi0:root2 ubi.mtd=root rootfstype=ubifs"
  • Write the file by pressing CTRL-D and run:
bootloader$ saveenv

to save the environment.

  • Run the following commands to create the required bootchooser non-volatile environment variables:
bootloader$ nv bootchooser.state_prefix=state.bootstate
bootloader$ nv bootchooser.system0.boot=nand
bootloader$ nv bootchooser.system1.boot=nand2
bootloader$ nv bootchooser.targets="system0 system1"

To simplify the initial partitioning and update of the NAND flash, two script are used.

  • The /env/bin/create_nand_partitions script is used to format and partition the NAND flash. Create this script:
bootloader$ edit /env/bin/create_nand_partitions

and insert the following to the file (adapt the root filesystem sizes to the size of your NAND flash. Remember, the barebox, barebox-environment, kernel, and device tree use space too!):

echo "Create NAND partitions using rauc with backup system"
ubiformat -q -y /dev/nand0.root
ubiattach /dev/nand0.root
#Hold the following order or change the /dev/ubi0_X enumeration in /etc/rauc/system.conf
ubimkvol -t static /dev/nand0.root.ubi kernel 8M
ubimkvol -t static /dev/nand0.root.ubi oftree 1M
#For 512MB NANDs (otherwise other partition sizes)
ubimkvol -t dynamic /dev/nand0.root.ubi root 230M
ubimkvol -t static /dev/nand0.root.ubi kernel2 8M
ubimkvol -t static /dev/nand0.root.ubi oftree2 1M
ubimkvol -t dynamic /dev/nand0.root.ubi root2 230M
ubidetach /dev/nand0.root

Write the file by pressing CTRL-D and run:

bootloader$ saveenv

to save the environment.

  • The /env/bin/init_flash_from_tftp script is used to update the kernel, device tree, and root filesystem of both systems with images from network. To create it, use:
bootloader$ edit /env/bin/init_flash_from_tftp

and insert the follwing to the file:

echo "Initialize NAND flash for rauc from TFTP"
[ ! -e /dev/nand0.root.ubi ] && ubiattach /dev/nand0.root
ubiupdatevol /dev/nand0.root.ubi.kernel  /mnt/tftp/zImage
ubiupdatevol /dev/nand0.root.ubi.kernel2 /mnt/tftp/zImage
ubiupdatevol /dev/nand0.root.ubi.oftree  /mnt/tftp/oftree
ubiupdatevol /dev/nand0.root.ubi.oftree2 /mnt/tftp/oftree
# Update rootfs image name as needed
cp /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root
cp /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root2
ubidetach /dev/nand0.root

Write the file by pressing CTRL-D and run:

bootloader$ saveenv

to save the environment.

The NAND flash can be updated from different sources too. You can choose from one of the possibilities described in Updating the Software. Simply adapt the script and its name to the choosen source.

Troubleshooting NAND Flash Update

Updating from BSP-Yocto-AM335x-PD15.x.x or BSP-Yocto-phyCORE-AM335x-R2-PD16.1.x

Since BSP-Yocto-AM335x-PD16.2.0, the NAND Flash's partition layout has changed. Instead of having a separate Linux image and oftree partition, the images are now part of the root filesystem partition. Inside the root UBI, two new static volumes are created. This keeps the kernel and oftree more secure and protected from the wear leveling of the UBI. A barebox_backup partition was also introduced in the BSP-Yocto-AM335x-PD16.2.0 release. To update the BSP, use one of the following two ways:

  • Boot the new BSP from a boot source different from NAND and follow the update instructions in the previous sections.
  • Update the BSP using an older release. Update the MLO and the barebox with the barebox_update command, then delete the environment partition as described in the update sections above. Reboot the board from NAND and run the barebox_update command again for the barebox.bin to ensure that the new barebox_backup partition is being written. Continue updating the kernel, device tree, and root filesystem as described in the previous sections.

Updating from a PTXdist BSP

When updating the images on the NAND Flash from a PTXdist-based release (Linux Kernel 3.2) to a Yocto-based release, there might be an UBIFS issue coming up when mounting the root filesystem. The old Linux kernel had an issue with subpage write which required to set the VID header offset to 2048. This is not needed any more. Because of that, the UBI parameters changed which requires a different call:

bootloader$ ubiformat -y -f /dev/nand0.root -s 512
bootloader$ ubiattach /dev/nand0.root
bootloader$ ubimkvol /dev/nand0.root.ubi root 0
bootloader$ cp /mnt/disk/root.ubifs /dev/nand0.root.ubi.root

Device Tree (DT)

Introduction

The following text describes briefly the Device Tree and can be found in the Linux kernel (linux/Documentation/devicetree/usage-model.txt).

"The "Open Firmware Device Tree", or simply Device Tree (DT), is a data structure and language for describing hardware. More specifically, it is a description of hardware that is readable by an operating system so that the operating system doesn't need to hard code details of the machine.

Structurally, the DT is a tree or acyclic graph with named nodes, and nodes may have an arbitrary number of named properties encapsulating arbitrary data. A mechanism also exists to create arbitrary links from one node to another outside of the natural tree structure.

Conceptually, a common set of usage conventions, called 'bindings' is defined for how data should appear in the tree to describe typical hardware characteristics including data busses, interrupt lines, GPIO connections, and peripheral devices."

The kernel is a really good source for a DT introduction. An overview of the device tree data format can be found on the device tree usage page at devicetree.org:

http://devicetree.org/Device_Tree_Usage

PHYTEC AM335x BSP Device Tree Concept

The following sections explain some rules we have defined on how to set up device trees in first place for our AM335x SoC based boards.

Basic DT Structure

Basic DT Structure of PHYTEC AM335x Boards

The module includes file Modul .dtsi contains all devices which are mounted on the module, such as NAND Flash and RAM. Devices which come from the AM335x SoC but are just routed down to the carrier board are not part of the Module .dtsi, but are included in the Carrierboard .dtsi. The Board .dts includes the carrier board and module nodes. It also adds partition tables and enables all hardware configurable nodes of the carrier board or the module. I.e. the Board .dts shows the special characteristics of the board configuration. For example, there are phyCORE-AM335x SOMs which may or may not have an SPI NOR Flash mounted. Hence, the SPI NOR Flash is enabled (if available) in the Board .dts and not in the Module .dtsi.

To make development easier to start, we have also created a different device tree including files for the various module options. For example, there is already an am335x-phycore-som-eeprom.dtsi which has the EEPROM enabled but not the SPI NOR Flash and the RTC. So you can include the appropriate Module .dtsi to start directly with the development of the Carrierboard .dtsi.

Expansion Boards and Displays

Different expansion boards can be mounted on different carrier boards. Some carrier boards may have several connectors to support more than one expansion board at a time. This requires a separate device tree for every expansion board/carrier board combination.

DTS Structure of Expansion Boards

To facilitate the use of expansion boards, we created an Expansionboards .dtsi for every expansion board/carrier board/module combination. We then included all possible extensions to a board file but disabled them. To use an expansion board, it can be enabled in the Board .dts or from the bootloader.

Switching Expansion Boards and Displays

Disconnect all power before connecting an expansion board. After you plug the board in, the software support can be activated in the bootloader without recompiling and flashing the images.

Here is a simple example on how to switch from am335x-wega-peb-av-01 (HDMI Expansion Board) to am335x-phytec-lcd-018-peb-av-02 (Display Expansion Board) on the phyBOARD-Wega using the barebox bootloader.

The configuration for the currently selected expansion board am335x-wega-peb-av-01 can be found in /env/init/config-expansions.

#!/bin/sh
. /env/expansions/am335x-wega-peb-av-01

To switch to another expansion board, the file config-expansions in the barebox environment must be edited.

  • To switch to am335x-phytec-lcd-018-peb-av-02, modify the /env/init/config-expansions file. Then add or uncomment the text according to the expansion board used. For example, for the PEB-AV-02 on the phyBOARD-Wega:
#!/bin/sh
. /env/expansions/am335x-phytec-lcd-018-peb-av-02
config-expansions is called within each boot source script (/env/boot/*) and will be executed before every boot process. This will cause the barebox to modify the DT used before the boot process. Information on which DT nodes are necessary for the expansion board can be found in the expansion configuration files.

am335x-wega-peb-av-01:

of_fixup_status /hdmi
of_fixup_status /ocp/lcdc@0x4830e000

am335x-phytec-lcd-018-peb-av-02:

of_fixup_status /panel
of_fixup_status /backlight
of_fixup_status /ocp/lcdc@0x4830e000/
of_fixup_status /ocp/epwmss@48304000/
of_fixup_status /ocp/epwmss@48304000/ecap@48304100/
of_fixup_status /ocp/i2c@44e0b000/touchscreen@38/

of_fixup_status is a barebox command and will enable a given DT node.

Handle the Different Displays

If you have chosen a display as an expansion, you have to select the appropriate display timings in the device tree.

  • Look at the following lines at the end of config-expansions:
#7.0" display
#of_display_timings -S /panel/display-timings/ETM0700G0DH6
 
#5.7" display
#of_display_timings -S /panel/display-timings/ETMV570G2DHU
 
#4.3" display
#of_display_timings -S /panel/display-timings/ETM0430G0DH6
  • Uncomment the of_display_timings -S ... command for your screen size and save the file and environment.

Beside the display timings, you have to choose the right touchscreen type. Capacitive touchscreens are the standard touchscreens used with our boards. Thus, if you want to use a resistive touchscreen, you have to choose a modified board file in the /env/init/config-expansions. The board files for resistive touchscreens all have the suffix -res.

Example: If you have the am335x-phytec-lcd-018-peb-av-02 board, change the /env/init/config-expansions from:

#!/bin/sh
. /env/expansions/am335x-phytec-lcd-018-peb-av-02

to:

#!/bin/sh
 . /env/expansions/am335x-phytec-lcd-018-peb-av-02-res

First stage bootloader's DT Handling

The first stage bootloader (MLO) uses only a very small, simple device tree which also has most nodes deactivated by default. The MLO detects the boot device and activates this node only to load the barebox bootloader. The RAM setup is done at an early stage where no device tree support is available.

Bootloader's DT Modifications

The bootloader loads the device tree blob, a separate binary which includes the hardware description (section Accessing Peripherals). Then it will modify the memory node loaded at runtime. Thus, there is no need to handle different RAM sizes in the device tree. However, there should be always a memory node to ensure that the RAM size is set even if a different bootloader without this feature is used. For this purpose, a memory node dummy which sets the RAM size to the size of the RDK module's memory is added in the Module.dsti.

/* This is a dummy node. Will be set by a bootloader */
memory {
        device_type = "memory";
        reg = <0x80000000 0x20000000>; /* 512 MB */
};

The memory node is not the only node which is modified by the bootloader. Display nodes and nodes of expansion boards can be enabled (section Switching Expansion Boards and Displays), whereas the partition table in the kernel device tree is set by the bootloader. Because of that, it is not possible to use our device trees without modifications with another bootloader, then the barebox bootloader from our unified BSP.

The bootloader itself also contains a device tree in the bootloader image which differs from the one used by the kernel. The barebox loads Linux, the kernel image, and a second device tree blob file.

The unified BSP contains device tree (DT) sources for the barebox bootloader and for the Linux kernel. The bootloader DT holds only the absolutely necessary hardware description for the basic board bring-up and is also using a different DT model. Make sure you are working with the right DT.

The following boot script for booting from SD card is an example for the barebox configuration:

  • Display the script with:
bootloader$ cat env/boot/mmc
#!/bin/sh

 
global.bootm.image=/mnt/mmc0.0/zImage                                         # kernel image
global.bootm.oftree=/mnt/mmc0.0/oftree                                        # DTB
global.linux.bootargs.dyn.root="root=/dev/mmcblk0p2 rootflags='data=journal'" # kernel bootargs

Accessing Peripherals

The following sections provide an overview of the supported hardware components and their corresponding operating system drivers. Further changes can be ported upon customer request.

To find out which boards and modules are supported by the release of PHYTEC’s AM335x unified BSP described herein, visit our web page at http://www.phytec.de/produkte/software/yocto/phytec-unified-yocto-bsp-releases/ and click the corresponding BSP release. Now you can find all hardware supported in the columns "Hardware Article Number" and the correct machine name in the corresponding cell under "Machine Name".

To achieve maximum software re-use, the Linux kernel offers a sophisticated infrastructure, layering software components into board-specific parts. The BSP tries to modularize the kit features as far as possible, which means that when a customized baseboard or even a customer-specific module is developed, most of the software support can be re-used without error-prone copy-and-paste. The kernel code corresponding to the supported hardware can be found in the device trees (DT):

linux/arch/arm/boot/dts/*.dts[i]

In fact, software re-use is one of the most important features of the Linux kernel and especially of the ARM port, which always had to fight with an insane number of possibilities of the System-on-Chip CPUs. The whole board specific hardware is described in DTs and is not part of the kernel image itself. The hardware description is in its own separate binary, called Device Tree Blob (DTB) (section Bootloader's DT Modifications).

Please also read section PHYTEC AM335x BSP Device Tree Concept to get an understanding of our unified AM335x BSP device tree model. The following sections provide an overview of the supported hardware components and their operating system drivers on the AM335x platform.

AM335x Pin Muxing

The AM335x SoC contains many peripheral interfaces. In order to reduce package size and lower overall system cost while maintaining maximum functionality, many of the AM335x terminals can multiplex up to eight signal functions. Although there are many combinations of pin multiplexing that are possible, only a certain number of sets, called IO sets, are valid due to timing limitations. These valid IO sets were carefully chosen to provide many possible application scenarios for the user.

The pin muxing tool helps developers find the correct IO sets for their application:

http://www.ti.com/tool/pinmuxtool

Look at the following datasheet for a detailed pin configuration description:

http://www.ti.com/lit/ds/symlink/am3359.pdf

AM335x's pin register addresses can be found in the AM335x Technical Reference Manual, Chapter 9 "Control Module":

https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf

The IO set configuration, also called muxing, is done in the Device Tree. The driver pinctrl-single reads the DT's node "pinctrl-single,pins" and does the appropriate pin muxing.

The following is an example of the pin muxing of the UART0 device in am335x-pcm-953.dtsi:

&am33xx_pinmux {
        uart0_pins: pinmux_uart0 {
                pinctrl-single,pins = <
			AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
			AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
                >;
        };
};

All pin configuration nodes have to be a declared in the am33xx_pinmux node. The pin configuration for the pinctrl-single nodes is specified by combined pairs of pinctrl register offset and value within pinctrl-single,pins. Only the bits specified in pinctrl-single,function-mask are updated.

AM335x's pinctrl register base address is 0x44e10800 (am33xx.dtsi).

More information about the pinctrl-single driver binding can be found in the kernel documentation:

linux/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt

Serial TTYs

The AM335x SoC provides up to 6 so-called UART units. PHYTEC boards support different numbers of these UART units.

ttyO0 is always used as the standard console output.

  • From the command line prompt of Linux userspace, you can easily check the availability of other UART interfaces with:
target$ echo "test" > /dev/ttyO1

Be sure that the baud rate is set correctly on both the host and target.

In order to get the currently configured baud rate, you can use the command stty on the target. The following example shows how to copy all serial settings from ttyO0 (the standard console on most AM335x boards) to ttyO1.

  • First get the current parameters:
target$ stty -F /dev/ttyO0 -g
5500:5:1cb2:a3b:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
  • Now use the output from the stty command above as an argument for the next command:
target$ stty -F /dev/ttyO0 -g
5500:5:1cb2:a3b:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

Here is an example from am335x-pcm-953.dtsi:

/* UARTs */
&am33xx_pinmux {
	uart0_pins: pinmux_uart0 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
			AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
		>;
	};
 
	uart1_pins: pinmux_uart1 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart1_rxd.uart1_rxd */
			AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart1_txd.uart1_txd */
			AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0)		/* uart1_ctsn.uart1_ctsn */
			AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart1_rtsn.uart1_rtsn */
		>;
	};
 
	uart2_pins: pinmux_uart2 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE1)	/* mii1_tx_clk.uart2_rxd */
			AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLDOWN | MUX_MODE1)	/* mii1_rx_clk.uart2_txd */
		>;
	};
 
	uart3_pins: pinmux_uart3 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1)	/* mii1_rxd3.uart3_rxd */
			AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxd2.uart3_txd */
		>;
	};
};
 
&uart0 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart0_pins>;
	status = "okay";
};
 
&uart1 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart1_pins>;
};
 
&uart2 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart2_pins>;
	status = "okay";
};
 
&uart3 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart3_pins>;
	status = "okay";
};

RS-485

The phyBOARD-Regor provides one RS-485 interface derived from UART1. The following code snippet can be found in the am335x-regor.dtsi:

/* RS485 - UART1 */
&am33xx_pinmux {
	uart1_rs485_pins: pinmux_uart1_rs485_pins {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart1_rxd.uart1_rxd */
			AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart1_txd.uart1_txd */
			AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE7)    /* uart1_rtsn.gpio0_13 */
		>;
	};
};
 
&uart1 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart1_rs485_pins>;
	status = "okay";
	rs485-rts-active-high;
	rts-gpio = <&gpio0 13 GPIO_ACTIVE_HIGH>;
	rs485-rts-delay = <0 0>;
	linux,rs485-enabled-at-boot-time;
};

For easy testing, the RS-485 port must be configured.

  • Execute:
target$ stty -F /dev/ttyO1 -echo -echoe -echok -echoctl -echoke 115200

Now, you can apply the echo and cat command to /dev/ttyO1.

Network

The Ethernet features provided by our modules and boards vary (e.g.: 1 x 10/100 Mbit, 2 x 10/100 Mbit, gigabit or both). However, all interfaces offer a standard Linux network port which can be programmed using the BSD socket interface. The whole network configuration is handled by the systemd-networkd daemon. The relevant configuration files can be found on the target in /lib/systemd/network/ and also in the BSP in meta-yogurt/recipes-core/systemd/systemd/.

IP addresses can be configured within *.network files. The default IP addresses and netmasks for eth0 and eth1 are:

eth0: 192.168.3.11/24
eth1: 192.168.4.11/24

In our configuration, both interfaces are handled with separate MAC addresses. Thus, both interfaces have to be connected to different subnets. A different configuration, like switch mode, is also possible. MAC addresses get flashed by the semiconductor with a predefined range of numbers. If these don't fit into existing addresses ranges of systems or if a specific address is desired, it is possible to have the bootloader to overwrite them during boot:

bootloader$ am335x_phytec_mac_state.mac0=e8:eb:11:28:85:16
bootloader$ am335x_phytec_mac_state.mac0=e8:eb:11:28:85:17
bootloader$ state -s am335x_phytec_mac_state

This feature in our BSP is only available with EEPROMs, but can also be configured with other storage medias.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The state framework is enabled by default but will not overwrite existing data on EEPROMs. To use the mac state feature, the eeprom has to be cleared.

The DT Ethernet setup is mostly split into two files, the module DT and the board specific DT.

Example: RDK phyCORE- AM335x

Module DT, am335x-phycore-som.dtsi:

/* Ethernet */
&am33xx_pinmux {
	ethernet0_pins: pinmux_ethernet0 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_crs.rmii1_crs_dv */
			AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxerr.rmii1_rxerr */
			AM33XX_IOPAD(0x914, PIN_OUTPUT | MUX_MODE1)		/* mii1_txen.rmii1_txen */
			AM33XX_IOPAD(0x924, PIN_OUTPUT | MUX_MODE1)		/* mii1_txd1.rmii1_txd1 */
			AM33XX_IOPAD(0x928, PIN_OUTPUT | MUX_MODE1)		/* mii1_txd0.rmii1_txd0 */
			AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxd1.rmii1_rxd1 */
			AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxd0.rmii1_rxd0 */
			AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0)	/* rmii1_refclk.rmii1_refclk */
		>;
	};
 
	mdio_pins: pinmux_mdio {
		pinctrl-single,pins = <
			/* MDIO */
			AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
			AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
		>;
	};
};
 
&cpsw_emac0 {
	phy-handle = <&phy0>;
	phy-mode = "rmii";
	dual_emac_res_vlan = <1>;
};
 
&davinci_mdio {
	pinctrl-names = "default";
	pinctrl-0 = <&mdio_pins>;
	status = "okay";
 
	phy0: ethernet-phy@0 {
		reg = <0>;
	};
};
 
&mac {
	slaves = <1>;
	pinctrl-names = "default";
	pinctrl-0 = <ðernet0_pins>;
	status = "okay";
};
 
&phy_sel {
	rmii-clock-ext;
};

Board specific DT, am335x-pcm-953.dtsi:

/* Ethernet */
&am33xx_pinmux {
	ethernet1_pins: pinmux_ethernet1 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a0.rgmii2_tctl */
			AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a1.rgmii2_rctl */
			AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a2.rgmii2_td3 */
			AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a3.rgmii2_td2 */
			AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a4.rgmii2_td1 */
			AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a5.rgmii2_td0 */
			AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a6.rgmii2_tclk */
			AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a7.rgmii2_rclk */
			AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a8.rgmii2_rd3 */
			AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a9.rgmii2_rd2 */
			AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a10.rgmii2_rd1 */
			AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a11.rgmii2_rd0 */
		>;
	};
};
 
&cpsw_emac1 {
	phy-handle = <&phy1>;
	phy-mode = "rgmii-id";
	dual_emac_res_vlan = <2>;
	status = "okay";
};
 
&davinci_mdio {
	phy1: ethernet-phy@2 {
		reg = <2>;
	};
};
 
&mac {
	slaves = <2>;
	pinctrl-names = "default";
	pinctrl-0 = <ðernet0_pins ðernet1_pins>;
	dual_emac;
};

CAN Bus

The phyCORE-AM335x provides a Controller Area Network (CAN) interface, which is supported by drivers using the proposed Linux standard CAN framework SocketCAN. Using this framework, CAN interfaces can be programmed with the BSD socket API. The CAN bus offers a low-bandwidth, prioritized message fieldbus for serial communication between microcontrollers. Unfortunately, CAN was not designed with the ISO/OSI layer model in mind, so most CAN APIs available throughout the industry do not support a clean separation between the different logical protocol layers.

The SocketCAN framework for Linux extends the BSD socket API concept towards CAN bus. Because of that, using this framework, the CAN interfaces can be programmed with the BSD socket API and behaves like an ordinary Linux network device, with some additional features special to CAN.

  • To get the information on can0 (which represents AM335x’s CAN1) such as bit rate and error counters, type:
target$  ip -s addr show can0

The information for can0 will look like:

target$ ip -s addr show can0
2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN group default ql
en 10
    link/can 
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0

The CAN configuration is done in the systemd configuration file /lib/systemd/system/can0.service. For a persistent change of the default bitrates, change the configuration in the BSP under meta-yogurt/recipes-core/systemd/systemd/can0.service. For temporarily modifications, change the systemd file in the root filesystem instead and rebuild the root filesystem.

[Unit]
Description=can0 interface setup
 
[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/sbin/ip link set can0 up type can bitrate 500000
ExecStop=/sbin/ip link set can0 down
 
[Install]
WantedBy=basic.target

The can0.service is started after boot by default. You can start and stop it with:

target$ systemctl stop can0.service
target$ systemctl start can0.service

You can send messages with cansend or receive messages with candump:

target$ cansend can0 123#45.67
target$ candump -dex can0

See cansend --help and candump --help messages for further information on options and usage.

To generate random CAN traffic for testing purpose, use cangen:

target$ cangen -v can0

The corresponding kernel part can be found within the board specific DT, for example am335x-pcm-953.dtsi:

/* CAN */
&am33xx_pinmux {
	dcan1_pins: pinmux_dcan1 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x980, PIN_OUTPUT_PULLUP | MUX_MODE2)	/* uart1_rxd.dcan1_tx_mux2 */
			AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE2)	/* uart1_txd.dcan1_rx_mux2 */
		>;
	};
};
 
&dcan1 {
	pinctrl-names = "default";
	pinctrl-0 = <&dcan1_pins>;
	status = "okay";
};

CAN, in combination with an 25 MHz oscillator, can't produce all bit timings. For 20 and 800 kBit/s, an 24 Mhz oscillator is necessary.

MMC/SD Card

All AM335x kits support a slot for Secure Digital Cards and Multi Media Cards to be used as general purpose block devices. These devices can be used in the same way as any other block device.

This kind of devices are hot pluggable. Nevertheless, you must make sure not to unplug the device while it is still mounted. This may result in data loss!

After inserting an MMC/SD card, the kernel will generate new device nodes in /dev. The full device can be reached via its /dev/mmcblk0 device node. MMC/SD card partitions will show up in the following way:

/dev/mmcblk0p<Y>

<Y> counts as the partition number starting from 1 to the max. count of partitions on this device. The partitions can be formatted with any kind of file system and also handled in a standard manner. The mount and umount command work as expected.

These partition device nodes will only be available if the card contains a valid partition table (”hard disk” like handling). If it does not contain a valid table, the whole device can be used as a file system (”floppy” like handling). In this case, /dev/mmcblk0 must be used for formatting and mounting.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The cards are always mounted as being writable.

DT configuration for the MMC/SD interface:

/* MMC */
&am33xx_pinmux {
	mmc1_pins: pinmux_mmc1_pins {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat3.mmc0_dat3 */
			AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat2.mmc0_dat2 */
			AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat1.mmc0_dat1 */
			AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat0.mmc0_dat0 */
			AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_clk.mmc0_clk */
			AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_cmd.mmc0_cmd */
			AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE7)	/* spi0_cs1.mmc0_sdcd */
		>;
	};
};
 
&mmc1 {
	vmmc-supply = <&vcc3v3>;
	bus-width = <4>;
	pinctrl-names = "default";
	pinctrl-0 = <&mmc1_pins>;
	cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
	status = "okay";
};

NAND Flash

PHYTEC AM335x modules are equipped with raw NAND memory, which is used as media for storing Linux, DTB, and root filesystem including applications and their data files. The NAND Flash is connected to the GPMC interface of the AM335x. The NAND flash type and size is automatically being detected via the Open NAND Flash Interface (ONFI) during boot.

This type of media is managed by the UBI file system. This file system uses compression and decompression on the fly to increase the quantity of data stored. The partitions of a NAND flash are defined in the barebox bootloader. It writes the partitions into the kernel device tree. Thus, changing the partitions has to be done either in the barebox DT or in the barebox environment. Modifying the partitions during runtime in the barebox environment is described in section Changing MTD Partitions.

Adding new partitions can be done by creating a new partition node in the Module.dtsi of the barebox. The property label defines the name of the partition and the reg value the offset and size of a partition. Do not forget to update all following partitions when adding or changing a partition's size. The kernel image and device tree are stored in the first 9 MB of the root partition (see section "Updating NAND Flash from SD Card").

The partitions are defined in the DT, e.g. am335x-phytec-phycore-som.dtsi in the barebox:

&nandflash {
        partition@0 {
                label = "xload";
                reg = <0x0 0x20000>;
        };
 
        partition@20000 {
                label = "xload_backup1";
                reg = <0x20000 0x20000>;
        };
 
        partition@40000 {
                label = "xload_backup2";
                reg = <0x40000 0x20000>;
        };
 
        partition@60000 {
                label = "xload_backup3";
                reg = <0x60000 0x20000>;
        };
 
        partition@80000 {
                label = "barebox";
                reg = <0x80000 0x80000>;
        };
 
        partition@100000 {
               label = "barebox_backup";
               reg = <0x100000 0x80000>;
        };
 
        partition@180000 {
                label = "bareboxenv";
                reg = <0x180000 0x40000>;
        };
 
        partition@1C0000 {
                label = "root";
                /*
                 * setting size to 0x0 here, size will be extended to
                 * end of nand flash while booting.
                 */
                reg = <0x1C0000 0x0>;
        };
};

eMMC

PHYTEC phyCORE-AM335x modules can be populated with an eMMC memory chip as the main storage instead of the NAND Flash. eMMC devices contain raw MLC memory cells (see section Enable pseudo-SLC Mode) combined with a memory controller that handles ECC and wear leveling. They are connected via an MMC/SD interface to the AM335x and are represented as block devices in the Linux kernel like SD cards, flash drives, or hard disks.

The electric and protocol specification is provided by JEDEC (https://www.jedec.org/standards-documents/technology-focus-areas/flash-memory-ssds-ufs-emmc/e-mmc). The eMMC manufacturer's datasheet is relatively short and meant to be read together with the supported version of the JEDEC eMMC standard.

DT configuration for the eMMC interface:

/* EMMC */
&am33xx_pinmux {
	emmc_pins: pinmux_emmc_pins {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
			AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
			AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
			AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
			AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
			AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
			AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
			AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
			AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
			AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
		>;
	};
 
};
 
&mmc2 {
	pinctrl-names = "default";
	pinctrl-0 = <&emmc_pins>;
	vmmc-supply = <&vmmc_reg>;
	bus-width = <8>;
	ti,non-removable;
	status = "disabled";
};

Extended CSD Register

eMMC devices have an extensive amount of extra information and settings that are available via the Extended CSD registers. For a detailed list of the registers, see the manufacturer datasheets and the JEDEC standard.

  • In the Linux userspace, you can query the registers:
target$ mmc extcsd read /dev/mmcblk1

You will see:

=============================================
  Extended CSD rev 1.7 (MMC 5.0)
=============================================

Card Supported Command sets [S_CMD_SET: 0x01]
[...]

Enable Background Operations (BKOPS)

In contrast to raw NAND flashs, an eMMC device contains a Flash Transfer Layer (FTL) that handles the wear leveling, block management, and ECC of the raw MLC cells. This requires some maintenance tasks. For example, erasing non-used blocks that are performed regularly. These tasks are called Background Operations (BKOPS).

In the default case (depending on the chip), the background operations are not executed periodically, which impacts the worst-case read and write latency. Therefore, the JEDEC Standard specifies a method that the host can issue BKOPS manually. See the JEDEC Standard chapter Background Operations and the description of registers BKOPS_EN (Reg: 163) and BKOPS_START (Reg: 164) in the eMMC datasheet for more details.

Meaning of Register BKOPS_EN (Reg: 163) Bit MANUAL_EN (Bit 0):

  • Value 0: The host does not support manual trigger of BKOPS. Device write performance suffers.
  • Value 1: The host does support manual trigger of BKOPS. It will issue BKOPS from time to time when it does not need the device.

The mechanism to issue background operations has been implemented in the Linux kernel since v3.7. You only have to enable BKOPS_EN on the eMMC device (see below for details). The JEDEC standard v5.1 introduces a new automatic BKOPS feature. It frees the host to trigger the background operations regularly as the device starts BKOPS itself when it is idle (see the description of bit AUTO_EN in register BKOPS_EN(Reg: 163)).

eMMC chips deployed by PHYTEC currently do not support the new standard v5.1. The Linux kernel and userspace tool mmc do not support the feature either.

  • To check whether BKOPS_EN is set, execute:
target$ mmc extcsd read /dev/mmcblk1 | grep BKOPS_EN

The output will be, for example:

Enable background operations handshake [BKOPS_EN]: 0x01

Here BKOPS_EN is enabled. The host will issue background operations from time to time.

There is also a kernel boot message showing if BKOPS_EN is not set:

mmc1: MAN_BKOPS_EN bit is not set
  • To set the BKOPS_EN bit, execute:
target$ mmc bkops enable /dev/mmcblk1
  • To ensure that the new setting is taken over and the kernel triggers BKOPS by itself, shut down the system:
target$ poweroff

and perform a power cycle.

The BKOPS_EN bit is one-time-programmable only. It cannot be reversed.

Enable pseudo-SLC Mode

eMMC devices use MLC memory cells (https://en.wikipedia.org/wiki/Multi-level_cell) to store the data. Compared with SLC memory cells used in NAND flashes, MLC memory cells have a lower reliability and a higher error rate at lower costs.

If you prefer reliability over storage capacity, you can enable the pseudo-SLC mode or SLC mode. The method used here employs the enhanced attribute, described in the JEDEC standard, which can be set for continuous regions of the device. The JEDEC standard does not specify the implementation details and the guarantees of the enhanced attribute. This is left to the chipmaker. For the Micron chips, the enhanced attribute increases the reliability but also halves the capacity.

When enabling the enhanced attribute on the device, all data will be lost!

The following sequence shows how to enable the enhanced attribute.

  • First, obtain the current size of the eMMC device:
target$ parted -m /dev/mmcblk1 unit B print

You will receive:

BYT;
/dev/mmcblk1:3850371072B:sd/mmc:512:512:msdos:MMC Q2J54A:;
1:4194304B:25165823B:20971520B:fat16::boot, lba;
2:25165824B:185224191B:160058368B:ext4::;

As you can see, this device has 3850371072 Byte = 3672.0 MiB.

  • To get the maximum size of the device after pseudo-SLC is enabled, use:
target$ mmc extcsd read /dev/mmcblk1 | grep ENH_SIZE_MULT -A 1

which shows, for example:

Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x0000e5
 i.e. 1875968 KiB
--
Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x000000
 i.e. 0 KiB

Here, the maximum size is 1875968 KiB = 1789 MiB.

  • Now, you can set enhanced attribute for the whole device, e.g. 1875968 KiB, by typing:
target$ mmc enh_area set -y 0 1875968 /dev/mmcblk1

You will get:

Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x0000e5
 i.e. 1875968 KiB
Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x0000e5
 i.e. 1875968 KiB
Done setting ENH_USR area on /dev/mmcblk1
setting OTP PARTITION_SETTING_COMPLETED!
Setting OTP PARTITION_SETTING_COMPLETED on /dev/mmcblk1 SUCCESS
Device power cycle needed for settings to take effect.
Confirm that PARTITION_SETTING_COMPLETED bit is set using 'extcsd read' after power cycle
  • To ensure that the new setting used, shut down the system:
target$ poweroff

and perform a power cycle.

PHYTEC recommends verifying the settings now.

  • First, check the value of ENH_SIZE_MULT which must be 1847296 KiB:
targe$ mmc extcsd read /dev/mmcblk1 | grep ENH_SIZE_MULT -A 1
You should receive:
Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x0000e5
 i.e. 1875968 KiB
--
Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x0000e5
 i.e. 1875968 KiB
  • Finally, check the size of the device. In this example, it should be 1891631104 Byte = 1804.0 MiB:

target$ parted -m /dev/mmcblk1 unit B print
BYT;
/dev/mmcblk1:3850371072B:sd/mmc:512:512:msdos:MMC Q2J54A:;
  • Now you can flash your new image.

Further reference: https://www.micron.com/support/faqs (Products -> NAND Flash -> eMMC -> "What are the enhanced technology features mentioned in JEDEC specification, and what are the benefits?")

Reliable Write

There are two different Reliable Write options:

  • Reliable Write option for a whole eMMC device/partition
  • Reliable Write for single write transactions

Do not confuse eMMC partitions with partitions of a DOS MBR, or GPT partition table (see previous section).

The first Reliable Write option can be enable with the mmc tool:

target$ mmc --help
[...] 
mmc write_reliability set <-y|-n> <partition> <device>

The second Reliable Write option is the configuration bit Reliable Write Request parameter (bit 31) in command CMD23. It has been used in the kernel since v3.0 by file systems (i.e.ext4 for the journal) and user space applications such as fdiskfor the partition table. In the Linux kernel source code, it is handled via flag REQ_META.

Conclusion: ext4 file system with mount option data=journal should be safe against power cuts. The file system check can recover the file system after a power failure, but data that was written just before the power cut may be lost. At a minimum, a consistent state of the file system can be recovered. To ensure data consistency for the files of an application, the system functions fdatasync, or fsync should be used in the application.

Erase the Device

It is possible to erase the eMMC device directly rather than overwriting it with zeros. The eMMC block management algorithm will erase the underlying MLC memory cells or mark these blocks as discard. The data on the device is lost and will be read back as zeros.

  • After booting from SD card, execute:
target$ blkdiscard --secure /dev/mmcblk1

The option --secure ensures that the command waits until the eMMC device has erased all blocks.

'dd if=/dev/zero of=/dev/mmcblk1 also destroys all information on the device, but is bad for wear leveling and takes much longer!

For raw NAND flashes, the same could be achieved with the command flash_erase.

GPIOs

PHYTEC boards often have a set of pins especially dedicated as user I/Os. These pins are connected directly to AM335x pins. The processor has organized its GPIOs into four chips (gpiochip0 – gpiochip3) of 32 GPIO lines each. Pins connected directly to the AM335x are muxed as GPIOs and are directly usable in Linux userspace.

By contrast, the Linux kernel uses a single integer to enumerate all available GPIOs in the system. The formula to calculate the right number:

Linux GPIO number: <N> = <X> * 32 + <Y>

Accessing GPIOs from user space will be done using the libgpiod. It provides a library and tools for interacting with the linux GPIO character device. Examples of the usage for some of the tools:

  • Detecting the gpiochips on the chip:
target$ gpiodetect 
gpiochip0 [gpio] (32 lines) 
gpiochip1 [gpio] (32 lines) 
gpiochip2 [gpio] (32 lines) 
gpiochip3 [gpio] (32 lines)
  • Show detailed information about the gpiochips. Like their names, consumers, direction, active state, and additional flags:
target$ gpioinfo gpiochip0
  • Read the value of a gpio (e.g gpio 20 from chip0):
target$ gpioget gpiochip0 20
  • Set value of gpio 20 on chip0 to 0 and exit tool:
target$ gpioset --mode=exit gpiochip0 20=0

Help text of gpioset shows possible options:

# gpioset --help
Usage: gpioset [OPTIONS]  = = ...
Set GPIO line values of a GPIO chip
Options:
  -h, --help:           display this message and exit
  -v, --version:        display the version and exit
  -l, --active-low:     set the line active state to low
  -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):
                tell the program what to do after setting values
  -s, --sec=SEC:        specify the number of seconds to wait (only valid for --mode=time)
  -u, --usec=USEC:      specify the number of microseconds to wait (only valid for --mode=time)
  -b, --background:     after setting values: detach from the controlling terminal
 
Modes:
  exit:         set values and exit immediately
  wait:         set values and wait for user to press ENTER
  time:         set values and sleep for a specified amount of time
  signal:       set values and wait for SIGINT or SIGTERM

Some of the user IOs are used for special internal functions on the carrier boards (e.g. GPIO1_8 and GPIO1_9 on the PCM-953 CB). Before using a user IO, refer to the schematic or the hardware manual of your board to ensure that it is not already in use. Otherwise, do not touch them as this may cause a CB malfunction.

Keys

With gpio-keys, the Linux kernel can interpret GPIO signals as virtual keyboard events. Some carrier boards have buttons, which can be used with the gpio-keys driver. By pushing a button, an interrupt is triggered which causes the system to handle the corresponding keyboard event.

  • To display the key events in ASCII format, use evtest and select the correct event device:
target$ evtest /dev/input/event1
  • Listing the device with cat will print the raw output:
target$ cat /dev/input/event1

GPIO-Keys configuration in am335x-pcm-953.dtsi:

        user_buttons: user_buttons {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                pinctrl-0 = <&user_buttons_pins>;
 
                button@0 {
                        label = "home";
                        linux,code = <KEY_HOME>;
                        gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
                        wakeup-source;
                };
 
                button@1 {
                        label = "menu";
                        linux,code = <KEY_MENU>;
                        gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
                        wakeup-source;
                };
 
        };
};
 
&am33xx_pinmux {
        user_buttons_pins: pinmux_user_buttons {
                pinctrl-single,pins = <
                        AM33XX_IOPAD(0x9e4, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* emu0.gpio3_7 */
                        AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLDOWN | MUX_MODE7)     /* emu1.gpio3_8 */
                >;
        };

LEDs

If the LEDs are connected to GPIOs, you have the possibility to access them by using a special LED driver interface. All LEDs will be accessible through the /sys/class/leds/ directory, where they appear with their DT label. Several attributes such as the maximum brightness (max_brightness) or the current brightness (brightness), which can be every positive number less then or equal to the maximum brightness, are assigned to each LED. Since most LEDs do not support hardware brightness, they will be turned on by all non-zero brightness settings.

Here is a simple example for the PCM-953 CB:

  • To list all LEDs available, type:
target$ ls /sys/class/leds

which will result in:

user-led0 user-led1
  • To toogle the LEDs, use:
target$ echo 255 > /sys/class/leds/user-led0/brightness

to turn it ON, and:

target$ echo 0 > /sys/class/leds/user-led0/brightness

to turn it OFF.

User I/O configuration in am335x-pcm-953.dtsi:

        /* User IO */
        user_leds: user_leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
                pinctrl-0 = <&user_leds_pins>;
 
                user-led0 {
                        gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "gpio";
                        default-state = "on";
                };
 
                user-led1 {
                        gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
                        linux,default-trigger = "gpio";
                        default-state = "on";
                };
        };
...
        user_leds_pins: pinmux_user_leds {
                pinctrl-single,pins = <
                        AM33XX_IOPAD(0x880, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_csn1.gpio1_30 */
                        AM33XX_IOPAD(0x884, PIN_OUTPUT_PULLDOWN | MUX_MODE7)    /* gpmc_csn2.gpio1_31 */
                >;
        };

User LEDs on PCM-953 with a PCM-062 module are set in the file am335x-pcm-953-emmc.dtsi due to pin conflict.

SPI Master

Most PHYTEC boards are equipped with a NOR Flash which connects to the AM335x's McSPI interface. The NOR Flash is suitable for booting (section Booting from SPI NOR Flash). From Linux userspace, the NOR Flash partitions start with dev/mtdblock0. There are currently five partitions: barebox, barebox-environment, oftree, MLO, and kernel.

Please note that there is no root file system partition.

The partitions of an SPI Flash are defined in the barebox bootloader. It passes the partitions to the kernel device tree. Thus, changing the partitions has to be done either in the barebox DT or in the barebox environment. To modify the partitions during runtime in the barebox environment, see section Changing MTD Partitions.

Adding new partitions can be done by creating a new partition node in the Module.dts. The property label defines the name of the partition and the reg value the offset and size of a partition. Do not forget to update all following partitions when adding or changing a partition's size. The serial_flash node is defined inside of the SPI master node in the module DTs. The SPI node contains all devices connected to this SPI bus which is, in this case, only the SPI NOR Flash.

Definition of the SPI master node, e.g. in am335x-phycore-som.dtsi:

/* SPI Busses */
&am33xx_pinmux {
        spi0_pins: pinmux_spi0 {
                pinctrl-single,pins = <
                        AM33XX_IOPAD(0x950, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* spi0_clk.spi0_clk */
                        AM33XX_IOPAD(0x954, PIN_INPUT_PULLDOWN | MUX_MODE0)     /* spi0_d0.spi0_d0 */
                        AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)       /* spi0_d1.spi0_d1 */
                        AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE0)       /* spi0_cs0.spi0_cs0 */
                >;
        };
};
 
&spi0 {
        pinctrl-names = "default";
        pinctrl-0 = <&spi0_pins>;
        status = "okay";
 
        serial_flash: m25p80@0 {
                compatible = "jedec,spi-nor";
                spi-max-frequency = <48000000>;
                reg = <0x0>;
                m25p,fast-read;
                status = "disabled";
                #address-cells = <1>;
                #size-cells = <1>;
        };
};

I²C Bus

The AM335x contains three multimaster fast-mode I²C modules called I2C0, I2C1, and I2C2. This chapter will describe the basic device usage and its DT representation of some of the I²C devices integrated on our RDK boards.

General I²C bus configuration (e.g. am335x-phycore-som.dtsi):

/* I2C Busses */
&am33xx_pinmux {
	i2c0_pins: pinmux_i2c0 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x988, PIN_INPUT | MUX_MODE0)	/* i2c0_sda.i2c0_sda */
			AM33XX_IOPAD(0x98c, PIN_INPUT | MUX_MODE0)	/* i2c0_scl.i2c0_scl */
		>;
	};
};
 
&i2c0 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c0_pins>;
        clock-frequency = <400000>;
        status = "okay";
        /* ... */
};

EEPROM

It is possible to read and write to the device directly in /sys/class/i2c-adapter/i2c-0/0-0052/eeprom

  • E.g. to read and print the first 1024 bytes of the EEPROM as hex number execute:
target$ dd if=/sys/class/i2c-adapter/i2c-0/0-0052/eeprom bs=1 count=1024 | od -x
  • E.g. to fill the device with zeros use:
target$ dd if=/dev/zero of=/sys/class/i2c-adapter/i2c-0/0-0052/eeprom bs=4096 count=1

This operation takes some time because the EEPROM is relatively slow.

DT representation, e.g. in am335x-phycore-som.dtsi:

&i2c0 {
        i2c_eeprom: eeprom@52 {
                compatible = "atmel,24c32";
                pagesize = <32>;
                reg = <0x52>;
                status = "disabled";
        };
};
State Framework

The state framework can handle data in media and deliver them to the bootloader or kernel. To list all states and their media devices, run:

bootloader$ state
am335x_phytec_mac_state (backend: raw, path: /dev/eeprom0.state-eeprom)
state                (backend: raw, path: /dev/eeprom0.update-eeprom)

This output, used to handle MAC addresses and boot chooser settings, is from our BSP in a default state, which lie in EEPROM partitions. The state name to access all variables inside a state is the prefix. All variables can be read with a pattern of $<state name>., e.g. $am335x_phytec_mac_state.mac0, and be written with <state name>. = <value>.

In the end, a state has to be written to the partition by entering state -s <state name>.

RTC

RTCs can be accessed via /dev/rtc*. Because PHYTEC boards have often more than one RTC, there may be more than one RTC device file.

  • To find out the name of the RTC device, you can read its sysfs entry with:
target$ cat /sys/class/rtc/rtc*/name

you will get, for example:

rtc-m41t80 0-0068 
omap_rtc 44e3e000.rtc

This will list all RTCs including the non-I²C RTCs. Linux assigns RTC devices IDs based on the device tree /aliases entries if present.

am335x-phycore-som.dtsi:

aliases {
        rtc0 = &i2c_rtc;
        rtc1 = &rtc;
};

As the time is set according to the value of rtc0 during system boot, rtc0 should be always the RTC that is being backed up. Date and time can be manipulated with the hwclock tool, using the -w (systohc) and -s (hctosys) options. To set the date, first use date and then run hwclock -w -u to store the new date into the RTC. For more information about this tool, refer to the man page of hwclock.

If you want to use the interrupt of the RV-4162-C7 RTC while working with the PCM-953 CB, jumper JP23 on the CB must be closed. Remember that the interrupt can only be applied to the RTC if it is not already in use for the LCD-018 touch.

DT representation for I²C RTCs, e.g. in am335x-phycore-som.dtsi:

        i2c_rtc: rtc@68 {
                compatible = "microcrystal,rv4162";
                reg = <0x68>;
                status = "disabled";
        };

Capacitive Touchscreen

The capacitive touchscreen is a part of the display module.

  • For a simple test of this feature, start our demo application with:
target$ QtDemo

This application also includes a Multitouch Demo.

  • To start another, simpler test application:
target$ qt5-opengles2-test
  • To test the basic input handling of the touchscreen, use evtest after selecting an input device:
target$ evtest

The raw touch input events will be displayed. As the touchscreen is part of the display, the touchscreen DT entry is required (for example, for the LCD-018 module). For the LCD-018 module, our DT model expects an i2c_ts node. Please see am335x-phytec-lcd.dtsi.

The display DT representation for all displays implemented so far, are summarized in am335x-phytec-lcd.dtsi.

DT representation, e.g. am335x-pcm-953.dtsi:

/* Defined in am335x-pcm-953.dtsi, board specific part */
&
am33xx_pinmux {
	ts_irq_pin: pinmux_ts_irq_pin {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x9B4, PIN_INPUT_PULLUP | MUX_MODE7)	/* xdma_event_intr1.gpio0_20 */
		>;
	};
};
 
&i2c0 { 
        i2c_ts: touchscreen@38 {
                compatible = "edt,edt-ft5x06";
                reg = <0x38>;
                pinctrl-names = "default";
                pinctrl-0 = <&ts_irq_pin>;
                interrupt-parent = <&gpio0>;
                interrupts = <20 0>;
                status = "disabled";
        };
};

Temperature Sensor

The phyCORE-AM335x-R2 has a TMP102 temperature sensor optionally mounted on the module. The temperature can be read out of the sensor over the sysfs.

  • Type:
target$ cat /sys/class/hwmon/hwmon0/temp1_input

to get the temperature in millicelsius.

DT representation, e.g. in am335x-phycore-som.dtsi:

&i2c0 {
        i2c_tmp102: temp@4b {
                compatible = "ti,tmp102";
                reg = <0x4b>;
                status = "disabled";
        };
};

USB Host Controller

The USB controller of the AM335x SoC provides a low-cost connectivity solution for numerous consumer portable devices by providing a mechanism for data transfer between USB devices with a line/bus speed up to 480 Mbps. The USB subsystem has two independent USB 2.0 modules built around two Mentor USB OTG controllers (musb hdrc).

The unified BSP includes support for mass storage devices and keyboards. Other USB related device drivers must be enabled in the kernel configuration on demand. Due to udev, all connected mass storage devices get unique IDs and can be found in /dev/disks/by-id. These IDs can be used in /etc/fstab to mount the different USB memory devices in different ways.

User USB1 (host) configuration in am335x-pcm-953.dtsi:

/* USB */
&cppi41dma {
        status = "okay";
};
 
&ctrl_mod {
        status = "okay";
};
 
&usb {
        status = "okay";
};
 
&usb1 {
        status = "okay";
        dr_mode = "host";
};
 
&usb1_phy {
        status = "okay";
};

USB OTG

Most PHYTEC boards provide a USB OTG interface. USB OTG ports can act as USB device only on default. The support of the automatical switch between host and device mode of the USB OTG has been removed from the kernel. To change the mode to host the device tree has to be changed.

USB Device

In order to connect the board as USB device to a USB host port (for example a PC), you need to configure the appropriate USB gadget. With USB configfs, you can define the parameters and functions of the USB gadget. The BSP includes USB configfs support as a kernel module.

  • Type:
target$ modprobe libcomposite

to load the module.

Example:

  • First, define the parameters such as the USB vendor and product IDs and set the information strings for English (0x409):
target$ cd /sys/kernel/config/usb_gadget/ 
target$ mkdir g1 target$ cd g1/ target$ echo "0x1d6b" > idVendor 
target$ echo "0x0104" > idProduct target$ mkdir strings/0x409 
target$ echo "0123456789" > strings/0x409/serialnumber 
target$ echo "Foo Inc." > strings/0x409/manufacturer 
target$ echo "Bar Gadget" > strings/0x409/product
  • Next, create a file for the mass storage gadget:
target$ dd if=/dev/zero of=/tmp/file.img bs=1M count=64
  • Now you should create the functions you want to use:
target$ cd /sys/kernel/config/usb_gadget/g1
target$ mkdir functions/acm.GS0
target$ mkdir functions/ecm.usb07
target$ mkdir functions/mass_storage.0
target$ echo /tmp/file.img > functions/mass_storage.0/lun.0/file

- acm: Serial gadget, creates a serial interface like /dev/ttyGS0.
- ecm: Ethernet gadget, creates an Ethernet interface, e.g. usb0
- mass_storage: The host can partition, format and mount the gadget mass storage the same way as any other USB mass storage.
  • Bind the defined functions to a configuration:
target$ cd /sys/kernel/config/usb_gadget/g1
target$ mkdir configs/c.1
target$ mkdir configs/c.1/strings/0x409
target$ echo "CDC ACM+ECM+MS" > configs/c.1/strings/0x409/configuration
target$ ln -s functions/acm.GS0 configs/c.1/
target$ ln -s functions/ecm.usb0 configs/c.1/
target$ ln -s functions/mass_storage.0 configs/c.1/
  • Finally, start the USB gadget with the following commands:
target$ cd /sys/kernel/config/usb_gadget/g1 
target$ ls /sys/class/udc/
musb-hdrc.0
  • Now, use the output from the previous command:
target$ echo "musb-hdrc.0" >UDC

If your system has more than one USB Device or OTG port, you can pass the right one to the USB Device Controller (UDC).

  • To stop the USB gadget and unbind the used functions, execute:
target$ echo "" > /sys/kernel/config/usb_gadget/g1/UDC


Jumper 12 (JP12) doesn't have to be closed on the PCM-953 to establish a connection with a host.

User USB0 (OTG) configuration in am335x-pcm-953.dtsi:

&usb0 {
        status = "okay";
};
 
&usb0_phy {
        status = "okay";
};

Add the following property to the usb0 node to set USB OTG interface to host:

dr_mode = "host";

Audio

On PHYTEC products, you will find different audio chips. This chapter should be applicable to most audio chips without modification. Audio support is done via the I2S interface and controlled via I2C.

The I2S port does not always strictly follow the I2S specification, but can use other clock and bit alignments. However, the common ground is the synchronous serial transmission.

  • To check if your soundcard driver is loaded correctly and what the device is called, type:
target$ aplay -lL
  • Use scp to copy a wav file to the board and play it through the sound interface:
target$ aplay -vv file.wav

Not all wave formats are supported by the sound interface. Use Audacity on your host to convert any file into 44100:S16_LE wave format which should be supported on all platforms.

  • Run speaker-test to identify channel numbers:
target$ speaker-test -c 2 -t wav
  • An external audio source can be connected to the input in order to record a sound file which can then be played back:
target$ arecord -c 2 -r 44100 -f S16_LE test.wav 
target$ aplay test.wav
  • To inspect your soundcards capabilities, call:
target$ alsamixer

You should see a lot of options as the audio-ICs have many features you can play with. It might be better to open alsamixer via ssh instead of the serial console, as the console graphical effects could be better. You have either mono or stereo gain controls for all mix points. "MM" means the feature is muted, which can be toggled by hitting m.

For more advanced audio usage, you need to have an audio server. This is required if you want to playback from different applications at the same time. For example, you a have a notification app which makes a beep every now then plus a browser which should be able to play sounds embedded in websites. The notification app has no possibility to open the sound device as long as the browser is running. The notifications will be suppressed. The standard sound server of Linux is pulseaudio. It is not currently installed at the moment, though.

Audio Sources and Sinks

Screenshot of Alsamixer

Enabling and disabling input and output channels can be done with the alsamixer program. F3 selects Screen Playback and F4 Screen Capture. With the Tabulator key you can switch between these screens. To enable or disable switchable controls, press m (mute). With the keys cursor left and cursor right, you can step through the different channels. There are too many channels to fit onto one screen. They will scroll if your cursor reaches the right or left edge. If you get trouble in the display during scrolling, use ssh or gtkterm instead of microcom.

alsamixer can be exited by pressing the ESC key. The settings are saved automatically on shutdown and restored on boot by the systemd service alsa-restore. If you want to save the mixer settings manually, you can execute aslactl store. The settings are saved in /var/lib/alsa/asound.state.

Playback

To playback simple audio streams, you can use aplay. For example:

target$ aplay /usr/share/sounds/alsa/Front_Center.wav

The file formats .ogg and .flac can be played back using ogg123. MP3 playback is currently not supported per default due to licensing issues. If you are going to deliver a product including .mp3 files, please check the royalty fees.

Capture

arecord is a command line tool for capturing audio streams which use Line In as default input source. To select a different audio source, you can use alsamixer. For example, switch on Right PGA Mixer Mic3R and Left PGA Mixer Mic3L in order to capture the audio from the microphone input.

It is a known error that you need to choose Playback screen (F3) instead of Capture screen (F4) to access these two controls.

The following example will capture the current stereo input source with a sample rate of 48000 Hz and will create an audio file in WAV format (signed 16 bit per channel, 32 bit per sample):

target$ arecord -t wav -c 2 -r 48000 -f S16_LE test.wav

Capturing can be stopped using CTRL-C.

Texas Instruments TLV320AIC3007 (phyBOARD-Wega)

The TI chip has a lot of mixing features that you will notice when opening alsamixer. To get an idea of the possibilities, refer to the datasheet from TI. One important feature is the analog mixing capability. You can route input channels to output channels either active or passive without transferring data back and forth to the SoC. This is usually known as zero latency monitoring in terms of PC Audio cards. To control this feature, open alsamixer and go to Playback section (F3). There will be one group of selectors for each output channel, e.g. Right Line Mixer. For most of the input paths, you can select between "passive through" or you can activate a programmable gain signal path. To route the line input to the line output, activate both "Right Line Mixer PGAR Bypass" and "Left Line Mixer PGAL Bypass". You should now hear the input signal at the line out.

As an example application, we can route the audio stream through the whole system. First, we deactivate the direct loop from the line into the line out in alsamixer and activate the ADC for the analog input mixer and the DAC for the analog output mixer. We can now close the signal path in the user space by using a pipe and the ALSA tools:

target$ arecord -c 2 -r 44100 -f S16_LE | aplay

We created the following audio routing path:

analog in -> ADC -> AM335x -> kernel -> (userspace -> kernel -> )* DAC -> analog out

* actually twice for the pipe

You should now hear the input signal at the line output again. But this time, the routing through the entire system added latency of 750 ms to the signal. The line mixer on the other side will only add about 4 μs delay.

This pipe routing is a crude example of how to use audio. If you need good audio performance you should use an audio server. There are two prominent choices available, pulseaudio and jack.

As a third option, you can route the audio from line in to the internal ADC. But instead of taking the signal path through the complete system, you can directly use the internal digital mixer of the TLV to route the signal back to the DAC and then to the output analog mixer and line out. This signal path is record only. You do not have the option of full-duplex playback in this mode, but you can use all the available DSP features of the TLV, the automatic gain, the high-pass filter, EQ and de-emphasis filters for the record path. To activate this mode, you have to use the TI Windows tool to look up the specific I²C commands. The software can be found on the TI webpage and is called TLV320AIC3107EVM-K - GUI Software. The 3107 is register compatible in all available features to the 3007. The software is used for both chips.

Wolfson WM8974 (phyCORE-AM335x Carrier Board - PCM-953)

The WM8974 is a low power mono codec with a speaker out. The codec has an internal PLL, so different clocking modes can be support. On the PCM-953, we achieved the best values for the Total Harmonic Distortion (THD) with an external quartz (OZ1 on the PCM-953) and the WM8974 used in I2S and master mode. The BSP is, per default, configured this way. If the codec is not working, first ensure that jumper JP6 is closed at 1+2 to enable the external quartz.

The microphone input is configured in single ended mode. Test Pad TP1 can be used when connecting a balanced microphone. MONO_OUT is the line out mono signal. HEADPHONES is a stereo out jack with a ground on the sleeve and the differential mono signal connected to the tip (positive power out) and the ring of the jack (negative power out). An adapter is required in order to attach a stereo headphone to the jack. The adapter must connect the ring of the board's jack (negative power out) to the ground of the headphone and the tip of the jack (positive power out) to both, left and right signal input of the stereo headphone.

Framebuffer

This driver gains access to displays connected to PHYTEC carrier boards via device node /dev/fb0.

  • To run a simple test of the framebuffer feature, execute:
target$ fbtest

This will show various pictures on the display.

  • Information about the framebuffer's resolution can be obtained with:
target$ fbset

which will return:

mode "800x480-0"
        # D: 0.000 MHz, H: 0.000 kHz, V: 0.000 Hz
        geometry 800 480 800 480 32
        timings 0 0 0 0 0 0 0
        accel true
        rgba 8/16,8/8,8/0,0/0
endmode

fbset cannot be used to change display resolution or color depth. Depending on the framebuffer device, different kernel commands are mostly needed to do this. Some documentation can be found in the kernel documentation at https://www.kernel.org/doc/Documentation/fb/modedb.txt. Please also refer to the manual of your display driver for more details.

  • To query the color depth of the framebuffer emulation, type:
target$ cat /sys/class/graphics/fb0/bits_per_pixel

The result can be, for example:

32

The display DT representation can be found in am335x-phytec-lcd.dtsi. We have split the display configuration into two parts. In a generic display module am335x-phytec-lcd.dtsi, which includes the display DT representations for all displays supported, and a board specific part which can be found in all board DTs. The am335x-phytec-lcd.dtsi file is included within the board DTs.

Board specific part, e.g. am335x-pcm-953.dtsi:

/* Display */
&am33xx_pinmux {
        ecap0_pins: pinmux_ecap0 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x964, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* ecap0_in_pwm0_out.ecap0_in_pwm0_out */
		>;
        };
 
        ts_irq_pin: pinmux_ts_irq_pin {
   		pinctrl-single,pins = <
			AM33XX_IOPAD(0x9B4, PIN_INPUT_PULLUP | MUX_MODE7)	/* xdma_event_intr1.gpio0_20 */
		>;
        };
};
 
&ecap0 {
        pinctrl-names = "default";
        pinctrl-0 = <&ecap0_pins>;
        status = "disabled";
};
 
&i2c0 {
        i2c_ts: touchscreen@38 {
                compatible = "edt,edt-ft5x06";
                reg = <0x38>;
                pinctrl-names = "default";
                pinctrl-0 = <&ts_irq_pin>;
                interrupt-parent = <&gpio0>;
                interrupts = <20 0>;
                status = "disabled";
        };
};
 
&tscadc {
        status = "disabled";
        tsc {
                ti,wires = <4>;
                ti,x-plate-resistance = <200>;
                ti,coordinate-readouts = <5>;
                ti,wire-config = <0x00 0x11 0x22 0x33>;
                ti,charge-delay = <0x400>;
        };
};
 
#include "am335x-phytec-lcd.dtsi"

Backlight Control

If a display is connected to the PHYTEC board, you can control its backlight with the Linux kernel sysfs interface. All available backlight devices in the system can be found in the folder /sys/class/backlight. Reading the appropriate files and writing to them allows the backlight to be controlled.

  • To get, for example, the maximum brightness level (max_brightness), execute:
target$ cd /sys/class/backlight/backlight/ 
target$ cat max_brightness

which will result in:

7

The valid values for the brightness level are 0 to <max_brightness>.

  • To obtain the current brightness level, type:
target$ cat brightness

you will get for example:

2
  • Write to the file brightness to change the brightness:
target$ echo 0 > brightness

turns the backlight off:

target$ echo 6 > brightness

sets the brightness to the second highest brightness level.

For documentation of all files see https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight.

If dimming does not work by writing to the file brightness, check the DIP switch settings on the bottom side of the display module (LCD-018-xxx). The correct setting of DIP switch S1 is 1=OFF, 2=OFF, 3=ON and 4=OFF.

Resistive Touchscreens

Most of the PHYTEC boards support connecting a resistive touchscreen which requires tslib support in general. But tslib support is also needed for the Qt framework for use of a resistive touchscreen, because tslib and Qt5 do not work together out of the box.

  • To set the right environment when starting a Qt application, start it with our qtLauncher:
target$ qtLauncher QtDemo [optional QtDemo parameters]

The launcher will check whether the touchscreen is calibrated or not. If not, it will automatically start the calibration program before starting your application.

  • Recalibration of the touchscreen can be done after closing the Qt application by executing:
target$ ts_calibrate

Watchdog

The AM335x SoC includes a hardware watchdog which is able to reset the board when the system hangs. Support for this is already partly activated in the AM335x BSP. This chapter will explain how to enable full support based on a root filesystem using systemd. The kernel driver expects a user space to "ping" the watchdog on a regular basis. As user space setups may handle this different, we have not activated this for the whole system.

Watchdog Support in the Barebox Bootloader

The watchdog is enabled when the boot command is launched. The timeout of the watchdog is set with the persistent nv variable in boot.watchdog_timeout. The default value is 60 s.

  • If the value should be changed, edit the file boot.watchdog_timeout:
bootloader$ edit /env/nv/boot.watchdog_timeout
  • Or change the variable with the nv command:
bootloader$ nv boot.watchdog_timeout=<time, e.g. 30s>
  • Then save the changes with saveenv.

It is also possible to enable the watchdog manually at the barebox prompt using the wd <timeout> command. Executing the wd command without any parameter retriggers the watchdog. Disabling the watchdog again can be done with wd 0.

Watchdog Support in the Linux Kernel

After the kernel has started, the watchdog is disabled again when the omap_wdt driver is loaded. This is the default behavior of the watchdog driver. To keep the watchdog enabled after the driver has been probed, the kernel command line needs to be extended with:

omap_wdt.early_enable omap_wdt.timer_margin=60

The first parameter enables the watchdog in the kernel and the second one defines a new timeout in seconds. The bootargs can also be set in the barebox environment.

  • To set the bootargs edit the file linux.bootargs.base:
bootloader$ edit /env/nv/linux.bootargs.base
  • Then save the changes with saveenv.

As the kernel driver has no self petting mechanism, the board will reset after the timeout runs out and the user space does not handle it.

Watchdog Support in systemd

Systemd includes hardware watchdog support since version 183.

  • To activate watchdog support the file system.conf in /etc/systemd/ has to be adapted by enabling the options:
RuntimeWatchdogSec=60s 
ShutdownWatchdogSec=10min

RuntimeWatchdogSec defines the timeout value of the watchdog, while ShutdownWatchdogSec defines the timeout when the system is rebooted. For more detailed information about hardware watchdogs under systemd refer to: http://0pointer.de/blog/projects/watchdog.html

WLAN Modules

Supported Wi-Fi Modules and Software used

Currently, there is only one module supported. The BSP described herein allows the board to run the TiWi-BLE Bluetooth and Wi-Fi combo module in client and Access Point (AP) mode using WEP, WPA and WPA2 encryption. More information about the module can be found at https://www.lsr.com/embedded-wireless-modules/wifi-plus-bluetooth-module/tiwi-ble

This BSP is using the most current firmware from the Linux firmware repository.

https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/

The following binaries are used:

wl127x-fw-5-mr.bin (multi role)
wl127x-fw-5-sr.bin (single role) 
wl127x-fw-5-plt.bin (used for the calibration process)

The Linux kernel driver will select the right firmware.

We are using a self generated nvs binary file to allow the TiWi-BLE combo module to operate in compliance with the modular certification for FCC and ETSI. We have also set the MAC in the nvs file to 00:00:00:00:00:00. This causes the driver to use the MAC from the BT BD address that is burned into the wl127x chip.

The wl1271-nvs.bin can be generated by using TI's calibrator tool and our ini file in:

/usr/share/wl127x-inis/tiwi-ble-fcc-etsi.ini

Please see section Calibration for more information.

Enable Wi-Fi Expansion Boards

All Wi-Fi expansion boards can be enabled by sourcing the am335x-wlan expansion file in env/expansions/.

am335x-wlan:

of_fixup_status /fixedregulator@2 
of_fixup_status /ocp/mmc@47810000 
of_fixup_status /ocp/mmc@47810000/wlcore@2

This file will be sourced in /env/init/config-expansions.

After enabling the Wi-Fi module on the expansion board and booting the kernel, you should see an output on your console similar to the following:

cfg80211: Calling CRDA to update world regulatory domain
wlcore: loaded

On phyBOARD-WEGA-AM335x make sure to disable the am335x-wega-peb-eval-01 in /env/init/config-expansions. UART0 will still work but the leds and buttons are needed for wifi.

Calibration

Calibration is a process of determining radio parameters for a specific chip. These configuration parameters are suitable to the specific chip with its unique design. Therefore, the calibration parameters are sent back to the driver to be stored in non-volatile memory for later use. Upon initialization, the wL12xx driver loads an nvs file, where it expects to read those calibration parameters to send them to the chip. The nvs file includes two main parts: one stores the calibration parameters and the other stores the initialization information required for the wL12xx driver. The calibration is described in:

http://processors.wiki.ti.com/index.php/WL12xx_NLCP_Calibration_Process 
and 
http://linuxwireless.sipsolutions.net/en/users/Drivers/wl12xx/

TI provides a calibration tool which can be found in the 18xx-ti-utils repository:

http://git.ti.com/wilink8-wlan/18xx-ti-utils

The calibrator version used is 0.80.

  • Before starting the calibration, the WiFi module has to be set to PLT mode. For this purpose, open the menuconfig in your Yocto directory:
<yocto_dir>/build$ bitbake virtual/kernel -c menuconfig
  • Activate the NL80211_TESTMODE configuration:
Networking support > Wireless > nl80211 testmode command
  • Press F6 to save the configurations and F9 to leave. Rebuild the kernel:
<yocto_dir>/build$ bitbake phytec-headless-image
  • Flash the new BSP image to the board (section Updating the Software) and reboot the module.
  • To start the calibration, first generate a nvs reference file:
target$ calibrator set ref_nvs /usr/share/wl127x-inis/tiwi-ble-fcc-etsi.ini 
target$ cp new-nvs.bin /lib/firmware/ti-connectivity/wl1271-nvs.bin
  • Reload the driver:
target$ ifconfig wlan0 down 
target$ rmmod wlcore_sdio 
target$ modprobe wlcore_sdio
  • Now perform the first calibration:
target$ ifconfig wlan0 down 
target$ calibrator plt calibrate
  • Copy the newly created file to the proper location:
target$ cp new-nvs.bin /lib/firmware/ti-connectivity/wl1271-nvs.bin
  • Finally, set the WLAN MAC address:
target$ calibrator set nvs_mac /lib/firmware/ti-connectivity/wl1271-nvs.bin 00:00:00:00:00:00

Restart the module to get the new MAC address:

target$ rmmod wlcore_sdio
target$ modprobe wlcore_sdio

Power Management

CPU Core Frequency Scaling

The CPU of the AM335x SoC is able to scale the voltage and clock frequency. This is used to save power when the full performance of the CPU is not needed. Scaling the voltage and frequency is referred to as 'Dynamic Voltage and Frequency Scaling' (DVFS). The AM335x BSP supports the DVFS feature. The Linux kernel provides a DVFS framework that allows each CPU core to have a min/max frequency and a governor that governs it. Depending on the AM335x variant used, several different frequencies are supported.

  • Type:
target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

to get a complete list.

In case you have, for example, an AM3359 with a maximum of 800 MHz, the result will be:

300000 600000 720000 800000

The voltages are scaled according to the setup of the frequencies.

You can decrease the maximum frequency (e.g. to 720000):

target$ echo 720000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq

or increase the minimum frequency (e.g. to 600000):

target$ echo 600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
  • To ask for the current frequency, type:
target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

So-called governors automatically select one of these frequencies in accordance with their goals.

  • List all governors available:
target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

The result will be:

conservative userspace powersave ondemand performance

- conservative is much like the ondemand governor. It differs in behavior in that it gracefully increases and decreases the CPU speed rather than jumping to max speed the moment there is any load on the CPU.
- userspace allows the user or user space program running as root to set a specific frequency (e.g. to 600000). Type:

target$ echo 600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

- powersave always selects the lowest possible CPU core frequency.
- ondemand switches between possible CPU core frequencies in reference to the current system load. When the system load increases above a specific limit, it immediately increases the CPU core frequency. This is the default governor when the system starts up.
- performance always selects the highest possible CPU core frequency.

  • In order to ask for the current governor, type:
target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

You will normally get:

ondemand
  • witching over to another governor (e.g. userspace) is done with:
target$ echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Power Saving Modes

The phyCORE-AM335x-R2 supports two different Suspend-to-RAM (STR) modes, standby and deep sleep. They switch the SoC into a power saving mode and turn off different power domains.

Standby

This mode has the following behaviors:

  • DDR in self-refresh
  • CPU shutdown
  • Peripheral is on

To turn on this STR mode, write standby to /sys/power/state:

echo -n standby > /sys/power/state

Deep Sleep

This mode has the following behaviors:

  • DDR in self-refresh
  • CPU shutdown
  • Peripheral is off

To turn on this STR mode write mem to /sys/power/state:

echo -n mem > /sys/power/state

Customizing the BSP

PREEMPT RT

By default, all phyBOARD-Regor BSPs are built with PREEMPT RT enabled, but it's not restricted to this. A machine built with or without a real-time kernel is defined by the variable value of "DISTRO" in 'build/conf/local.conf'. So if a machine other than pyhBOARD-Regor is built with PREEMPT RT, the value of "DISTRO" must be changed to "yogurt-rt".

Changing MTD Partitions

For Memory Technology Devices (MTD) such as NAND Flash or SPI NOR Flash, the partitions are usually defined in the device trees, i.e. they are defined in the device tree of the MLO, the barebox, and the kernel. When changing the partition table, all those parts need to be touched. Newer barebox versions (v2015.07.0 and newer) have a mechanism to overwrite partitions at runtime.

The barebox holds an internal list with partitions which are initialized with the partition table out of the barebox device tree. This list is used later on to fix up the device tree of the kernel and can be overwritten in the barebox shell or with a script before booting the kernel.

  • To print the partitions, type:
bootloader$ echo $<mtddevice>.partitions

Example:

bootloader$ echo $nand0.partitions

can, for example, result in:

128k(xload),128k(xload_backup1),128k(xload_backup2),128k(xload_backup3),512k(barebox),512k(barebox_backup),256k(bareboxenv),129280k(root)
  • To overwrite the partitions, change the partitions variable:
target$ m25p0.partitions=128k(xload),512k(barebox),128k(bareboxenv),128k(oftree),7296k(kernel)

Adding and deleting partitions by overwriting the partitions variable is possible. But do not touch the xload, xload_backup*, barebox, barebox_backup, and bareboxenv partitions. Those must not be changed at runtime.