BSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.A3)

Table of Contents

BSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.A3)
Document TitleBSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.A3)
Document TypeBSP Reference Manual
Yocto PageL-813e.A8 Yocto Reference Manual
Article NumberL-844e.A3
Release Date01.10.2020
Is Branch ofBSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.Ax)

Compatible BSP'SBSP Release TypeBSP Release DateBSP Status
BSP-Yocto-i.MX6UL-PD19.1.1Minor Release02.09.2020Released
BSP-Yocto-i.MX6UL-PD19.1.0Final Release (stable final Release)29.05.2019Released
BSP-Yocto-phyBOARD-Segin-PD17.2.0Final Release (stable final Release)17.10.2017Released
BSP-Yocto-Vendor-phyBOARD-Segin-PD17.1.2Fix Release13.10.2017Released
BSP-Yocto-Vendor-phyBOARD-Segin-PD17.1.0Final Release (stable final Release)13.07.2017Released

Introduction to Yocto

Please read the Yocto Reference Manualfor 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 i.MX 6UL/6ULL BSP described herein, visit our web page at https://www.phytec.de/produkt/system-on-modules/phycore-imx-6ul-download/#software. Click the corresponding BSP release and look for the article number of your module in the column "Article Number". Finally, look for 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 i.MX 6UL BSP using the phyLinux script. For more details, see the section phyLinux Documentation in the Yocto Reference Manual. If you want to use our software without phyLinux and the Repo tool managed environment, you can find all Git repositories at:

git://git.phytec.de  

Used barebox repository:

git://git.phytec.de/barebox

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

Used Linux kernel repository:

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

Our i.MX 6UL/6ULL Linux kernel is based on the Linux stable kernel. The kernel repository can be found at:

git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

To find out which tag is used for a specific board, look at:

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 can start.

Finding the Correct Software Platform

To find the correct software and the corresponding machine name for your PHYTEC board, go to i.MX 6UL/ULL BSP Releasesand click on the corresponding BSP release, or refer to the files in the source folder of the BSP:

meta-phytec/conf/machine/*.conf

where you can find the platform name to the corresponding product IDs. This information is also displayed by the phyLinux script.

Example: phyboard-segin-imx6ul-6.conf machine configuration file:

#@TYPE: Machine                                                                  
#@NAME: phyboard-segin-imx6ul-6                                                  
#@DESCRIPTION: PHYTEC phyBOARD-Segin i.MX6 ULL, 512MB RAM, NAND                  
#@ARTICLENUMBERS: PB-02013-001.A5, PB-02013-310I.A0, PCL-063-23900CI.A0          
#@SUPPORTEDIMAGE: phytec-qt5demo-image/yogurt, phytec-vision-image/yogurt, -c populate_sdk phytec-qt5demo-image/yogurt

Machine phyboard-segin-imx6ul-6.conf represents the phyBOARD-Segin Full Featured (Kit) with the PCL-063-23300CI.A2 phyCORE-i.MX 6ULL.

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$ ./phyLinux init -p imx6ul -r PD19.1.0

Please read the section Initialization for more information.

Starting the Build Process

Refer to the section Start the Build.

BSP Images

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

As an example, the following list shows all files generated for the i.MX 6ULL SOC, phyboard-segin-imx6ul-6 machine:

  • Barebox: barebox.bin
  • Barebox configuration: barebox-defconfig
  • Kernel: zImage
  • Kernel device tree file: zImage-imx6ull-phytec-phyboard-segin-ff-rdk-nand.dtb
  • Kernel configuration: zImage.config
  • Root filesystem: phytec-qt5demo-image-phyboard-segin-imx6ul-6.tar.gz, phytec-qt5demo-image-phyboard-segin-imx6ul-6.ubifs, phytec-qt5demo-image-phyboard-segin-imx6ul-6.ext4
  • SD card image: phytec-qt5demo-image-phyboard-segin-imx6ul-6.sdcard

Booting the System

The default boot source for the i.MX 6UL/6ULL modules like phyCORE-i.MX 6UL or phyCORE-i.MX 6ULL is the NAND flash. The easiest way to get started with your freshly created images is writing them to an SD card and setting the boot configuration accordingly. For information on how to set the correct boot configuration, refer to the corresponding hardware manual for your PHYTEC board.

Booting from NAND Flash

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

On BSP version PD19.1.0, there is a software issue about factory bad block-detection, in which only 25% of the factory bad blocks are detected correctly and marked as such. Any I/O operation on the unmarked bad blocks will lead to an error. Please read the BSP Release Notes for more information. This issue is fixed on PD19.1.1.

Booting from SD Card

Booting from SD card is useful in several situations, for example, if the board does not start due to a damaged bootloader. To boot from SD card, the SD card must be formatted in a special way as the i.MX 6UL/6ULL ROM code does not use file systems. Instead, it expects the bootloader at a fixed location on the SD card.

There are two ways to create a bootable SD card. You can either use:
- a single prebuild SD card image, or
- the four individual images (barebox-, kernel- and device tree image, and root filesystem)

Using a Single, Prebuild SD Card Image

The first option is to use the SD card image built by Yocto. This image has the ending *.sdcard and can be found under build/deploy/images/<MACHINE>/<IMAGENAME>-<MACHINE>.sdcard. It contains all BSP files in already correctly formatted image and can be easily copied to the SD card by using the single Linux command dd.

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

Warning

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, having selected the wrong device can also erase your hard drive!

To create your bootable SD card, you must first find the correct device name and possible partitions of your SD card. 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.
  • Next, 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 also recognize the partitions which must be unmounted if the SD card is formatted. 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:
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:
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 actually written to the SD card and do not remain in the memory.

Using Four Individual Images (barebox-, kernel- and device tree image, and root filesystem)

Instead of using the single prebuild SD card image, you can use the barebox, kernel, and device tree image together with the root filesystem separately to manually create a bootable SD card.

For this method, a new card must be set up with 2 partitions and 8 MB of free space at the beginning of the card. Use the following procedure with fdisk under Linux:

  • Create a new FAT partition with partition id C. When creating the new partition, you must leave 8 MB of free space at the beginning of the card. When you go through the process of creating a new partition, fdisk lets you specify where the first sector starts. During this process, fdisk will tell you where the first sector on the disk begins. If, for example, the first sector begins at 2048, and each sector is 512 bytes. 8 MB / 512 bytes = 16384 sectors, which means your first sector should begin at 18432 to leave 8 MB of free space. The size of the FAT partition only needs to be big enough to hold the zImage which is only a few megabytes. To be safe we, recommend a size of 64 MB.
  • Create a new Linux partition with partition id 83. Make sure you start this partition after the last sector of partition 1! By default, fdisk will try to use the first partition available on the disk, which in this example is 1000. However, this is our reserved space! You must use the remaining portion of the card for this partition.
  • Write the new partition to the SD card and exit fdisk.

Example:

  • Type:
host$ sudo fdisk -l /dev/sdc

You will receive:

Disk /dev/sde: 3,8 GiB, 4025483264 bytes, 7862272 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xef6c9559
 
Device     Boot  Start     End Sectors  Size Id Type
/dev/sde1        18432  149503  131072   64M  c W95 FAT32 (LBA)
/dev/sde2       149504 7862271 7712768  3,7G 83 Linux

Remove and reinsert the card. Otherwise, Linux will not recognize the new partitions created in the previous step. Create a file system on the partitions with (replace 'sde' with your device):

host$ sudo mkfs.vfat /dev/sde1
host$ sudo mkfs.ext4 -L "rootfs" /dev/sde2

Now the images need to be copied to the SD card. Write the bootloader in front of the first partition (replace 'sde' with your device):

host$ sudo dd if=barebox.bin of=/dev/sde bs=512 skip=2 seek=2 conv=fsync

Mount the first partition (vfat) and copy the zImage and oftree file to it:

host$ sudo mount /dev/sd<X>1 /mnt


Warning

Make sure that the images are named as zImage (kernel) and oftree (devicetree), as the bootloader expects them exactly like that.

In case you want to boot the whole Linux from SD card, mount the ext4 partition. Then untar <IMAGENAME>-<MACHINE>.tar.gz rootfs image to it:

host$ sudo mount /dev/sd<X>2 /media
host$ sudo tar zxf <IMAGENAME>-<MACHINE>.tar.gz -C /media/

Do not forget to properly unmount the SD card:

host$ sudo umount /media

Booting from eMMC

On phyCORE-i.MX 6UL/6ULL, eMMC can be equipped instead of NAND flash. For these boards, eMMC is the default boot source. To update the software of the eMMC, see Updating the Software.

Booting from USB OTG (Serial Downloader)

The i.MX 6UL/6ULL ROM code is capable of downloading a bootloader from the USB OTG interface ("Serial Downloader" in the i.MX 6UL/6ULL Reference Manual). This is useful for a last resort recovery of a broken bootloader, or for rapid barebox development. First, you have to compile the program imx-usb-loader in the barebox source directory. You can use any current mainline barebox version for that (see getting barebox).

First load the default configuration:

host$ make ARCH=arm imx_v7_defconfig

To activate imx-usb-loader, type:

host$ make ARCH=arm menuconfig

and enable Host Tools --> imx-usb-loader (ARCH_IMX_USBLOADER). Now compile the imx-usb-loader:

host$ make ARCH=arm CROSS_COMPILE=<prefix of your arm cross toolchain> scripts/imx/

The tool is in scripts/imx/imx-usb-loader.

To load the bootloader to the module, execute the following sequence:

  • Connect your target to your host PC via USB OTG.
  • Check the boot configuration of your board and ensure that the ROM code enters Serial Downloader mode (see the corresponding section in the Hardware Manual of your board). (L-820e_1 phyBOARD-Segin Hardware Manual)
  • As the boot configuration is not read during a soft reset, perform a power cycle.
  • Finally, execute the imx-usb-loader:
host$ sudo scripts/imx/imx-usb-loader images/barebox-phytec-phycore-imx6ul-512mb.img

You should see the barebox boot messages on the serial console.

Booting the Kernel from Network

Booting from network means loading the kernel and devicetree over TFTP. 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. The following tools will be needed to boot the Kernel from Ethernet:

  1. A TFTP server and
  2. An optional tool for starting/stopping a service (xinetd).

For Ubuntu, install:

host$ sudo apt-get install tftpd-hpa xinetd

After the installation, there are two ways to configure the TFTP server:

  1. As a standalone daemon
  2. Controlled and handled by xinetd

First, create a directory to store the TFTP files:

host$ sudo mkdir /tftpboot
host$ sudo chmod -R 777 /tftpboot
host$ sudo chown -R nobody /tftpboot

Then copy your BSP image files to this directory. You also need to configure a static IP address for the appropriate interface. The default IP address of the PHYTEC evaluation boards is 192.168.3.11. So setting 192.168.3.10 with netmask 255.255.255.0 as a host address is a good choice.

Configure TFTP as a stand alone daemon

Create or edit /etc/default/tftpd-hpa:

# /etc/default/tftpd-hpa
 
TFTP_USERNAME="nobody"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="192.168.3.10:69"
TFTP_OPTIONS="-s -c"

Set TFTP_DIRECTORY to your TFTP server root directory
Set TFTP_ADDRESS to the host address the server is listening to (set to 0.0.0.0:69 to listen to all local IPs)
Set TFTP_OPTIONS, following command shows the available options:

host$ man tftpd

Restart the services to pick up the configuration changes:

host$ sudo service tftpd-hpa restart

Configure TFTP as xinetd service:

To run the TFTP server with xinetd, the standalone daemon first needs to be disabled:

host$ sudo systemctl disable tftpd-hpa
host$ sudo systemctl stop tftpd-hpa

If necessary, edit or create /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
}

server_args holds the options and the TFTP server root directory
Reload the services to pick up the configuration changes:

sudo /etc/init.d/xinetd reload

After the installation of the TFTP server, an NFS server needs to be installed, too. The NFS server is not restricted to a certain file system location, so all we have to do on most distributions is modify the file /etc/exports and export our root filesystem to the embedded network. For that, append /etc/exports:

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

and adapt it to your local needs, where <user> must be replaced with your home directory name and the <rootfspath> can be set to a folder which contains an extracted rootfs tar.gz image.

Preparations on the Embedded Board

To find the Ethernet settings in the bootloader of the target, type:

bootloader$ ifup eth0
bootloader$ devinfo eth0

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

ethaddr: 50:2d:f4:11:96:65 (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::eth0: (type: string)
linux.devname: eth0 (type: string)
mode: static (type: enum) (values: "dhcp", "static", "disabled")
netmask: 255.255.255.0 (type: ipv4)
serverip: 192.168.3.10 (type: ipv4)

If you need to change any values, use the nv variables related to that device:

bootloader$ ll /env/nv/dev.eth0.*
-rwxrwxrwx             12 /env/nv/dev.eth0.ipaddr
-rwxrwxrwx              4 /env/nv/dev.eth0.linux.devname
-rwxrwxrwx              6 /env/nv/dev.eth0.mode
-rwxrwxrwx             13 /env/nv/dev.eth0.netmask
-rwxrwxrwx             12 /env/nv/dev.eth0.serverip

You can either edit these files directly or use the nv command for instance like this:

bootloader$ nv dev.eth0.ipaddr=192.168.3.11

You can also change the IP address to DHCP instead of using a static one.

bootloader$ nv dev.eth0.mode=dhcp

Also set up paths for TFTP and NFS in the file /env/boot/net. A modified file could look like this:

#!/bin/sh
 
[ -e /env/config-expansions ] && /env/config-expansions
 
path="/mnt/tftp"
 
global.bootm.image="${path}/zImage"
 
oftree="${path}/oftree"
if [ -f "${oftree}" ]; then
    global.bootm.oftree="$oftree"
fi
 
nfsroot="/home/user/nfssrc"
ip_route_get -b ${global.net.server} global.linux.bootargs.dyn.ip
global.linux.bootargs.dyn.root="root=/dev/nfs nfsroot=$nfsroot,vers=3,tcp"

Please note that these modifications will only affect the bootloader settings.

Booting the Embedded Board

To boot from network, call:

bootloader$ boot net

or restart the board and press m to stop autoboot. You will see a menu:

Main menu
1: Boot default
2: Detect bootsources
3: Settings
4: Save environment
5: Shell
6: Reset

Press 2 and then Enter which opens a second menu:

boot
1: mmc
2: nand
3: spi
4: net
5: back

Press 4 and then Enter 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, emmc). If this is the case, you can create your own custom boot entry specifying the kernel and root filesystem location. Create your own boot entry in barebox, for example named "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>"
ip_route_get -b ${global.net.server} global.linux.bootargs.dyn.ip
/env/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 below. <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 
/mnt/tftp/zImage - To boot the Linux kernel via TFTP 
/mnt/mmc/zImage - To boot the Linux kernel from SD/MMC card
/mnt/emmc/zImage - To boot the Linux kernel from eMMC

<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 
/mnt/tftp/oftree - To boot the device tree binary via TFTP 
/mnt/mmc/oftree - To boot the device tree binary from SD/MMC card 
/mnt/emmc/oftree - To boot the device tree binary from eMMC

<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 
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 
root=/dev/mmcblk1p2 rootwait - To mount the root filesystem from eMMC

When the root filesystem is booted from a network, the nfsroot variable has to hold the path of your nfs root directory on the host machine. So <nfs_root_path> can be:

/home/<user>/nfsroot

where <user> has to be replaced by your host username. 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 source and boot order is defined in /env/init/bootsource.

Updating the Software

In this chapter, we explain how to use the barebox bootloader to update images in NAND flash or eMMC, either from Network, SD card, USB Flash Drive, USB DFU or Android Fastboot. The RAUC update mechanism is introduced as well.

Updating from Network

i.MX 6UL/6ULL boards that have an Ethernet connector can be updated over network. 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(see Booting the Kernel from Network).

Tip

Although some phyBOARD-Segin feature two Ethernet connectors only eth0 is available in the barebox.

Boot the system using any boot device available.
Press any key to stop autoboot, then type:

bootloader$ ifup eth0
bootloader$ devinfo eth0

The Ethernet interfaces should be configured like this:

ethaddr: 50:2d:f4:11:96:65 (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::eth0: (type: string)
linux.devname: eth0 (type: string)
mode: static (type: enum) (values: "dhcp", "static", "disabled")
netmask: 255.255.255.0 (type: ipv4)
serverip: 192.168.3.10 (type: ipv4)

If you need to change any values, use the nv variables related to that device:

bootloader$ ll /env/nv/dev.eth0.*
-rwxrwxrwx             12 /env/nv/dev.eth0.ipaddr
-rwxrwxrwx              4 /env/nv/dev.eth0.linux.devname
-rwxrwxrwx              6 /env/nv/dev.eth0.mode
-rwxrwxrwx             13 /env/nv/dev.eth0.netmask
-rwxrwxrwx             12 /env/nv/dev.eth0.serverip

You can either edit these files directly or use the nv command for instance like this:

bootloader$ nv dev.eth0.ipaddr=192.168.3.11

You can also change the IP address to DHCP instead of using a static one.

bootloader$ nv dev.eth0.mode=dhcp

Reboot the system after applying any changes.

Updating NAND Flash from Network

To update the bootloader, you may use the barebox_update command. This provides a handler which automatically erases and flashes two copies of the barebox image into the NAND Flash. This makes the system more robust against ECC issues. If one block is corrupted, the ROM loader uses the next block. This handler also creates an FCB table in the NAND. The FCB table is needed from the ROM loader to boot from NAND.

Update barebox:

Type:

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

On startup, the TFTP server is automatically mounted to /mnt/tftp. 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.

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

bootloader$ erase /dev/nand0.barebox-environment.bb

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

bootloader$ reset

Update the kernel and devicetree:

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

Tip

With BSP-Yocto-i.MX6UL-PD19.1.0 ubiformat does not show a "100% complete" output anymore in certain cases although it finished succesfully. This is caused by a change in implementation which is not harmful. The succesful completion of the ubiformat command can always be checked by analyzing its return code. (target$ echo $?)

Now get the Linux kernel and oftree from your TFTP server and store it into the NAND Flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /mnt/tftp/zImage
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /mnt/tftp/oftree

Tip

If you get the message /mnt/tftp/zImage has unknown filesize, this is not supported you have to copy the linux kernel and the oftree before with cp.

bootloader$ cp /mnt/tftp/zImage .
bootloader$ cp /mnt/tftp/oftree .
bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel zImage 
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree oftre

Update the root filesystem:

For flashing Linux’s root filesystem into NAND, please use:

bootloader$ cp -v /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root

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 trees, and root filesystem.

To flash the SD card image, use:

bootloader$ detect mmc1
bootloader$ cp -v /mnt/tftp/<name>.sdcard /dev/mmc1


Tip

After flashing the SD card image, the root filesystem does not use all available space on the device. To enlarge the file system, see section Resize the ext4 Root Filesystem.

If you only want to update the bootloader on the eMMC, use:

bootloader$ barebox_update -l

to find the correct update target and:

bootloader$ barebox_update -t mmc1 /mnt/tftp/barebox.bin

to update the target. We also recommend erasing the environment of the old barebox. Otherwise the new barebox will use the old environment.

bootloader$ cp /dev/zero /dev/mmc1.barebox-environment

You should also check the boot configuration of the eMMC device:

bootloader$ detect mmc1
bootloader$ devinfo mmc1 

If you used the cp command as described in the previous, step the value of boot should be disabled, or user:

[...]
Parameters:
  boot: disabled ("disabled", "boot0", "boot1", "user")
  probe: 0

If the values are not disabled or user, the i.MX 6Ul/6ULL ROM code cannot load the bootloader from the eMMC device. It can be set with:

bootloader$ mmc1.boot=disabled

Now 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

To update the kernel and device tree, use:

bootloader$ ls /mnt/emmc
bootloader$ cp /mnt/tftp/zImage /mnt/emmc/
bootloader$ cp /mnt/tftp/oftree /mnt/emmc/

Updating from SD Card

To update the software from SD card, one needs an SD card which holds all required images (barebox, kernel, devicetree and root filesystem). Using an SD card which was flashed with the .sdcard image from Yocto out of the box is not possible since the FAT partition holding the kernel and devicetree image is not big enough to hold the root filesystem images.

A new partitioning scheme is created for the SD card. The SD card will hold the barebox in 8 MiB unpartitioned space at the first sectors to still be able to boot from this SD card and following that a FAT partition which will hold all required images (including a copy of the barebox image).

Use the following procedure with fdisk under Linux:

  • First, delete all existing partitions on the disk and then create a new primary FAT partition with partition id C. When creating the new partition you must leave 8 MB of free space at the beginning of the card. When you go through the process of creating a new partition, fdisk lets you specify where the first sector starts. With the command F on an unpartitioned disk, fdisk tells you where the first sector on the disk begins. If, for example, the first sector begins at 2048 and each sector is 512 bytes, then 8 MB / 512 bytes = 16384 sectors. Therefore, your first sector should begin at 18432 to leave 8 MB of free space. The size of the FAT partition needs to be at least big enough to hold all required images. The partition can easily cover the rest of the SD card.
  • Remove and reinsert the card. Otherwise, Linux will not recognize the new partitions created in the previous step.
  • Create a file system on the partition with (replace 'sde' with your device):
host$ sudo mkfs.vfat /dev/sde1

Now write the barebox in front of the partition (replace 'sde' with your device):

host$ sudo dd if=barebox.bin of=/dev/sde bs=512 skip=2 seek=2 conv=fsync

Mount the FAT partition and copy all required images to the partition (replace 'sde' with your device):

host$ sudo mount /dev/sde1 /mnt

After copying unmount the FAT partition and insert the SD card into your board:

host$ sudo umount /mnt

To update an i.MX 6UL/6ULL board from SD card, the SD card used for updating must be mounted after the board is powered and the boot sequence is stopped on the bootloader prompt. If the board is booted from SD card, the card is already mounted automatically under /mnt/mmc/. Otherwise, mount the SD card in the barebox with:

bootloader$ detect mmc0

It is then also mounted under /mnt/mmc/ if it was partitioned as described above. In any other case, the partition needs to be mounted manually.

Updating NAND Flash from SD Card

To update the images on the NAND Flash from SD card, the same commands as updating from a network are used. The path parameters need to be adapted, however.

Update barebox:

To update the barebox type:

bootloader$ barebox_update -t nand /mnt/mmc/barebox.bin

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

bootloader$ erase /dev/nand0.barebox-environment.bb

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

bootloader$ reset

Update kernel and devicetree:

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

Tip

With BSP-Yocto-i.MX6UL-PD19.1.0 ubiformat does not show a "100% complete" output anymore in certain cases although it finished succesfully. This is caused by a change in implementation which is not harmful. The succesful completion of the ubiformat command can always be checked by analyzing its return code. (target$ echo $?)

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 /mnt/mmc/zImage
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /mnt/mmc/oftree

Update the root filesystem:

For flashing Linux’s root filesystem to NAND, please use:

bootloader$ cp -v /mnt/mmc/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

To update the images on the eMMC from SD card, the same commands as updating from a network are used. However, the path parameters need to be adapted. Either update the whole .sdcard image:

bootloader$ detect mmc1
bootloader$ cp -v /mnt/mmc/<name>.sdcard /dev/mmc1

or update barebox, kernel, and devicetree separately:

Update barebox:

bootloader$ barebox_update -t mmc1 /mnt/mmc/barebox.bin

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

bootloader$ cp /dev/zero /dev/mmc1.barebox-environment

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

bootloader$ reset

Update kernel and devicetree:

bootloader$ detect mmc0
bootloader$ detect mmc1
bootloader$ cp /mnt/mmc/zImage /mnt/emmc/
bootloader$ cp /mnt/mmc/oftree /mnt/emmc/

Change the boot configuration of your board to eMMC boot, if necessary, and reset your board.

Tip

The root filesystem can only be updated with a whole .sdcard image update.

Updating from USB Flash Drive

To update the software from a USB Flash Drive, the stick needs to hold all required images (barebox, kernel, devicetree, and root filesystem).

Copy the required images to the USB Flash Drive, preferably on a FAT partition but any other filesystem supported by the bootloader is ok.

  • 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 with the following command:

bootloader$ usb

This should print output like:

usb: USB: scanning bus for devices...
usb: Bus 001 Device 001: ID 0000:0000 EHCI Host Controller
usb: Bus 001 Device 002: ID 090c:6200 Generic USB2.0 card 
Using index 0 for the new disk
usb: 2 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:

bootloader$ ls /dev/disk0*

You should see:

/dev/disk0      /dev/disk0.0 

Mount the filesystem with the following commands:

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


Tip

The disk number of the USB Flash Drive is enumerated and can vary. Make sure that you mount the correct disk device. The usb command returns the used disk index.

Updating NAND Flash from USB Flash Drive

To update the images on the NAND Flash from USB Flash Drive, the same commands as updating from a network are used. The path parameters need to be adapted, however.

Update barebox:

To update the barebox type:

bootloader$ barebox_update -t nand /mnt/usb/barebox.bin

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

bootloader$ erase /dev/nand0.barebox-environment.bb

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

bootloader$ reset

Update kernel and devicetree:

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

Tip

With BSP-Yocto-i.MX6UL-PD19.1.0 ubiformat does not show a "100% complete" output anymore in certain cases although it finished succesfully. This is caused by a change in implementation which is not harmful. The succesful completion of the ubiformat command can always be checked by analyzing its return code. (target$ echo $?)

Now get the Linux kernel and oftree from your USB Flash Drive and store it on the NAND Flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /mnt/usb/zImage
bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /mnt/usb/oftree

Update the root filesystem:

To flash Linux’s root filesystem to NAND, please use:

bootloader$ cp -v /mnt/usb/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 USB Flash Drive

To update the images on the eMMC from USB Flash Drive, the same commands as updating from a network are used. however, the path parameters need to be adapted. Either update the whole .sdcard image:

bootloader$ detect mmc1
bootloader$ cp -v /mnt/usb/<name>.sdcard /dev/mmc1

or update the barebox, kernel, and devicetree separately:

Update barebox:

bootloader$ barebox_update -t mmc1 /mnt/usb/barebox.bin

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

bootloader$ cp /dev/zero /dev/mmc1.barebox-environment

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

bootloader$ reset

Update kernel and devicetree:

bootloader$ detect mmc1
bootloader$ cp /mnt/usb/zImage /mnt/emmc/
bootloader$ cp /mnt/usb/oftree /mnt/emmc/

Change the boot configuration of your board to eMMC boot, if necessary, and reset your board.

Tip

The root filesystem can only be updated with a whole .sdcard image update.

Updating via USB DFU

To update the software with the USB DFU (Direct Firmware Update) mechanism, the Linux dfu-util tool needs to be installed on the host machine. On Ubuntu install the tool:

host$ sudo apt-get install dfu-util

The DFU mechanism works by exporting the device or file to be updated into the bootloader via the DFU gadget. Then the corresponding file is sent from the host with the dfu-util tool. At this point, the bootloader DFU gadget together with the dfu-util tool only supports updating a single file at once. So to update multiple files, the DFU gadget on the bootloader has to be restarted for each file.

The general approach is as follows:

  • Connect the board with the USB OTG port to your host PC
  • Boot to the bootloader and stop the boot process
  • Activate peripheral mode for the USB OTG port
  • Create a folder for downloaded files in case files cannot be copied to a device directly (e.g. barebox.bin which needs to be updated with barebox_update command)
  • Start USB DFU gadget for the first file to download
  • Run dfu-util tool on the host to download the file
  • After completion, stop the DFU gadget on the bootloader with CTRL-C
  • Start USB DFU gadget for the next file
  • Repeat until all required files are downloaded

Warning

To update the software via USB DFU, the barebox from BSP-Yocto-i.MX6UL-PD19.1.0 or higher is required. If you have an older barebox, you first have to update the barebox with another method.

Updating NAND flash via USB DFU

To update the NAND flash, boot the target and stop the boot process in the bootloader.

Update barebox:

To update the barebox, create a folder for the files to download and start the DFU gadget:

bootloader$ mkdir files
bootloader$ otg.mode=peripheral
bootloader$ dfu /files/barebox.bin(barebox)src

Now the corresponding barebox image can be downloaded from the host:

host$ sudo dfu-util -a barebox -D barebox.bin

After completing the download, stop the DFU gadget on the bootloader by pressing CTRL-C. Then update the barebox with the barebox-update command:

bootloader$ barebox_update -t nand /files/barebox.bin

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

bootloader$ erase /dev/nand0.barebox-environment.bb

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

bootloader$ reset

Update kernel and devicetree:

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

Tip

With BSP-Yocto-i.MX6UL-PD19.1.0 ubiformat does not show a "100% complete" output anymore in certain cases although it finished succesfully. This is caused by a change in implementation which is not harmful. The succesful completion of the ubiformat command can always be checked by analyzing its return code. (target$ echo $?)

Now get the Linux kernel via USB DFU and store it also into the NAND Flash:

bootloader$ mkdir files
bootloader$ otg.mode=peripheral
bootloader$ dfu /files/zImage(kernel)src 

Now the corresponding kernel image can be downloaded from the host:

host$ sudo dfu-util -a kernel -D zImage

After completing the download, stop the DFU gadget on the bootloader by pressing CTRL-C. Update the kernel into NAND flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /files/zImage

Now get the devicetree via USB DFU and store it in the NAND Flash:

bootloader$ dfu /files/oftree(oftree)src 

Now the corresponding kernel image can be downloaded from the host:

host$ sudo dfu-util -a oftree -D <devicetree file name>.dtb

After completing the download, stop the DFU gadget on the bootloader by pressing CTRL-C.

Update the oftree into NAND flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /files/oftree

Update the root filesystem:

The Linux root filesystem can be flashed directly to NAND, use:

bootloader$ dfu /dev/nand0.root.ubi.root(root)r

Now the root filesystem can be downloaded from the host:

host$ sudo dfu-util -a root -D <rootfs file name>.ubifs


Warning

The root filesystem is written directly to the NAND flash. If the download fails, the root filesystem is partially written and can be corrupted.

After completing the download, stop the DFU gadget on the bootloader by pressing CTRL-C. Change the boot configuration of your board to NAND boot, if necessary, and reset your board.

Updating eMMC via USB DFU

To update the eMMC, boot the target and stop the boot process in the bootloader. Configure the USB OTG port as peripheral and start the USB DFU gadget to flash an SDcard image to the eMMC:

bootloader$ otg.mode=peripheral
bootloader$ dfu /dev/mmc1(emmc)r

Now the SDcard image can be downloaded from the host:

host$ sudo dfu-util -a emmc -D <sdcard image name>.sdcard


Warning

The SDcard image is written directly to the eMMC. If the download fails, the eMMC is partially written and can be corrupted.

After completing the download, stop the DFU gadget on the bootloader by pressing CTRL-C. Change the boot configuration of your board to eMMC boot, if necessary, and reset your board.

Updating via USB Fastboot

To update the software with the USB Android fastboot mechanism, the Linuxfastboottool needs to be installed on the host machine. The latest version of fastboot is available from Android SDK Platfrom Tools.  To install it, first uninstall any older version of fastboot from your machine. For example, on Ubuntu run:

host$ sudo apt-get remove android-tools-fastboot

Copy the fastboot binary to /usr/local/bin/:

host$ cp <platform-tools download dir>/fastboot /usr/local/bin


To run fastboot, sudo rights are required or a udev rule needs to be created (see How to write udev rulesAdding udev rules for Android devices). The Android fastboot mechanism works by exporting the devices or files to be updated in the bootloader via the usb composite gadget. Then the corresponding files can be sent from the host with thefastboottool.

The general approach is as follows:

  • Connect the board with the USB OTG port to your host PC
  • Boot to the bootloader and stop the boot process
  • Activate peripheral mode for the USB OTG port
  • Create a folder for downloaded files in case files cannot be copied to a device directly (e.g. barebox.bin which needs to be updated with barebox_update command)
  • Start the usb composite gadget in fastboot mode
  • Runfastboottool on the host to download the files
  • After completion, stop the fastboot gadget on the bootloader withusbgadget -d

Warning

To update the software via USB Android fastboot, the barebox BSP-Yocto-i.MX6UL-PD19.1.0 or higher is required. If you have an older barebox, you first have to update the barebox with another method.

Updating NAND flash via Fastboot

To update the NAND flash, boot the target and stop the boot process in the bootloader. 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

Tip

With BSP-Yocto-i.MX6UL-PD19.1.0 ubiformat does not show a "100% complete" output anymore in certain cases although it finished succesfully. This is caused by a change in implementation which is not harmful. The succesful completion of the ubiformat command can always be checked by analyzing its return code. (target$ echo $?)

Create a temporary folder for the downloaded files and start the USB composite gadget. Also prepare the:

bootloader$ mkdir files
bootloader$ otg.mode=peripheral
bootloader$ usbgadget -A /files/barebox.bin(barebox)src,/files/zImage(kernel)src,/files/oftree(devicetree)src,/dev/nand0.root.ubi.root(rootfs)r

To verify that the fastboot gadget is working correctly run:

host$ fastboot getvar all

The output should look something like:

(bootloader) version: 0.4
(bootloader) bootloader-version: barebox-2019.01.0-bsp-yocto-i.mx6ul-pd1
(bootloader) partition-size:barebox: 00000000
(bootloader) partition-type:barebox: file
(bootloader) partition-size:kernel: 00000000
(bootloader) partition-type:kernel: file
(bootloader) partition-size:devicetree: 00000000
(bootloader) partition-type:devicetree: file
(bootloader) partition-size:rootfs: 1d78a000
(bootloader) partition-type:rootfs: basic
all: 
Finished. Total time: 0.001s

Update barebox:

To update the barebox, run following command on the host system:

host$ fastboot flash barebox barebox.bin

After downloading the barebox image, it can be installed with:

bootloader$ barebox_update -t nand /files/barebox

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

bootloader$ erase /dev/nand0.barebox-environment.bb

To use the newly flashed barebox, the board has to be reset. But since the fastboot gadget is already running, first update the remaing parts of the system.

Update kernel and devicetree:

Download the corresponding kernel image from the host:

host$ fastboot flash kernel zImage

Update the kernel into NAND flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.kernel /files/zImage

Download the corresponding devicetree from the host:

host$ fastboot flash devicetree <devicetree file name>.dtb

Update the devicetree into NAND flash:

bootloader$ ubiupdatevol /dev/nand0.root.ubi.oftree /files/oftree

Update the root filesystem:

The Linux root filesystem can be flashed directly to NAND, use:

host$ fastboot flash rootfs <rootfs file name>.ubifs


Warning

The root filesystem is written directly to the NAND flash. If the download fails, the root filesystem is partially written and can be corrupted.

After completing the download, stop the USB composite gadget on the bootloader with:

bootloader$ usbgadget -d

Change the boot configuration of your board to NAND boot, if necessary, and reset your board.

Updating eMMC via Fastboot

With the current implementation, the maximum transferable filesize is half of the available RAM size that is shown in the barebox bootlog or with:

bootloader$ meminfo

If the .sdcard Image is larger than that, either split it in smaller chunks and update them seperately or use Update eMMC via USB DFU.

Otherwise, follow these steps:

  • To update the eMMC, boot the target and stop the boot process in the bootloader.
  • Configure the USB OTG port as peripheral and start the USB composite gadget to flash an SDcard image to the eMMC:
bootloader$ otg.mode=peripheral
bootloader$ usbgadget -A /dev/mmc1(emmc)r
  • Now the SDcard image can be downloaded from the host:
host$ fastboot flash emmc <sdcard image name>.sdcard


Warning

The SDcard image is written directly to the eMMC. If the download fails, the eMMC is partially written and can be corrupted.

  • After completing the download, stop the USB composite gadget on the bootloader with:
bootloader$ usbgadget -d
  • Change the boot configuration of your board to eMMC boot, if necessary, and reset your board.

Updating the bootloader from Linux Userspace

It is possible to update the barebox bootloader from within the booted Linux userspace. This can only be done if certain specifications have been met.

Updating NAND Flash bootloader from Linux Userspace

To update the barebox on the NAND Flash from within Linux Userspace, the kobs-ng tool is used. It implements the same failsafe update mechanism that is used with the barebox-update tool in the barebox. The following command requires the new barebox image to be copied to the target.

To update the barebox on the target type:

target$ kobs-ng init --search_exponent=1 barebox.bin

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

target$ flash_erase /dev/mtd1 0 0

After a reboot or power cycle, the new barebox will be used.

Updating eMMC bootloader from Linux Userspace

To update the bootloader on the eMMC from within Linux userspace, the dd command is used. This is similar to programming the bootloader to an SD card (see Booting from SD Card).

Some precautions need to be taken when updating the bootloader on the eMMC. The i.MX 6UL/6ULL ROM code expects the bootloader at a specific offset from the beginning of the eMMC. In front of that lies the partitioning table of the filesystem which follows the bootloader. So we have to make sure not to overwrite the partitioning table. Copying the bootloader to the eMMC can be achieved with:

target$ dd if=barebox.bin of=/dev/mmcblk1 bs=512 skip=2 seek=2 conv=fsync

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

target$ dd if=/dev/zero of=/dev/mmcblk0 bs=128k count=1 seek=7

After a reboot or power cycle the new barebox will be used.

RAUC

Since the rocko release, 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 and the example setup used in the BSP.

RAUC on i.MX 6UL/6ULL

With the BSP-Yocto-i.MX6UL-PD19.10 BSP release, RAUC (Robust Auto-Update Controller) can be used with NAND flash. It is not enabled by default but our example can be configured and activated with the instructions shown below. 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.

Warning

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/rauc_init_nand 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$ rauc_init_nand


Warning

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$ rauc_flash_nand_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). Activate bootchooser to use the newly flashed A-B system:

bootloader$ nv boot.default=bootchooser

Now the bootchooser tries to boot the system which is currently marked as active (the one with the higher priority). If it fails to boot that system three consecutive times, it is marked as bad and the bootchooser tries to boot the other system. A system is marked bad when the remaining_attempts are set to 0.

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=phyboard-segin-imx6ul-6
version=r1
description=PHYTEC rauc bundle based on BSP-Yocto-i.MX6UL-PD19.1.0
build=20190521073744
 
[image.rootfs]
sha256=586fe06c3d61ff04023a8cb3ddd6d246f8031ef0a05b1ed25213f7db8897ff2b
size=130023424
filename=phytec-qt5demo-image-phyboard-segin-imx6ul-6.ubifs
 
[image.kernel]
sha256=1a184e5356267277211eb690a151977d5f872b4ae8f0661ac5d963b4e83efdfa
size=6725712
filename=zImage-phyboard-segin-imx6ul-6.bin.img
 
[image.dtb]
sha256=2102512a05e37ba78e8dba06553be2f1c686e85acafbe5efd44e48c554b3f6db
size=34242
filename=imx6ull-phytec-segin-ff-rdk-nand.dtb.img

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

Tip

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-phyboard-segin-imx6ul-6.raucb root@192.168.3.11:/home/root/

On the target, you can verify the bundle:

target$ rauc info phytec-qt5demo-bundle-phyboard-segin-imx6ul-6.raucb

and get output similar to this:

rauc-Message: Reading bundle: /home/root/phytec-qt5demo-bundle-phyboard-segin-imx6ul-6.r
aucb
rauc-Message: Verifying bundle...
Compatible:     'phyboard-segin-imx6ul-6'
Version:        'r0'
Description:    'PHYTEC rauc bundle based on BSP-Yocto-i.MX6UL-PD19.1.0'
Build:          '20190521073744'
Hooks:          ''
3 Images:
(1)     phytec-qt5demo-image-phyboard-segin-imx6ul-6.ubifs
        Slotclass: rootfs
        Checksum:  586fe06c3d61ff04023a8cb3ddd6d246f8031ef0a05b1ed25213f7db8897ff2b
        Size:      130023424
        Hooks:     
(2)     zImage-phyboard-segin-imx6ul-6.bin.img
        Slotclass: kernel
        Checksum:  1a184e5356267277211eb690a151977d5f872b4ae8f0661ac5d963b4e83efdfa
        Size:      6725712
        Hooks:     
(3)     imx6ull-phytec-segin-ff-rdk-nand.dtb.img
        Slotclass: dtb
        Checksum:  2102512a05e37ba78e8dba06553be2f1c686e85acafbe5efd44e48c554b3f6db
        Size:      34242
        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 Development
   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
   Not Before: Jan  1 00:00:00 1970 GMT
   Not After:  Dec 31 23:59:59 9999 GMT
 1 Subject: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Development
   Issuer: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Development
   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
   Not Before: Jan  1 00:00:00 1970 GMT
   Not After:  Dec 31 23:59:59 9999 GMT

To check the current state of the system, run:

target$ rauc status

and get output similar to:

Compatible:  phyboard-segin-imx6ul-6
Variant:     
Booted from: system0
Activated:   rootfs.0 (system0)
slot states:
  dtb.1: class=dtb, device=/dev/ubi0_4, 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=good
  kernel.1: class=kernel, device=/dev/ubi0_3, type=ubivol, bootname=(null)
      state=inactive, description=, parent=rootfs.1, mountpoint=(none)
  rootfs.1: class=rootfs, device=/dev/ubi0_5, type=ubifs, bootname=system1
      state=inactive, description=, parent=(none), mountpoint=(none)
      boot status=good
  kernel.0: class=kernel, device=/dev/ubi0_0, type=ubivol, bootname=(null)
      state=active, description=, parent=rootfs.0, mountpoint=(none)
  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-phyboard-segin-imx6ul-6.raucb

and reboot afterwards:

target$ reboot

Tip

When you update from a USB stick, make sure to remove the stick after a successful update before reboot. If not, an automatic update will be started after each boot. This due to the "Automatic Update from USB Flash Drive example" you can find below.

With success of the 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 automounts 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.

Tip

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-i.MX 6UL/6ULL Evaluation Kits, corresponding to the Yocto machines phyboard-segin-imx6ul-2 and phyboard-segin-imx6ul-6, 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 Customizationchapter in the Yocto reference manual. You have to include the imx6ul-phytec-state.dtsi file to your barebox device tree by adding

#include imx6ul-phytec-state.dtsi

to the includes. Afterwards, rebuild the image

Warning

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.

/ {
        aliases {                                                                
                state = &state;                                                  
        };                                                                       
 
        state: imx6ul_phytec_boot_state {                                        
                magic = <0x883b86a6>;                                            
                compatible = "barebox,state";                                    
                backend-type = "raw";                                            
                backend = <&backend_update_eeprom>;                              
                backend-stridesize = <54>;                                       
                status = "disabled";                                             
 
                #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>;                          
                                };                                               
                                ok {                                             
                                        reg = <0xc 0x4>;                         
                                        type = "uint32";                         
                                        default = <0>;                           
                                };                                               
                        };                                                       
                        system1 {                                                
                                #address-cells = <1>;                            
                                #size-cells = <1>;                               
                                remaining_attempts {                             
                                        reg = <0x10 0x4>;                        
                                        type = "uint32";                         
                                        default = <3>;                           
                                };                                               
                                priority {                                       
                                        reg = <0x14 0x4>;                        
                                        type = "uint32";                         
                                        default = <20>;                          
                                };                                               
                                ok {                                             
                                        reg = <0x18 0x4>;                        
                                        type = "uint32";                         
                                        default = <0>;                           
                                };                                               
                        };                                                       
                };                                                               
        };                                                                       
};
 
&eeprom {                                                                        
        partitions {                                                             
                compatible = "fixed-partitions";                                 
                #size-cells = <1>;                                               
                #address-cells = <1>;                                            
                backend_update_eeprom: state@0 {                                 
                        reg = <0x0 0x100>;                                       
                        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. Also two new boot scripts have to be created for system0 and system1 of the A-B system. To fulfill these requirements, boot your board and stop the boot process in the barebox.

Create the NAND boot script for system0 with:

bootloader$ edit /env/boot/system0

and insert the following to the file:

#!/bin/sh
 
[ -e /env/config-expansions ] && /env/config-expansions
 
[ ! -e /dev/nand0.root.ubi ] && ubiattach /dev/nand0.root
 
global.bootm.image="/dev/nand0.root.ubi.kernel0"
global.bootm.oftree="/dev/nand0.root.ubi.oftree0"
 
global.linux.bootargs.dyn.root="root=ubi0:root0 ubi.mtd=root rootfstype=ubifs"

Write the file by pressing CTRL-D and run:

bootloader$ saveenv

to save the environment. Create the NAND boot script for system1 with:

bootloader$ edit /env/boot/system1

and insert the following to the file:

#!/bin/sh
 
[ -e /env/config-expansions ] && /env/config-expansions
 
[ ! -e /dev/nand0.root.ubi ] && ubiattach /dev/nand0.root
 
global.bootm.image="/dev/nand0.root.ubi.kernel1"
global.bootm.oftree="/dev/nand0.root.ubi.oftree1"
 
global.linux.bootargs.dyn.root="root=ubi0:root1 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=system0
bootloader$ nv bootchooser.system1.boot=system1
bootloader$ nv bootchooser.targets="system0 system1"

To simplify the initial partitioning and update of the NAND flash, two script are used. The /env/bin/rauc_init_nand script is used to format and partition the NAND flash. Create this script:

bootloader$ edit /env/bin/rauc_init_nand

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 kernel0 8M
ubimkvol -t static /dev/nand0.root.ubi oftree0 1M
#For 512MB NANDs (otherwise other partition sizes)
ubimkvol -t dynamic /dev/nand0.root.ubi root0 230M
ubimkvol -t static /dev/nand0.root.ubi kernel1 8M
ubimkvol -t static /dev/nand0.root.ubi oftree1 1M
ubimkvol -t dynamic /dev/nand0.root.ubi root1 230M
ubidetach /dev/nand0.root

Write the file by pressing CTRL-D and run:

bootloader$ saveenv

to save the environment. The /env/bin/rauc_flash_nand_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/rauc_flash_nand_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.kernel0  /mnt/tftp/zImage
ubiupdatevol /dev/nand0.root.ubi.kernel1 /mnt/tftp/zImage
ubiupdatevol /dev/nand0.root.ubi.oftree0 /mnt/tftp/oftree
ubiupdatevol /dev/nand0.root.ubi.oftree1 /mnt/tftp/oftree
# Update rootfs image name as needed
cp /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root0
cp /mnt/tftp/root.ubifs /dev/nand0.root.ubi.root1
ubidetach /dev/nand0.root

Write the file by pressing CTRL-D and run:

bootloader$ saveenv

to save the environment.

Tip

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.

Device Tree (DT)

Introduction

The following text briefly describes 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:
Device Tree Usage

PHYTEC i.MX 6UL/6ULL BSP Device Tree Concept

The following section explains some rules we have defined on how to set up device trees for our i.MX 6 and i.MX 6UL/6ULL SOC based boards.

The device tree files are roughly divided into three layers:

  • the SoC layer
  • the module layer
  • the baseboard layer

This resembles the physical properties of the hardware. For example, the same phyCORE-i.MX 6UL module can be used on the phyBOARD-Segin full featured and the phyBOARD-Segin low cost.

In each layer, multiple device trees include files.

An overview of the device tree hierarchy for the PHYTEC i.MX 6UL/6ULL platforms is shown below.

i.MX 6UL Device Tree Hierarchy

Switching Expansion Boards

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

Here is a simple example on how to enable the imx6ul-phytec-segin-peb-av-02 (Display Expansion Board) on the phyBOARD-Segin using the barebox bootloader. The configuration for any expansion board currently selected can be found in env/config-expansions:

target$ edit /env/config-expansions


#!/bin/sh
#. /env/expansions/imx6ul-phytec-segin-peb-av-02

To enable an expansion board, the corresponding line in the config-expansions file needs to be uncommented.

#!/bin/sh
. /env/expansions/imx6ul-phytec-segin-peb-av-02

config-expansions is called within each bootsource script (/env/boot/*) and will be executed before every boot process. This will cause the barebox to modify the Device Tree before the boot process. Information on which Device Tree nodes are affected by an expansion board can be found in the expansion configuration files.

imx6ul-phytec-segin-peb-av-02:

of_fixup_status /soc/aips-bus@2100000/lcdif@21c8000/
of_fixup_status /soc/aips-bus@2100000/lcdif@21c8000/display@di0
of_fixup_status /backlight
of_fixup_status /soc/aips-bus@2100000/i2c@21a0000/edt-ft5x06@38
of_fixup_status /soc/aips-bus@2000000/pwm@2088000/

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

Handling Different Displays

If you have chosen a display as expansion, you have to select the appropriate display timings in the device tree. Following display timings are already included in the config-expansions:

# imx6ul-phytec-lcd: 7" display
#of_display_timings -S /soc/aips-bus@2100000/lcdif@21c8000/display@di0/display-timings/ETM0700G0EDH6

# imx6ul-phytec-lcd: 5.7" display
#of_display_timings -S /soc/aips-bus@2100000/lcdif@21c8000/display@di0/display-timings/ETMV570G2DHU

# imx6ul-phytec-lcd: 4.3" display
#of_display_timings -S /soc/aips-bus@2100000/lcdif@21c8000/display@di0/display-timings/ETM0430G0DH6

# imx6ul-phytec-lcd: 3.5" display
#of_display_timings -S /soc/aips-bus@2100000/lcdif@21c8000/display@di0/display-timings/ETM0350G0DH6

To select your display, uncomment the of_display_timings -S ... command for your screen size and save the file and environment (saveenv).

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

Example: If you have the imx6ul-phytec-segin-peb-av-02-res board, change the env/config-expansions from:

#!/bin/sh

. /env/expansions/imx6ul-phytec-segin-peb-eval-01
#use this expansion when a capacitive touchscreen is connected
. /env/expansions/imx6ul-phytec-segin-peb-av-02
#use this expansion when a resisitive touchscreen is connected
#. /env/expansions/imx6ul-phytec-segin-peb-av-02-res

to:

#!/bin/sh

. /env/expansions/imx6ul-phytec-segin-peb-eval-01
#use this expansion when a capacitive touchscreen is connected
#. /env/expansions/imx6ul-phytec-segin-peb-av-02
#use this expansion when a resisitive touchscreen is connected
. /env/expansions/imx6ul-phytec-segin-peb-av-02-res

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 loaded memory node at runtime. There is no need to handle different RAM sizes in the device tree. However, there should always be 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 minimum supported size, is added in the imx6ul-phytec-phycore-som.dsti.

Snippet from imx6ul-phytec-phycore-som.dtsi:

        /*
         * Set the minimum memory size here and
         * let the bootloader set the real size.
         */
        memory {
                reg = <0x80000000 0x8000000>;
        };

The memory node is not the only node which is modified by the bootloader. Display and expansion boards nodes can be enabled, whereas the partition table in the kernel device tree is modified by the bootloader. This means it is not possible to use our device trees without modifications with a bootloader other than the barebox bootloader from our unified BSP.

Tip

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

To get a sample barebox configuration type:

barebox$ cat env/boot/mmc  

The output will show something like:

#!/bin/sh
 
[ -e /env/config-expansions ] && /env/config-expansions
 
global.bootm.image="/mnt/mmc/zImage"
global.bootm.oftree="/mnt/mmc/oftree"
global.linux.bootargs.dyn.root="root=/dev/mmcblk0p2 rootflags='data=journal'"

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 i.MX 6UL/6ULL BSP described herein, visit our web page at https://www.phytec.de/produkt/system-on-modules/phycore-imx-6ul-download/#software. Click the corresponding BSP release and look for the article number of your module in the column "Article Number". Finally, look for 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 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 boards can be found in device trees (DT):

linux/arch/arm/boot/dts/*.dts*

In fact, software re-use is one of the most important features of the Linux kernel (especially the ARM implementation), 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 read section PHYTEC i.MX 6UL/6ULL BSP Device Tree Concept to get an understanding of our i.MX 6UL/6ULL BSP device tree model.

The following sections provide an overview of the supported hardware components and their operating system drivers on the i.MX 6UL and i.MX 6ULL platform.

i.MX 6UL/6ULL Pin Muxing

The i.MX 6UL/6ULL SOC contains many peripheral interfaces. In order to reduce package size and lower overall system cost while maintaining maximum functionality, many of the i.MX 6UL/6ULL terminals can be multiplexed to up to eight signal functions. Although there are many combinations of pin multiplexing 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 as many application scenarios as possible for the user.

Please refer to the NXP i.MX 6UL and i.MX 6ULL Reference Manuals for more information about the specific pins and the muxing capabilities:
- for the i.MX 6Ultra Lite:

http://www.nxp.com/docs/en/reference-manual/IMX6ULRM.pdf

- for the i.MX 6ULL:

http://www.nxp.com/docs/en/reference-manual/IMX6ULLRM.pdf

The IO set configuration, also called muxing, is done in the Device Tree. The following is an example of the pin muxing of the UART1 device in imx6ul-phytec-phycore-som.dtsi:

       pinctrl_uart1: uart1grp {
               fsl,pins = <
                       MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX   0x1b0b1
                       MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX   0x1b0b1
               >;
       };

The first part of the string MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX names the pad (PAD_UART1_TX_DATA). The second part of the string (UART1_DCE_TX) is the desired muxing option for this pad. The pad setting value (hex value on the right) is explained in:

linux/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt

In this example, the pad setting value 0x1b0b1 means the pin is configured with: PAD_CTL_HYS, PAD_CTL_SRE_SLOW, PAD_CTL_DSE_40ohm, PAD_CTL_SPEED_MED, PAD_CTL_PUS_100K_UP, PAD_CTL_PUE and PAD_CTL_PKE. For the i.MX 6UL the muxing options are defined in:

linux/arch/arm/boot/dts/imx6ul-pinfunc.h

and for the i.MX 6ULL in:

linux/arch/arm/boot/dts/imx6ull-pinfunc.h

Serial TTYs

The i.MX 6UL/6ULL SOCs provide up to 8 UART units. PHYTEC boards support different numbers of these UART units. The debug UART is configured as 115200 8N1 (115200 baud, 8 data bits, no parity bit, 1 stop bit). The other UARTs will have default settings, which normally will be 9600 baud.

Warning

When using UART7 in combination with the first Ethernet interface (ENET1/FEC1) or when using UART8 in combination with the second Ethernet interface (ENET2/FEC2) the precautions described in following link need to be taken:
How-To use UART7/8 on i.MX6UL

The phyBOARD-Segin uses the UART1 (ttymxc0) as standard console output. From the command line prompt of Linux user space, you can easily check the availability of other UART interfaces with:

target$ echo "test" > /dev/ttymxc4

Be sure that the baudrate 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 ttymxc0 to ttymxc4.

First, get the current parameters with:

target$ stty -F /dev/ttymxc0 -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 the argument for the next command:

target$ stty -F /dev/ttymxc4 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

You can also write both in just one command in order to make it more simple:

target$ stty -F /dev/ttymxc4 $(stty -g < /dev/ttymxc0)

Here is a device tree excerpt from arch/arm/boot/dts/imx6ul-phytec-segin.dtsi:

&iomuxc {
        pinctrl_uart5: uart5grp {                                                
                fsl,pins = <                                                     
                        MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX   0x1b0b1          
                        MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX   0x1b0b1          
                        MX6UL_PAD_GPIO1_IO08__UART5_DCE_RTS     0x1b0b1          
                        MX6UL_PAD_GPIO1_IO09__UART5_DCE_CTS     0x1b0b1          
                >;                                                               
        }; 
};
 
&uart5 {                                                                         
        pinctrl-names = "default";                                               
        pinctrl-0 = <&pinctrl_uart5>;                                            
        uart-has-rtscts;                                                         
        status = "disabled";                                                     
};

RS-485

The phyBOARD-Segin can also provide a RS-485 interface derived from UART5. The following code snippet can be found in the imx6ul-phytec-segin.dtsi and imx6ul-phytec-segin-ff-rdk-nand-rs485.dts.

arch/arm/boot/dts/imx6ul-phytec-segin.dtsi:

&iomuxc {
        pinctrl_uart5: uart5grp {                                                
                fsl,pins = <                                                     
                        MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX   0x1b0b1          
                        MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX   0x1b0b1          
                        MX6UL_PAD_GPIO1_IO08__UART5_DCE_RTS     0x1b0b1          
                        MX6UL_PAD_GPIO1_IO09__UART5_DCE_CTS     0x1b0b1          
                >;                                                               
        }; 
};
 
&uart5 {                                                                         
        pinctrl-names = "default";                                               
        pinctrl-0 = <&pinctrl_uart5>;                                            
        uart-has-rtscts;                                                         
        status = "disabled";                                                     
};

arch/arm/boot/dts/imx6ul-phytec-segin-ff-rdk-nand-rs485.dts:

&uart5 {                                                                         
        rts-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;                                 
        rs485-rts-active-high;                                                   
        linux,rs485-enabled-at-boot-time;                                        
        status = "okay";                                                         
};
 
&iomuxc {                                                                        
        pinctrl_uart5: uart5grp {                                                
                fsl,pins = <                                                     
                        MX6UL_PAD_UART5_TX_DATA__UART5_DCE_TX   0x1b0b1          
                        MX6UL_PAD_UART5_RX_DATA__UART5_DCE_RX   0x1b0b1          
                        MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x1a0b1          
                >;                                                               
        };                                                                       
};

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

Execute:

target$ stty -F /dev/ttymxc4 raw -echo -echoe -echok -echoctl -echoke 115200

Now, you can "echo" and "cat" data to and from /dev/ttymxc4

Network

The Ethernet features provided by our modules and boards vary (e.g.: 1 x 10/100 Mbit on phyBOARD-Segin Low Cost and 2 x 10/100 Mbit on phyBOARD-Segin Full Featured).

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-machine-units/.

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

Here is the device tree excerpt of the first Ethernet interface (eth0) on the phyCORE-i.MX 6UL (arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi):

&fec1 {                                                                          
        pinctrl-names = "default";                                               
        pinctrl-0 = <&pinctrl_enet1>;                                            
        phy-mode = "rmii";                                                       
        phy-handle = <ðphy1>;                                                 
        status = "disabled";                                                     
 
        mdio: mdio {                                                             
                #address-cells = <1>;                                            
                #size-cells = <0>;                                               
 
                ethphy1: ethernet-phy@1 {                                        
                        reg = <1>;                                               
                        interrupt-parent = <&gpio1>;                             
                        interrupts = <2 IRQ_TYPE_LEVEL_LOW>;                     
                        micrel,led-mode = <1>;                                   
                        clocks = <&clks IMX6UL_CLK_ENET_REF>;                    
                        clock-names = "rmii-ref";                                
                        status = "disabled";                                     
                };                                                               
        };                                                                       
};
 
&iomuxc {
	pinctrl_enet1: enet1grp {                                                
                fsl,pins = <                                                     
                        MX6UL_PAD_GPIO1_IO07__ENET1_MDC         0x10010          
                        MX6UL_PAD_GPIO1_IO06__ENET1_MDIO        0x10010          
                        MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN      0x1b0b0          
                        MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER      0x1b0b0          
                        MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0          
                        MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0          
                        MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN      0x1b010          
                        MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b010          
                        MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b010          
                        MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1  0x4001b010       
                        MX6UL_PAD_GPIO1_IO02__GPIO1_IO02        0x17059          
                >;                                                               
        }; 
};

Using the phyBOARD-Segin as a switch

The two ethernet interfaces allow the phyBOARD-Segin to be used as a switch. To activate the switch functionality, linux has to be setup accordingly.

First, enable the "802.1d Ethernet Bridging" support in the kernel configuration:

bridge.cfg
CONFIG_BRIDGE_NETFILTER=m
CONFIG_STP=y
CONFIG_BRIDGE=y
CONFIG_BRIDGE_IGMP_SNOOPING=y
# CONFIG_BRIDGE_VLAN_FILTERING is not set
CONFIG_LLC=y


Kernel configuration can be added as fragments to the linux kernel recipes in yocto. For more information, please refer to Add a Configuration Fragment to a Recipe.

With these configurations, linux will boot with the neccessary functionality to realize the ethernet bridge.

In the next step, the network deamon has to be configured appropriatly. For this, networkd needs to know about the interfaces and their role. Modify the already available eth0 and eth1 interface config files under /lib/systemd/network/ . Comment all options under [Network] and add a Bridge option:

/lib/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
#DHCP=ipv4
#Address=192.168.3.11/24
Bridge=br0


Then, create a netdev configuration file to set up a netdevice that should act as a bridge. The name of the bridge device needs to be referenced from the prior created interface files:

/etc/systemd/network/25-bridge.netdev
[NetDev]
Name=br0
Kind=bridge

Finally, specify the network options for the formerly created netdevice:

/etc/systemd/network/segin-bridge.network
[Match]
Name=br0
 
[Network]
DHCP=ipv4

Restart the network deamon for the changes to take effect:

systemctl restart systemd-networkd.service


CAN Bus

The phyBOARD-Segin-i.MX 6UL 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, for example, known from Ethernet.

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.

Use:

target$ ip link

to see if the interface is up or down. To get the information on can0 (which represents i.MX 6UL’s CAN module FLEXCAN1) (such as bit rate and error counters), type:

target$ ip -d -s link show can0

The information for can0 will look like the following:

2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10
    link/can  promiscuity 595628 
    can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 0 
          bitrate 500000 sample-point 0.866 
          tq 133 prop-seg 6 phase-seg1 6 phase-seg2 2 sjw 1
          flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1
          clock 30000000
          re-started bus-errors arbit-lost error-warn error-pass bus-off
          0          0          0          0          0          0         numtxqueues 595628 numrxqueues 595628 gso_max_size 595628 gso_max_segs 595628 
    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 output contains a standard set of parameters also shown for Ethernet interfaces, so not all of these are necessarily relevant for CAN. The following output parameters contain useful information:

FieldDescription
can0Interface Name
NOARPCAN cannot use ARP protocol
MTUMaximum Transfer Unit
RX packetsNumber of Received Packets
TX packetsNumber of Transmitted Packets
RX bytesNumber of Received Bytes
TX bytesNumber of Transmitted Bytes
errors...Bus Error Statistics

The CAN configuration is done in the systemd configuration file /lib/systemd/system/can0.service. For a persistent change of parameters change the configuration in the BSP under meta-yogurt/recipes-core/systemd/systemd-machine-units/can0.service 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 by default after boot. You can start and stop it using:

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 can0

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

target$ cangen

See cansend --help and candump --help help messages for further information on options and usage. Here is a device tree excerpt for the can interface of the phyBOARD-Segin (arch/arm/boot/dts/imx6ul-phytec-segin.dtsi):

/ {
        reg_can1_en: regulator-can1-en {                                         
                compatible = "regulator-fixed";                                  
                pinctrl-names = "default";                                       
                pinctrl-0 = <&princtrl_flexcan1_en>;                             
                regulator-name = "Can";                                          
                regulator-min-microvolt = <3300000>;                             
                regulator-max-microvolt = <3300000>;                             
                gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>;                              
                enable-active-high;                                              
                status = "disabled";                                             
        };
};
 
&can1 {                                                                           
        pinctrl-names = "default";                                                
        pinctrl-0 = <&pinctrl_flexcan1>;                                          
        xceiver-supply = <®_can1_en>;                                          
        status = "disabled";                                                      
};
 
&iomuxc {
        pinctrl_flexcan1: flexcan1 {                                             
                fsl,pins = <                                                     
                        MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX      0x0b0b0          
                        MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX      0x0b0b0          
                >;                                                               
        }; 
 
        princtrl_flexcan1_en: flexcan1engrp {                                    
                fsl,pins = <                                                     
                        MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02      0x17059          
                >;                                                               
        };
};

MMC/SD Card

All i.MX 6UL/6ULL kits support a slot for Micro Secure Digital Cards to be used as general purpose block devices. These devices can be used in the same way as any other block device.

Warning

These kind of devices are hot pluggable. Nevertheless, you must ensure 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 as:

/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 be handled in a standard manner, e.g the mount and umount command work as expected.

Tip

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 one, 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.

Device tree configuration for the MMC interface in arch/arm/boot/dts/imx6qdl-phytec-segin.dtsi:

&iomuxc {
	pinctrl_usdhc1: usdhc1grp {                                              
                fsl,pins = <                                                     
                        MX6UL_PAD_SD1_CMD__USDHC1_CMD           0x17059          
                        MX6UL_PAD_SD1_CLK__USDHC1_CLK           0x10059          
                        MX6UL_PAD_SD1_DATA0__USDHC1_DATA0       0x17059          
                        MX6UL_PAD_SD1_DATA1__USDHC1_DATA1       0x17059          
                        MX6UL_PAD_SD1_DATA2__USDHC1_DATA2       0x17059          
                        MX6UL_PAD_SD1_DATA3__USDHC1_DATA3       0x17059          
                        MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059          
                >;                                                               
        };
};
 
&usdhc1 {                                                                        
        pinctrl-names = "default";               
        pinctrl-0 = <&pinctrl_usdhc1>;                                                                            
        cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;                                  
        no-1-8-v;                                                                
        keep-power-in-suspend;                                                   
        wakeup-source;                                                           
        status = "disabled";                                                     
};

Resize the ext4 Root Filesystem

parted and resize2fs can be used to expand the root filesystem. The example works for any block device such as eMMC, SD card, or hard disk. Get the current device size (from SD card in this case):

target$ parted -m /dev/mmcblk0 unit B print

The output looks like:

BYT;
/dev/mmcblk0:3991928832B:sd/mmc:512:512:msdos:SD USD:;
1:4194304B:12582911B:8388608B:::lba;
2:12582912B:138412031B:125829120B:ext4::;

Now use the size of device minus one as the new end of the second partition (e.g. 3991928832B):

target$ parted /dev/mmcblk0 resizepart 2 3991928831B

After expanding the partition size, resize the ext4 file system in the partition:

target$ resize2fs /dev/mmcblk0p2

The command's output looks like this:

resize2fs 1.42.9 (28-Dec-2013)
Filesystem at /dev/mmcblk0p2 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 15
The filesystem on /dev/mmcblk0p2 is now 3886080 blocks long.

Increasing the file system size can be done while it is mounted. An on-line resizing operation is performed. However, you can also boot the board from internal memory (NAND or eMMC) and then resize the file system on the SD card partition while it is not mounted.

eMMC Devices

The phyCORE-i.MX 6UL/6ULL, can be populated with an eMMC memory chip as main storage instead of the NAND Flash. eMMC devices contain raw MLC memory cells (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 i.MX 6UL/6ULL 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 mostly relatively short and meant to be read together with the supported version of the JEDEC eMMC standard.

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]
[...]

In the bootloader you can use:

bootloader$ detect mmc1

if the device is not probed yet, then:

bootloader$ mmc_extcsd /dev/mmc1

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 (which depends on the chip), the background operations are not executed periodically which impacts the worst-case read and write latency.

Therefore, the JEDEC Standard version v4.41 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 because 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 user space tool mmc do not support this feature.

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 has taken over and the kernel triggers BKOPS by itself, shut down the system with:

target$ poweroff

and perform a power cycle.

Warning

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 Flashs, 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.

Warning

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 with:

target$ parted -m /dev/mmcblk1 unit B print

You will receive:

BYT;
/dev/mmcblk1:3850371072B:sd/mmc:512:512:msdos:MMC Q2J54A:;

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 = 1832 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:

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 a power cycle

To ensure that the new setting has taken over, shut down the system:

target$ poweroff

and perform a power cycle.

It is recommended that you now verify the settings. First, check the value of ENH_SIZE_MULT which must be 1875968 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 1920991232 Byte = 1832.0 MiB, with:

target$ parted -m /dev/mmcblk1 unit B print


BYT;
/dev/mmcblk1:1920991232B:sd/mmc:512:512:msdos:MMC Q2J54A:;

Now you can flash your new image. Further reference: https://www.micron.com/support/faqs/products/managed-nand/emmc (chapter "What are the enhanced technology features mentioned in JEDEC specification, and what are the benefits?")

eMMC (Boot-)Partitions

An eMMC device already contains four different hardware partitions: user, boot1, boot2 and rpmb.

The user partition is called the User Data Area in the JEDEC standard and is the main storage partition. The partitions boot1 and boot2 can be used to host the bootloader and are more reliable. Which partition the i.MX 6UL/6ULL uses to load the bootloader is controlled by the boot configuration of the eMMC device. The partition rpmb is a small partition and can only be accessed via trusted mechanism.

Furthermore, the user partition can be divided into four user-defined General Purpose Area Partitions. An explanation of this feature exceeds the scope of this document. For further information, see the JEDEC Standard chapter "7.2 Partition Management".

Tip

Do not confuse eMMC partitions with partitions of a DOS MBR, or GPT partition table.

The current PHYTEC BSP does not use the extra partitioning feature of eMMC devices. The barebox is flashed at the beginning of the user partition. The barebox environment is placed at a fix location after the barebox. An MBR partition table is used to create two partitions, a FAT32 boot and ext4 rootfs partition. They are located right after the barebox and the barebox environment. The FAT32 boot partition contains kernel and device tree.

There are two ways to flash the bootloader to one of the two boot partitions and to switch the boot device, either via bootloader or via userspace commands, as shown in the following examples.

1. Via bootloader:

First detect the eMMC if not already done:

bootloader$ detect mmc1

Now, query some information about the eMMC device:

bootloader$ devinfo mmc1

The output will look like:

Host information:
[...]
Parameters:
  boot: disabled (type: enum) (values: "disabled", "boot0", "boot1", "user")
  nt_signature: 3589eae7 (type: uint32)
  probe: 0 (type: bool)

Here the boot partition is currently set to disabled. Next flash the bootloader to the partition boot0:

bootloader$ cp -v /mnt/tftp/barebox.bin /dev/mmc1.boot0

Finally, switch the boot partition to boot0:

bootloader$ mmc1.boot=boot0

2. Via user space commands:

The partitions boot0 and boot1 are read-only by default. To write to them from user space, you have to disable force_ro in the sysfs:

target$ echo 0 > /sys/block/mmcblk1boot0/force_ro

Now, flash the bootloader to partition boot0:

target$ dd if=/tmp/barebox.bin of=/dev/mmcblk1boot0

After that set the boot partition from user space using the mmc tool:

(for 'boot0')

target$ mmc bootpart enable 1 0 /dev/mmcblk1

(for 'boot1')

target$ mmc bootpart enable 2 0 /dev/mmcblk1

(for 'user')

target$ mmc bootpart enable 7 0 /dev/mmcblk1

Currently, the mmc tool does not provide a way to show the current boot partition configuration.

Reliable Write

There are two different Reliable Write options:

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

Tip

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, e.g. ext4 for the journal, and user space applications such as fdisk for 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 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.

Resize the ext4 Root Filesystem

parted and resize2fs can be used to expand the root filesystem. The example works for any block device such as eMMC, SD card, or hard disk. Get the current device size (from eMMC in this case):

target$ parted -m /dev/mmcblk1 unit B print

The output looks like:

BYT;
/dev/mmcblk1:3850371072B:sd/mmc:512:512:msdos:MMC Q2J54A:;
1:4194304B:31457279B:27262976B:fat16::boot, lba;
2:31457280B:418647039B:387189760B:ext4::;

Now use the size of device minus one as the new end of the second partition (e.g. 3850371072B):

target$ parted /dev/mmcblk1 resizepart 2 3850371071B

After expanding the partition size, resize the ext4 file system in the partition:

target$ resize2fs /dev/mmcblk1p2

The command's output looks like this:

resize2fs 1.43.8 (1-Jan-2018)
Filesystem at /dev/mmcblk1p2 is mounted on /; on-line resizing required
old_desc_blocks = 2, new_desc_blocks = 15
The filesystem on /dev/mmcblk1p2 is now 3729408 (1k) blocks long.

Increasing the file system size can be done while it is mounted. An on-line resizing operation is performed. But you can also boot the board from SD card and then resize the file system on the eMMC partition while it is not mounted.

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.

Additional Software in the BSP

In the BSP, you will also find the tool flashbench which allows the user to get the page size and erase block size.

Type:

target$ flashbench -a /dev/mmcblk1 --blocksize=1024 

This will, for example, result in:

align 1073741824	pre 779µs	on 1.21ms	post 768µs	diff 439µs
align 536870912	pre 855µs	on 1.29ms	post 858µs	diff 433µs
align 268435456	pre 846µs	on 1.29ms	post 821µs	diff 454µs
align 134217728	pre 812µs	on 1.25ms	post 822µs	diff 429µs
align 67108864	pre 846µs	on 1.29ms	post 832µs	diff 452µs
align 33554432	pre 830µs	on 1.24ms	post 807µs	diff 422µs
align 16777216	pre 841µs	on 1.26ms	post 842µs	diff 418µs
align 8388608	pre 842µs	on 1.27ms	post 814µs	diff 446µs
align 4194304	pre 838µs	on 1.28ms	post 842µs	diff 436µs
align 2097152	pre 827µs	on 928µs	post 834µs	diff 97.9µs
align 1048576	pre 826µs	on 921µs	post 827µs	diff 94.5µs
align 524288	pre 828µs	on 924µs	post 841µs	diff 89.6µs
align 262144	pre 835µs	on 903µs	post 841µs	diff 65.1µs
align 131072	pre 842µs	on 949µs	post 853µs	diff 101µs
align 65536	pre 854µs	on 959µs	post 858µs	diff 103µs
align 32768	pre 844µs	on 954µs	post 869µs	diff 97.2µs
align 16384	pre 862µs	on 962µs	post 847µs	diff 108µs
align 8192	pre 849µs	on 946µs	post 847µs	diff 98.5µs
align 4096	pre 858µs	on 953µs	post 855µs	diff 96.9µ2s
align 2048	pre 845µs	on 936µs	post 846µs	diff 90.8µs

For an explanation how to interpret the output, see https://git.linaro.org/people/arnd.bergmann/flashbench.git/blob/HEAD:/README#l1

NAND Flash

PHYTEC i.MX 6UL/6ULL 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 General Purpose Media Interface (GPMI) of the i.MX 6Ul/6ULL. The NAND Flash type and size is automatically 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. For more information about UBI file system see http://www.linux-mtd.infradead.org/doc/ubifs.html. Although from Linux user space the NAND flash partitions are available as block devices, it is not recommended to use these block devices but instead, use the UBI file system (see http://www.linux-mtd.infradead.org/doc/general.html#L_mtdblock).

The partitions of the NAND Flash are defined the barebox device tree and the barebox writes the partitions to the kernel device tree before booting. Thus, changing the partitions can to be done either in the barebox device tree, or in the barebox environment. How to modify 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 corresponding board device tree (PHYTEC i.MX 6UL/6ULL BSP Device Tree Concept) in 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 a partition or changing a partition's size.

Here is an example partitioning for the phyBOARD-Segin (arch/arm/dts/imx6ul-phytec-phycore-som.dtsi) in the barebox:

&gpmi { 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_gpmi_nand>;
        nand-on-flash-bbt;
        fsl,no-blockmark-swap;
        status = "okay";
 
        #address-cells = <1>;
        #size-cells = <1>;
 
        partition@0 {
                label = "barebox";
                reg = <0x0 0x400000>;
        };
 
        partition@400000 {
                label = "barebox-environment";
                reg = <0x400000 0x100000>;
        };
 
        partition@500000 {
                label = "root";
                reg = <0x500000 0x0>;
        };
};

GPIOs

PHYTEC boards often have a set of pins especially dedicated as user I/Os. These pins are connected directly to i.MX 6UL/6ULL pins. The processor has organized its GPIOs into five chips (gpiochip0 – gpiochip4) of 32 GPIO lines each. 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> - 1) * 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

The muxing for GPIO Pins can be added by adding or modifying a pinctrl_hog group which is associated directly with the iomux controller of the i.MX 6UL/6ULL. Since the GPIO pins are not related to a specific function which is dedicated to a driver, the muxing should be done in this pinctrl_hog group. Be careful when adding a new pinctrl_hog group since there could already be an existing pinctrl_hog group defined in your devicetree or in any of the included device tree files. In this case, the new group will override the existing one.

Fir example, to add pin 42 of the expansion connector of the phyBOARD-Segin as user GPIO, modify the arch/arm/boot/dts/imx6ul-phytec-segin.dtsi file as shown below:

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog>;
 
 
	pinctrl_hog: hoggrp {
		fsl,pins = <
			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09	0x110a0
		>;
	};
};

For more details about the muxing, see i.MX 6UL/6ULL Pin Muxing.

Warning

Before adding a muxing for a GPIO always check the schematic or hardware manual if the pin is not already in use by another function. Otherwise, this can lead to a muxing conflict and malfunctioning of the respective function.

Keys

With gpio-keys, the Linux kernel can interpret GPIO signals as virtual keyboard events. The phyBOARD-Segin can feature a PEB-EVAL-01 adapter board which contains two buttons from which one can be used with the gpio-keys driver (see table bellow). 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:

To show the available input devices run:

target$ evtest

You will get, for example:

No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      20cc000.snvs:snvs-powerkey
/dev/input/event1:      gpio-keys
Select the device event number [0-1]:

Select input device gpio-keys. Listing the device with cat will print the raw output:

target$ cat /dev/input/event1

The following gpio-keys are already assigned with the phyBOARD-Segin evaluation board:

PAD NameGPIOFunctionDescription
SNVS_TAMPER0GPIO5_00Key PowerButton S2 on PEB-EVAL-01

Warning

As the Button S2 is assigned to the Power Key functionality, pressing this button initiates a powerdown of the baord. A wakeup from this state can only be issued by another press of the Power Key button. This behabior can be prevented by disabling the power key handling of systemd.

The Power Key handling of systemd can be disabled by setting following configuration in /etc/systemd/logind.conf:

HandlePowerKey=ignore

GPIO-Keys configuration in imx6ul-phytec-segin-peb-eval-01.dtsi:

/ {        
        gpio_keys: gpio-keys {                                                   
                compatible = "gpio-key";                                         
                pinctrl-names = "default";                                       
                pinctrl-0 = <&pinctrl_gpio_keys>;                                
                status = "disabled";                                             
                                                                                 
                power {                                                      
                        label = "Power Button";                                     
                        gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;                      
                        linux,code = <KEY_POWER>;                                 
                        gpio-key,wakeup;                                         
                };                                                               
        };
};
 
&iomuxc {                                                                        
        pinctrl_gpio_keys: gpio_keysgrp {                                        
                fsl,pins = <                                                     
                        MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00      0x79             
                >;                                                               
        };

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 phyBOARD-Segin Board:

To get all LEDs available, type:

target$ ls /sys/class/leds 
 mmc0::         mmc1::         phycore-green  user-led1      user-led2

To toogle the LEDs use:

target$ echo 255 > /sys/class/leds/user-led1/brightness

to turn it ON, and:

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

to turn it OFF.

phyBOARD-Segin carrier board:

PAD NameGPIODescription
JTAG_MODGPIO1_10LED1 on PEB-EVAL-01
GPIO1_IO01GPIO1_1LED2 on PEB-EVAL-01

User LED configuration in device tree file arch/arm/boot/dts/imx6ul-phytec-segin-peb-eval-01.dtsi:

&iomuxc {
        pinctrl_user_leds: user_ledsgrp {                                        
                fsl,pins = <                                                     
                        MX6UL_PAD_JTAG_MOD__GPIO1_IO10          0x79             
                        MX6UL_PAD_GPIO1_IO01__GPIO1_IO01        0x79             
                >;                                                               
        };
};
 
/ {
	user_leds: user-leds {                                                   
                compatible = "gpio-leds";                                        
                pinctrl-names = "default";                                       
                pinctrl-0 = <&pinctrl_user_leds>;                                
                status = "disabled";                                             
 
                user-led1 {                                                      
                        gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;                    
                        linux,default-trigger = "gpio";                          
                        default-state = "on";                                    
                };                                                               
 
                user-led2 {                                                      
                        gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;                     
                        linux,default-trigger = "gpio";                          
                        default-state = "on";                                    
                };                                                               
        };
};

I²C Bus

The i.MX 6UL contains four multimaster fast-mode I²C modules called I2C1, I2C2, I2C3 and I2C4. This chapter will describe the basic device usage of some of the I²C devices integrated on our phyBOARD-Segin. General i²C bus master device tree node (arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi):

&i2c1 {                                                                          
        pinctrl-names = "default";                                               
        pinctrl-0 =<&pinctrl_i2c1>;                                              
        clock-frequency = <100000>;                                              
        status = "okay"; 
        /* ... */
};
 
&iomuxc {
        pinctrl_i2c1: i2cgrp {                                                   
                fsl,pins = <                                                     
                        MX6UL_PAD_UART4_TX_DATA__I2C1_SCL       0x4001b8b0       
                        MX6UL_PAD_UART4_RX_DATA__I2C1_SDA       0x4001b8b0       
                >;                                                               
        };
};

EEPROM

It is possible to read and write directly to the device:

/sys/class/i2c-dev/i2c-0/device/0-0052/eeprom

To read and print the first 1024 bytes of the EEPROM as hex number, execute:

target$ dd if=/sys/class/i2c-dev/i2c-0/device/0-0052/eeprom bs=1 count=1024  | hexdump -C

To fill the whole EEPROM with zeros, use:

target$ dd if=/dev/zero of=/sys/class/i2c-dev/i2c-0/device/0-0052/eeprom bs=4096 count=1

This operation takes some time because the EEPROM is relatively slow. Device tree representation, e.g. in phyCORE-i.MX 6UL file arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi:

&i2c1 {
        eeprom@52 {
                compatible = "cat,24c32";
                reg = <0x52>;
        };
};

Tip

With RAUC (as described in RAUC), the EEPROM is used to hold the barebox state information.

RTC

RTCs can be accessed via /dev/rtc*. Because PHYTEC boards often have more than one RTC, there might 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
snvs_rtc 20cc000.snvs:snvs-rtc-lp

Tip

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.

arch/arm/boot/dts/imx6ul-phytec-phycore-som.dtsi:

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

As the time is set according to the value of rtc0 during system boot, rtc0 should always be 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 manpage of hwclock.

Device tree representation of I²C RTC (arch/arm/boot/dts/imx6ul-phytec-segin.dtsi):

&i2c1 {
        i2c_rtc: rtc@68 {                                                        
                pinctrl-names = "default";                                       
                pinctrl-0 = <&pinctrl_rtc_int>;                                  
                compatible = "st,rv4162";                                        
                reg = <0x68>;                                                    
                interrupt-parent = <&gpio5>;                                     
                interrupts = <1 IRQ_TYPE_LEVEL_LOW>;                             
                status = "disabled";                                             
        };
};
 
&iomuxc {
        pinctrl_rtc_int: rtcintgrp {                                             
                fsl,pins = <                                                     
                        MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01      0x17059          
                >;                                                               
        }; 
};

Capacitive Touchscreen

The capacitive touchscreen is a part of the display module. For a simple test of this feature, start evtest:

target$ evtest

USB Host Controller

The USB controller of the i.MX 6UL 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 controller cores. Both are On-The-Go (OTG) controller cores but on the phyBOARD-Segin one of them is used as a host only port.

The phyBOARD-Segin i.MX 6UL BSP includes support for mass storage devices, keyboards, and mice. Other USB related device drivers must be enabled in the kernel configuration on demand. Due to udev, all mass storage devices connected 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.

Device tree configuration of USB on the phyBOARD-Segin (arch/arm/boot/dts/imx6ul-phytec-segin.dtsi):

&iomuxc {
        pinctrl_usb_otg1_id: usbotg1idgrp {                                      
                fsl,pins = <                                                     
                        MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID    0x17059          
                >;                                                               
        };
};
 
&usbotg1 {                                                                       
        pinctrl-names = "default";                                               
        pinctrl-0 = <&pinctrl_usb_otg1_id>;                                      
        dr_mode = "otg";                                                         
        status = "disabled";                                                     
};                                                                               
 
&usbotg2 {                                                                       
        dr_mode = "host";                                                        
        disable-over-current;                                                    
        status = "disabled";                                                     
};

USB Host in Barebox

The USB host port on the PHYTEC phyBOARD-Segin is supported in the barebox to connect mass storage devices like USB sticks. To access it, it has to be detected first:

barebox$ detect -a 

This detects all available devices (including the USB devices) When a mass storage device is detected a disk# device is created in /dev/, where partitions can be mounted using:

barebox$ mkdir /mnt/usb
barebox$ mount /dev/disk<X>.<Y> /mnt/usb

where <X> is the disk number associated with the mass storage device and <Y> the numbering of the partition on the device. These can vary depending on the number of disks and partitions.

USB OTG

Most PHYTEC boards provide an USB OTG interface. USB OTG ports automatically act as USB device, or USB host. The mode depends on the USB hardware attached to the USB OTG port. If, for example, an USB mass storage device is attached to the USB OTG port, the device will show up as /dev/sda.

USB OTG in barebox

To be able to use a USB OTG port in the barebox either as Host or Device it first has to be assigned a role. This is due to the fact that there is no mechanism in the barebox for auto detecting the role. First of all the available roles can be listed with:

bootloader$ devinfo otg

Set the role as Host:

bootloader$ otg.mode=host

Set the role as Device:

bootloader$ otg.mode=peripheral

Tip

Once the role is set it cannot be changed except after a reset.

USB Device

In order to connect the board's 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.

target$ modprobe libcomposite

Example:

First, define the parameters such as the USB vendor and product IDs and set the information strings for the English (0x409) language:

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.usb0
target$ mkdir functions/mass_storage.0
target$ echo /tmp/file.img > functions/mass_storage.0/lun.0/file

- acm: Serial gadget, creates serial interface like /dev/ttyGS0.
- ecm: Ethernet gadget, creates 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 with:

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/
ci_hdrc.0
target$ echo "ci_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

Audio

On PHYTEC phyBOARD-Segin, the TI TLV320AIC3007 audio codec is used.

Warning

With the current BSP Release (BSP-Yocto-i.MX6UL-PD19.1.0) Audio recording with the TLV320A is broken.

Audio support is done via the I2S interface and controlled via I2C.

Tip

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 -L

Use scp to copy a WAV file to the board and play it through the sound interface:

target$ aplay -vv file.wav

Not all WAV formats are supported by the sound interface. Use Audacity on your host to convert any file into 44100:S16_LE WAV 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 441000 -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, e.g. you a have a notification app which makes a beep every now and then, plus you have a browser running 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, however, not currently installed per default.

Audio Sources and Sinks

The phyBOARD-Segin has pins to connect two jacks for line in and line out. 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 many more channels than fit onto one screen, so they will scroll if your cursor reaches the right or left edge. In case you get trouble in the display during scrolling, please use ssh instead of microcom. You can quitalsamixer 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 uses Line In as a 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.

Warning

There is a known error that you need to choose Playback screen (F3) instead of Capture screen (F4) for accessing 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 again using CTRL-C.

Video

Although the i.MX 6UL features a Pixel Processing Pipeline (PXP) which can take over some parts of the process of displaying videos in hardware like scaling, color space conversion alpha-blending or roation (for more information, see the i.MX 6 Reference Manual) it can't be used for video playback right now since there is no Linux mainline driver available.

Videos can still be played with Gstreamer but all conversions are done in software.

Videos with Gstreamer without PXP support

The following example uses decodebin for a VP8 encoded video and fbdevsink as video sink. The video is installed by default in the BSP:

target$ gst-launch-1.0 filesrc location=/usr/share/phytec-qtdemo/videos/caminandes.webm ! decodebin ! videoconvert ! fbdevsink sync=false

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:

fbtest

This will show various pictures on the display. Information about the framebuffer's resolution can be obtained with:

fbset

which will return:

mode "800x480-60"
        # D: 33.265 MHz, H: 31.501 kHz, V: 60.001 Hz
        geometry 800 480 800 480 32
        timings 30062 88 40 33 10 128 2
        accel false
        rgba 8/16,8/8,8/0,0/0
endmode

Tip

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. You can also refer to the manual of your display driver for more details.

Below, you will find some more useful commands. To query the color depth of the framebuffer emulation, type:

target$ cat /sys/class/graphics/fb0/bits_per_pixel

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. Read the appropriate files, and write to them to control the backlight. Type:

target$ cat /sys/class/backlight/backlight/max_brightness

to query the max brightness level, for example:

7

Valid brightness values are 0 to <max_brightness>.

target$ cat /sys/class/backlight/backlight/brightness

will show the current brightness level in the driver, for example:

2


target$ echo 0 > /sys/class/backlight/backlight/brightness

Set brightness to zero. The backlight is turned off.

target$ echo 6 > /sys/class/backlight/backlight/brightness

Set brightness to the second highest brightness level. For documentation of all files, see https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight.

Resistive Touchscreens

Most of the PHYTEC boards support connecting a resistive touchscreen which requires tslib support. Calibration of the touchscreen can be done by executing:

target$ ts_calibrate

Touchscreen can be tested by executing:

target$ ts_test

CPU Core Frequency Scaling

The CPU in the i.MX 6UL/6ULL SOC is able to scale the clock frequency and the voltage. This is used to save power when the full performance of the CPU is not needed. Scaling the frequency and the voltage is referred to as 'Dynamic Voltage and Frequency Scaling' (DVFS). The i.MX 6UL/6ULL 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.

To get a complete list of the available frequencies type:

target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

In case you have, for example, an i.MX 6ULL CPU with a maximum of 792 MHz the result will be:

198000 396000 528000 792000

The voltages are scaled according to the setup of the frequencies in the device tree. You can decrease the maximum frequency (e.g. to 396000),

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

or increase the minimum frequency (e.g. to 396000)

target$ echo 396000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq

To check the current frequency, type:

target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

The frequency governors automatically select one of the available frequencies in accordance with their goals. List all governors available with the following command:

target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

The result will be:

conservative userspace powersave ondemand performance
  • ondemand (default) switches between possible CPU core frequencies in reference to the current system load. When the system load increases above a specific limit, it increases the CPU core frequency immediately.
  • 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.
  • powersave always selects the lowest possible CPU core frequency.
  • performance always selects the highest possible CPU core frequency.
  • userspace allows the user or user space program running as root to set a specific frequency (e.g. to 396000). Type:
target$ echo 396000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

In order to ask for the current governor, type:

target$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

You will normally get:

ondemand

Switching over to another governor (e.g. userspace) is done with:

target$ echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

For more detailed information about the governors refer to the Linux kernel documentation in: linux/Documentation/cpu-freq/governors.txt.

Thermal Management

The Linux kernel has an integrated thermal management which is capable of monitoring SOC temperatures, reducing the CPU frequency, driving fans, advising other drivers to reduce the power consumption of devices, and – in the worst case – shut down the system quickly and safely (https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt).

This section describes how the thermal management kernel API can be used to monitor the i.MX 6UL SOC temperature. The i.MX 6UL has an internal temperature sensor for the SOC ("Temperature Monitor (TEMPMON)" in the i.MX 6UL/6ULL Reference Manual). The current temperature can be read in millicelsius with:

target$ cat /sys/class/thermal/thermal_zone0/temp

You will get, for example:

77535

which meets a temperature of 77,535 °C.

There are two trip points registered by the imx_thermal kernel driver:

  1. A passive trip point where the temperature is set to 10 °C below the maximum allowed temperature of the SOC.
  2. A critical trip point where the temperature is set to 5 °C below the maximum allowed temperature of the SOC.

(see kernel sysfs folder /sys/class/thermal/thermal_zone0/)

So for instance with the industrial temperature grade of the i.MX 6UL/6ULL, the following trip points are registered:

  • passive: 95 °C
  • critical: 100 °C

These trip points are used by the kernel thermal management to trigger events and change the cooling behavior. The events and cooling behavior depend on the thermal policy that is used. The following thermal policies (also named thermal governors) are available in the kernel:
Step Wise, Fair Share, Bang Bang, and User space.

The thermal policy used in this BSP is step_wise.

If the SoC temperature rises above the passive trip point, the maximum available CPU frequency is reduced step wise. If the temperature then drops under the passive trip point temperature again, the frequency throttling is released. If the SoC temperature reaches the critical trip point temperature, the thermal management of the kernel shuts down the systems. On the serial console you can see:

kernel[194]: [ 895.524255] thermal thermal_zone0: critical temperature reached(100 C),shutting down

[ OK ] Stopped target Sound Card.
[ OK ] Stopped target System Time Synchronized.
[ OK ] Stopped target Network. Stopping Autostart Qt 5 Demo...
[...] 

Watchdog

The PHYTEC i.MX 6UL/6ULL SOCs include a hardware watchdog which is able to reset the board when the system hangs. This chapter will explain how to enable the watchdog in the barebox to monitor a kernel boot and how to enable the watchdog in Linux using systemd to check for system hangs and during reboot. By default, the watchdog is disabled in barebox and Linux.

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 with:

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 systemd

Systemd has included 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

Tip

If the watchdog is enabled in the barebox it continues running in Linux so there is no need to also enable it with systemd

WLAN Modules

Supported Wi-Fi Modules and Software

Two modules are supported by the i.MX 6UL BSP:

  • PEB-WLBT-01 expansion board equipped with the TiWi-BLE Wi-Fi module.
  • PEB-WLBT-05 expansion board equipped with the Sterling-LWB module (PD19.1.1 or later).

Both can be used in client and Access Point (AP) mode using WEP, WPA and WPA2 encryption. For further information regarding the modules, look at the following links:

Currently, PEB-WLBT-01 and PEB-WLBT-05 are not supported together on the same BSP. By default, the support for PEB-WLBT-01 expansion board is configured to be build in the BSP. For guidance on how to switch the support between these modules, please refer to PEB-WLBT-05.

TiWi-BLE (PEB-WLBT-01) 

The BSP uses the most current firmware from the linux-firmware repository.

git://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.

Tip

We use 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 BSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.Ax) Head#Calibration(chapter 2.2) for more information.

Sterling-LWB (PEB-WLBT-05)

The PEB-WLBT-05 is only supported on BSP version PD19.1.1 and later.

Currently, the used Wi-Fi driver does not support the Sterling-LWB module. To add the support on the phyBOARD-Segin, Wi-Fi drivers with Sterling-LWB support are needed to be backported. A backport driver is provided by LairdConnectivity and can be found on their GitHub page:

https://github.com/LairdCP/Sterling-LWB-and-LWB5-Release-Packages/releases/download/LRD-REL-7.0.0.326/backports-laird-7.0.0.326.tar.bz2

The firmware to be flashed in the Sterling-LWB module is also provided by LairdConnectivity and can be found in the Phytec-FTP server:

ftp://ftp.phytec.de/pub/Software/Linux/Driver/Sterling-bcm43430_v1.1.zip

The provided firmware binaries are:

4343w.hcd
brcmfmac43430-sdio.txt
brcmfmac43430-sdio.bin
brcmfmac43430-sdio.clm_blob

As the backport drivers are not built-in, they have to be built as modules and added manually to the BSP. In order to do this, the Wi-Fi drivers have to be completely deactivated from the kernel configuration. This whole process is automated, so just one option needs to be set to trigger the build of the new BSP with Sterling-LWB support.

To add the backport drivers to the build, perform the following steps:

  • In your Yocto build-directory, uncomment the following line:
<Yocto_build_dir>/conf/local.conf
STERLING_LWB_BACKPORT = "1"
  • Start the build process from your build directory
<Yocto_build_dir>/
$ bitbake phytec-headless-image

For more information on how to build images with Yocto, refer to Start the Build.

Enable Wi-Fi Expansion Boards

To enable the Wi-Fi expansion board on the phyBOARD-Segin, perform the following steps:

  • Start the board and stop in the bootloader shell.
  • Edit the file /env/config-expansion with:
bootloader$ edit /env/config-expansions
  • In the file, remove the '#' character in the line:
. /env/expansions/imx6ul-phytec-peb-wlbt-01
  • In case of PEB-WLBT-05, remove the preceeding '#' in this line, instead:
. /env/expansions/imx6ul-phytec-peb-wlbt-05
  • Press CTRL+D and save the environment with:
bootloader$ saveenv
  • Reboot the board:
bootloader$ reset
  • After enabling the Wi-Fi module on the PEB-WLBT-01 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
  • It can be easily checked with:
target $ dmesg | grep wl
  • The output of  PEB-WLBT-05 differs from the PEB-WLBT-01. The console output should look like:
Loading modules backported from Laird Linux version LRD-REL-7.0.0.326-0-gb1ee9b1eb665
Backport generated by backports.git v7.0.0.326
brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43430-sdio for chip BCM43430/1
brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM43430/1 wl0: Sep 11 2018 09:22:09 version 7.45.98.65 (r707797 CY) FWID 01-b54727f


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. 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 and 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 also described in:

http://processors.wiki.ti.com/index.php/WL12xx_NLCP_Calibration_Process
http://linuxwireless.org/en/users/Drivers/wl12xx/calibrator/#wl12xx_Calibration

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

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

The calibrator version used is 0.80. Before starting the calibration, the WiFi module has to be set to PLT mode. To do this, 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 configuration and F9 to leave. Rebuild the kernel:

<yocto_dir>/build$ bitbake phytec-headless-image

Flash the new BSP image to the board (see section BSP Reference Manual - phyCORE-i.MX 6UL/ULL (L-844e.Ax) Head#Updating the Software) and reboot the module. To start the calibration, first generate an 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$ 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


Tip

Remove the NL80211_TESTMODE config before shipping the BSP.

Bluetooth

Bluetooth support comes only with PEB-WLBT-05 expansion module. For information about the module, refer to section PEB-WLBT-05.

The bluetooth is connected via the UART2 interface. More information about the module can be found at https://connectivity-staging.s3.us-east-2.amazonaws.com/2019-09/CS-DS-SterlingLWB%20v7_2.pdf. The firmware will not be selected from the Linux kernel automatically. To use bluetooth, the needed firmware has to be loaded manually:

target$ brcm_patchram_plus -d --patchram /lib/firmware/brcm/4343w.hcd --enable_hci --no2bytes --tosleep 1000 /dev/ttymxc1 &
[1] 3623
option patchram with arg /lib/firmware/brcm/4343w.hcd
option enable_hci
option no2bytes
option tosleep with arg 1000
/dev/ttymxc1 
writing 
01 03 0c 00 
received 7
04 0e 04 01 03 0c 00 
writing
01 2e fc 00  
received 7
04 0e 04 01 2e fc 00 
writing
01 4c fc 46 10 18 21 00 42 52 43 4d 63 66 67 53 
00 00 00 00 32 00 00 00 01 01 04 18 92 00 00 00 
03 06 ac 1f 12 a1 43 43 00 01 1c 52 18 21 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 fe 00 00 
...
received 7
04 0e 04 01 4c fc 00 
writing
01 4e fc 04 ff ff ff ff 
received 7
04 0e 04 01 4e fc 00 
writing
01 03 0c 00 
received 7
04 0e 04 01 03 0c 00 
Done setting line discpline
 
target$ hciconfig
 
hci0:   Type: Primary  Bus: UART
        BD Address: 00:25:CA:35:52:88  ACL MTU: 1021:8  SCO MTU: 64:1
        DOWN 
        RX bytes:668 acl:0 sco:0 events:34 errors:0
        TX bytes:423 acl:0 sco:0 commands:34 errors:0
 
target$ hciconfig hci0 up
 
target$ hciconfig
 
hci0:   Type: Primary  Bus: UART
        BD Address: 00:25:CA:35:52:88  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING PSCAN 
        RX bytes:1378 acl:0 sco:0 events:74 errors:0
        TX bytes:1186 acl:0 sco:0 commands:74 errors:0
 
target$ hciconfig -a
 
hci0:   Type: Primary  Bus: UART
        BD Address: 00:25:CA:35:52:88  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING PSCAN 
        RX bytes:1378 acl:8 sco:0 events:74 errors:0
        TX bytes:1186 acl:8 sco:0 commands:74 errors:0
        Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
        Link policy: RSWITCH SNIFF 
        Link mode: SLAVE ACCEPT 
        Name: 'BlueZ 5.48'
        Class: 0x000000
        Service Classes: Unspecified
        Device Class: Miscellaneous, 
        HCI Version: 4.1 (0x7)  Revision: 0x60
        LMP Version: 4.1 (0x7)  Subversion: 0x2209
        Manufacturer: Broadcom Corporation (15)

Now you can scan your environment for visible bluetooth devices. Bluetooth is not visible during a default startup.

target$ hcitool scan
Scanning ...
       XX:XX:XX:XX:XX:XX       <SSID>

Visibility

To activate visibility:

target$ hciconfig hciX piscan

To disable visibility:

target$ hciconfig hciX noscan

Adapt bluetooth settings

To change the name of the hci device:

target$ hciconfig hci0 name <name>

To change the device class of the bluetooth device:

target$ hciconfig hci0 class <hexzahl>

Connect

With the bluetoothctl-tool it is also possible to interactively configure the bluetooth device. The following operations can be performed to connect with external bluetooth devices:

target$ bluetoothctl
[bluetooth]# discoverable on
Changing discoverable on succeeded
[bluetooth]# pairable on
Changing pairable on succeeded
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent 
Default agent request successful
[bluetooth]# scan on
[NEW] Device XX:XX:XX:XX:XX:XX <name>
[bluetooth]# connect XX:XX:XX:XX:XX:XX

Note

To use Bluetooth-functionality, an already configured PAD has to be reconfigured, resulting in the loss of the former functionality. Activating the PEB-WLBT-05 from within the barebox as described in Enable Wi-Fi Expansion Boards section on the same time disables LED functionality, showed in LEDS.

On-Chip OTP Controller (OCOTP_CTRL) - eFuses

The i.MX 6UL/6ULL provides one-time programmable fuses to store information such as the MAC address, boot configuration, and other permanent settings (On-Chip OTP Controller or OCOTP_CTRL in the i.MX 6UL/6ULL Reference Manual). The following list is an abstract from the i.MX 6UL Reference Manual and includes some useful fuse registers in the OCOTP_CTRL (at base address 0x21BC000):

NameADDRMemory offset to 0x21BC000/dev/imx-ocotpDescription
OCOTP_CFG40x050x4500x14contains BOOT_CFG[1,2,3,4]. Transferred to register SRC_SBMR1 0x20D8004
OCOTP_CFG50x060x4600x18contains BT_FUSE_SEL at the fifths bit. Some bits are transferred to register SRC_SBMR2 0x20D801C
OCOTP_MAC00x220x6200x88contains bits 16-47 of MAC_ADDR1
OCOTP_MAC10x230x6300x8Ccontains bits 32-47 of MAC_ADDR2 and bits 0-15 of MAC_ADDR1
OCOTP_MAC0x240x6400x90contains bits 0-31 of MAC_ADDR2
OCOTP_GP10x260x6600x98general purpose register 1
OCOTP_GP20x270x6700x9Cgeneral purpose register 1

A complete list and a detailed mapping between the fuses in the OCOTP_CTRL and the boot/mac/... configuration is available in section "Fusemap" of the i.MX 6UL/6ULL Reference Manual.

Reading Fuse Values in Barebox

You can read the content of a fuse using memory mapped shadow registers. To calculate the memory address, use the fuse address ADDR (0x01-0x2F) in the following formula:

memory address = 0x21BC400 + <ADDR> * 0x10 

In the barebox, use md to read the value. Examples:

bootloader$ md 0x21BC450+4

reads OCOTP_CFG4: ADDR 0x05

bootloader$ md 0x21BC460+4

reads OCOTP_CFG5: ADDR 0x06

bootloader$ md 0x21BC620+4

reads OCOTP_MAC0: ADDR 0x22

bootloader$ md 0x21BC630+4

reads OCOTP_MAC1: ADDR 0x23

bootloader$ md 0x21BC640+4

reads OCOTP_MAC1: ADDR 0x24

Burning Boot Configuration Fuses

Warning

Fuses can only be written once! You can brick your board easily by burning an incorrect boot configuration. It cannot be reversed!

Execute the following commands on the barebox prompt to burn the BOOT_CFG1-4 values and enable reading the boot configuration from fuses. To select a boot device of your choice, replace the BOOT_CFG1-4 value with the appropriate value for your boot device (eMMC, SD, SPI, NAND, etc.). First, enable write to fuses with:

bootloader$ ocotp0.permanent_write_enable=1

Check the values:

bootloader$ devinfo ocotp0

Finally, burn the fuses:

bootloader$ mw -l -d /dev/imx-ocotp 0x14 0x00000093

writes OCOTP_CFG4: BOOT_CFG1-4 Here: NAND 4Gbit (512MByte) 64 pages per block (replace with the actual boot config of your board).

bootloader$ mw -l -d /dev/imx-ocotp 0x18 0x00000010    

writes OCOTP_CFG5: Set bit BT_FUSE_SEL

Here is a short overview of different BOOT_CFG1-4 values valid for the phyCORE-i.MX 6UL and phyCORE-i.MX 6ULL:

SRC_SBMR1 Register (0x20D8004)Module and Boot configuration
0x00000092NAND 1 Gbit (128 MByte) (64 pages per block, 4 address bytes)
0x00000093NAND 4 Gbit (512 MByte) (64 pages per block, 5 address bytes)
0x00002042SD Card on usdhc1
0x00004860eMMC on usdhc2

It is possible to read out a valid boot configuration from a board instead of deriving it from the i.MX 6UL/6ULL Reference Manual.

Boot the board from the boot source you want to configure in the fuses. Press any key to stop autoboot and execute:

bootloader$ md 0x20D8004+4
020d8004: 00000093

The command has read the value of register SRC_SBMR1 (here 0x00000093) which represents the boot configuration BOOT_CFG1-4 and can be written to the fuse register OCOTP_CFG4 as described above.

Burning MAC Address

Warning

Fuses can only be written once! You can brick your board easily, e.g. by burning a wrong boot configuration. It cannot be reversed!

To burn the MAC address, you do not have to blow the two fuse registers (OCOTP_MAC0 and OCOTP_MAC1) manually. The barebox ocotp driver has a special command for that. The following sequence shows how to use it.

Tip

Replace the dummy MAC address in the following commands with a valid MAC address from your pool of addresses. For boards with only one ethernet port (like the low cost phyBOARD-Segin), only ocotp0.mac_addr0 is available and can be changed. ocotp0.mac_addr is deprecated but still available for compatibility. It addresses the same MAC address as ocotp0.mac_addr0.

First, enable write to fuses with:

bootloader$ ocotp0.permanent_write_enable=1

Then, check values:

bootloader$ devinfo ocotp0

Finally, burn the MAC address:

bootloader$ ocotp0.mac_addr0=22:33:44:55:66:77
bootloader$ ocotp0.mac_addr1=22:33:44:55:66:78

When burning a mac address with X116, the first byte will create a multicast address! This one is not assignable as ip address.

Customizing the BSP

Changing MTD Partitions

For Memory Technology Devices (MTD) like 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 of these parts need to be touched. 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
4M(barebox),1M(barebox-environment),507M(root)

To overwrite the partitions, change the partitions variable:

bootloader$ nand0.partitions=1M(barebox),128k(barebox-environment),128k(oftree),5104k(kernel)

Adding and deleting partitions by overwriting the partitions variable is possible. But DO NOT touch the barebox and bareboxenv partitions. These MUST NOT be changed at runtime.