Main intention of this repository is to produce a reference system for TI AM64x product evaluation. Automatic binary releases are available on our website for download.
AM64x SoM and Carriers currently ship without OS or Bootloader preinstalled. Please download the latest binary release from
If no operating system was installed, please download the latest binary release from our website. Choose between Debian / Buildroot, annd pick the appropriate silicon revision ("sr1" / "sr2" suffix) matching your SoM. Note: SKU "SRT6442W00D01GE008V11I0" is Silicon 1.0 ("sr1"). Then follow the steps in section "Deploying -> to microSD".
Before power-on, ensure that the Board has been configured to boot from microSD according to this table
After flashing a microSD and booting into Linux, the serial console must be used for logging into the root account for the first time. Simply enter "root" and press return:
Welcome to Buildroot
buildroot login: root
#
To log in via SSH, an ssh key must be installed first. Copy your favourite public key, e.g. from ~/.ssh/id_ed25519.pub
, into a new file in the root users home directory at ~/.ssh/authorized_keys
:
# mkdir .ssh
# cat > .ssh/authorized_keys << EOF
ssh-ed25519 AAAAinsertyour pubkey@here
EOF
After network configuration ssh root@<ip>
can be used for logging in remotely.
After flashing an SD-Card or eMMC, the root filesystem is small and does not fill the complete disk. To utilize all space, resize both the rootfs partition - and then the filesystem:
Note:
mmcblk0
is eMMC, rootfs is on partition #1mmcblk1
is microSD, rootfs is on partition #2 Adapt instructions below accordingly.
-
inspect partitions:
Using fdisk, view the current partitions. Take note of the start sector ("StartLBA") for partition 2!
# fdisk /dev/mmcblk1 The number of cylinders for this disk is set to 243096. There is nothing wrong with that, but this is larger than 1024, and could in certain setups cause problems with: 1) software that runs at boot time (e.g., old versions of LILO) 2) booting and partitioning software from other OSs (e.g., DOS FDISK, OS/2 FDISK) Command (m for help): p Disk /dev/mmcblk1: 15 GB, 15931539456 bytes, 31116288 sectors 243096 cylinders, 4 heads, 32 sectors/track Units: sectors of 1 * 512 = 512 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 * 16,0,1 127,3,32 2048 16383 14336 7168K c Win95 FAT32 (LBA) /dev/mmcblk1p2 * 128,0,1 1023,3,32 16384 409600 393217 192M 83 Linux Command (m for help):
-
resize partition 2:
Drop and re-create partition 2 at the same starting sector noted before, keeping the "Boot" flag active. If prompted, do not remove the ext4 signature:
Command (m for help): d Partition number (1-4): 2 Command (m for help): n Partition type p primary partition (1-4) e extended p Partition number (1-4): 2 First sector (32-31116287, default 32): 16384 Last sector or +size{,K,M,G,T} (16384-31116287, default 31116287): Using default value 31116287 Command (m for help): a Partition number (1-4): 2 Command (m for help): p Disk /dev/mmcblk1: 15 GB, 15931539456 bytes, 31116288 sectors 243096 cylinders, 4 heads, 32 sectors/track Units: sectors of 1 * 512 = 512 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 * 16,0,1 127,3,32 2048 16383 14336 7168K c Win95 FAT32 (LBA) /dev/mmcblk1p2 * 128,0,1 1023,3,32 16384 31116287 31099904 14.8G 83 Linux Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table fdisk: WARNING: rereading partition table failed, kernel still uses old table: Device or resource busy
-
If fdisk finished with the warning line above, reboot the device:
reboot
If there was no warning, or after reboot completed - proceed to step 4.
-
resize root filesystem:
Linux supports online-resizing for the ext4 filesystem. Invoke
resize2fs
on partition 2 to do so:# resize2fs /dev/mmcblk1p2
The basic images include only a small number of kernel modules required for basic operation.
A package including all modules is generated as part of the build (build/linux-<hash>.tar
) and available for download on our website.
Ensure sufficient free space on rootfs - 300MB should be sufficient, then unpack to /
:
tar -C / -xf linux-<hash>.tar
sync
In order to create a bootable SD card, plug in a micro SD into your machine and run the following, where sdX is the location of the SD card got probed into your machine -
umount /media/<relevant directory>
sudo dd if=output/microsd-<hash>.img of=/dev/sdX
The build process generates special rootfs images for deployment on the eMMC main (data) partition: output/emmc-<hash>.img
Binary releases are available on our website for download.
-
Boot into Linux on the target system, e.g. using SD Card
-
Download, or copy eMMC image to the target system (
wget
,scp
, ...) -
Decompress image if necessary (e.g. if downloaded from our website):
xz -d emmc-<hash>.img.xz
-
Write (uncompressed) image to eMMC:
dd if=emmc-<hash>.img of=/dev/mmcblk0 bs=4M conv=fsync
This table indicates valid boot-modes selectable via the DIP switch S1 on the HummingBoard-T Carrier. The value 0 indicates OFF, 1 indicates the ON state and X indicates don't care.
Switch | 1 | 2 | 3 | 4 | 5 | 6 | Notes |
---|---|---|---|---|---|---|---|
microSD (FAT partition) | 0 | 0 | 0 | 1 | 0 | 1 | |
microSD (RAW) | 1 | 0 | 0 | 0 | 1 | 1 | |
eMMC | 1 | 0 | 0 | 1 | X | X | |
UART | 1 | 1 | 1 | 0 | X | X | DNP SoM R175 |
HummingBoard-T has 3x RJ45 interfaces that can be independently controlled by Linux: eth0
, eth1
, eth2
.
The standard linux tools such as ifconfig
(legacy) and ip
can be used to configure the network.
Examples:
-
enable link:
ip link set dev eth0 up
-
acquire IP address by DHCP
udhcpc -i eth0
-
set a static IP & default Gateway
ip addr add dev eth0 192.168.0.2/24 ip route add default via 192.168.0.1 dev eth0
The HummingBoard-T has 2x can interfaces: can0
, can1
.
Steps are identical except for replacing the name in instructions below.
-
Enable can0 netdev:
ip link set can0 type can bitrate 125000 ip link set can0 up
-
Receive on can0 to a temporary file:
touch /tmp/can_test candump can0 >> /tmp/can_test &
-
Send a message on can0:
cansend can0 "123#1234"
-
View current configuration:
rs485conf /dev/ttyS5 = Current configuration: RS485 enabled: true RTS on send: low RTS after send: high RTS delay before send: 0 RTS delay after send: 0 Receive during sending data: false
-
Optionally change configuration as needed (the settings shown above are functional):
rs485conf -h usage: rs485conf [-h] tty Get/set RS485 configuration of TTY. positional arguments: tty TTY to get/set configuration (e.g. /dev/ttyS1) optional arguments: -e {0,1} Disable/enable RS485 mode -o {0,1} Set RTS on send low/high -a {0,1} Set RTS after send low/high -r {0,1} Set RX during TX -d d1 d2 Set delay RTS before (d1) and after (d2) send rs485conf /dev/ttyS5 >options>
-
Receive data to a temporary file:
touch /tmp/rs485_test stty -F /dev/ttyS5 raw -echo -echoe -echok cat /dev/ttyS5 > /tmp/rs485_test &
-
Transmit a message:
echo "OK" > /dev/ttyS5
The HummingBoard-T features 2x m.2 connectors:
- M1 (E key): usb-2.0 + pci-e
- M2 (B key): usb-2.0 + usb-3.1
PCI-Express and USB-3.1 are mutually exclusive, the SoC supports only one function at a time.
Selection of specific function is achieved by setting a u-boot environment variable:
-
stop the boot process using the serial console by pressing a key at the timeout prompt:
Hit any key to stop autoboot: 3
-
set
board_m2_function
variable according to the desired function:- PCI-E:
setenv board_m2_function pcie
- USB-3:
setenv board_m2_function usb3
- Neither (default):
env delete -f board_m2_function
- PCI-E:
-
(optionally) save this choice in u-boot environment:
=> saveenv Saving Environment to FAT... OK
-
continue boot:
=> boot
The following commands can be used to download tiboot3.bin, tispl.bin and u-boot.img from a bootable SD card to the eMMC boot0 partition at appropriate offset:
# select eMMC
mmc dev 0 1
# erase (existing) boot data
mmc erase 0x0 0x1C00
# optionally erase environment
mmc erase 0x1C00 0x400
# write tiboot3.bin
load mmc 1 ${kernel_addr_r} tiboot3.bin
mmc write ${kernel_addr_r} 0x0 0x400
# write tispl.bin
load mmc 1 ${kernel_addr_r} tispl.bin
mmc write ${kernel_addr_r} 0x400 0xC00
# write u-boot.img
load mmc 1 ${kernel_addr_r} u-boot.img
mmc write ${kernel_addr_r} 0xC00 0x1000
eMMC layout:
boot0 partition (4 MB)
0x0+----------------------------------+
| tiboot3.bin |
0x400+----------------------------------+
| tispl.bin |
0xC00+----------------------------------+
| u-boot.img |
0x1C00+----------------------------------+
| environment |
0x2000+----------------------------------+
Select boot0
partition as boot source (first time only, may be changed later):
mmc partconf 0 1 1 1
Configure bus for x8 sdr high-speed mode (first time only, may be changed later)
mmc bootbus 0 2 1 1
Finally enable eMMC reset function (first time only, can not be changed later)
mmc rst-function 0 1
In order to boot Linux kernel and rootfs over ethernet, you'll need a TFTP server to serve the required files.
- Install tftpd, xinetd and tftp.
apt-get install tftpd xinetd tftp
- Create the directory you'll use to store the booting files.
mkdir /path/to/boot/dir
chmod -R 777 /path/to/boot/dir
chown -R nobody /path/to/boot/dir
- Create /etc/xinetd.d/tftp, and write in the file:
service tftp
{
protocol = udp
port = 69
socket_type = dgram
wait = yes
user = nobody
server = /usr/sbin/in.tftpd
server_args = /path/to/boot/dir
disable = no
}
Edit /path/to/boot/dir according to your directory
- Restart service
service xinetd restart
- Copy booting files (which are in ti_am64x_build/tmp directory)into tftp directory
# Copy device tree
cp some_location/ti_am64x_build/tmp/am642-solidrun.dtb /path/to/boot/dir/
# Copy Kernel
cp some_location/ti_am64x_build/tmp/Image /path/to/boot/dir/
# Copy rootfs
cp some_location/ti_am64x_build/tmp/rootfs.cpio /path/to/boot/dir/
This part assumes that you have a tftp server in the same network, and that your board is in U-boot.
- Get IP address using dhcp command (ignore the error, we are using this command to get an IP address for a DHCP server)
=> dhcp
link up on port 1, speed 1000, full duplex
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
DHCP client bound to address 192.168.15.119 (2756 ms)
*** ERROR: `serverip' not set
Cannot autoload with TFTPGET
- Set the tftp server IP address.
setenv serverip <the.server.ip.addr>
- Load Kernel into RAM
setenv loadaddr ${kernel_addr_r}
tftpboot Image
- Load Device Tree into RAM.
setenv loadaddr ${fdt_addr_r}
tftpboot am642-solidrun.dtb
- Load rootfs into RAM.
setenv loadaddr ${ramdisk_addr_r}
tftpboot rootfs.cpio
- boot
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
Since rootfs is loaded into RAM, all changes to the file system (creating/deleting files/directories) will be discarded every reboot.
This SOM has 3 Ethernet interfaces, CPSW and 2 ICSSGs, hence, needs 3 MAC addresses. U-boot will try to read these MAC addresses from an EEPROM in I2C bus 0, address 0x50.
EEPROM data is stored in ONIE TLV format:
- Number of MAC addresses stored will be read from entry TLV_CODE_MAC_SIZE.
- First MAC address will be read from entry TLV_CODE_MAC_BASE.
- Consecutive MACs are calculated by incrementing first MAC.
If no valid MAC addresses are found, random MAC addresses will be used.
Here is an example on how to write your own MAC addresses from U-Boot:
# Write 34:88:de:e3:c0:17, 34:88:de:e3:c0:18, 34:88:de:e3:c0:19 as MAC addresses:
tlv_eeprom set 0x24 "34:88:de:e3:c0:17"
tlv_eeprom set 0x2A 3
tlv_eeprom write
# Verify by re-reading the TLV data from eeprom
tlv_eeprom read
tlv_eeprom
# TLV: 0
# TlvInfo Header:
# Id String: TlvInfo
# Version: 1
# Total Length: 18
# TLV Name Code Len Value
# -------------------- ---- --- -----
# Base MAC Address 0x24 6 34:88:DE:E3:C0:17
# MAC Addresses 0x2A 2 3
# CRC-32 0xFE 4 0x2214EB35
Kernel modules can be built using the "linux-headers" package for a specific image. It is available in the same place as binary images on our website.
Modules should be compiled in the same environment as the original images:
x86_64 host, Debian 11, apt-get install crossbuild-essential-arm64
.
A ficticious module may be compiled for fictitious binary image 20240220-abcdefg/microsd-abcdefg-buildroot-sr1.img.xz
using the steps below:
wget https://images.solid-run.com/AM64X/ti_am64x_build/20240220-abcdefg/linux-headers-abcdefg.tar.xz
tar -xf linux-headers-abcdefg.tar.xz
cd kernel-mod-src
make -C ../linux-headers-abcdefg/ CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 M="$PWD" modules
ls *.ko
In case the module requires access to kernel private headers not included in -headers package,
it must be built as part of a full image. See runme.sh function build_atemsys
for an example.
AM64 SoMs featuring TI SoC Silicion 2.0 or later by default support cryptographically verified boot. Units from the factory show the below message during boot, indicating availability and status of the feature:
SoC: AM64X SR2.0 HS-FS
TI are calling the mode above "High-Security Field-Securable", i.e. can be enabled post production by the customer.
- TI System Controller Interface (TISCI) User Guide
- TISCI Security Guide
- TISCI Security Topic
- TISCI User Guide - Key Writer
Parts of Documentation and deployment utilities for Secure Boot are provided by TI directly, under NDA. For access contact your TI representative and request access to the "AM64x Security Resources".
Use TIs confidential OTP Keywriter Package and follow it's user manual for:
- generating signing keys
- programming efuses
Update TI's example code to enable vpp supply regulator of the carrier board programmatically.
On HummingBoard-T vpp is enabled by driving GPIO1_78
high:
#include <drivers/gpio.h>
#include <kernel/dpl/AddrTranslateP.h>
#include "ti_drivers_config.h"
void keywriter_setVpp()
{
uint32_t gpioBaseAddr, pinNum;
gpioBaseAddr = (uint32_t) AddrTranslateP_getLocalAddr(GPIO_VPP_BASE_ADDR);
pinNum = GPIO_VPP_PIN;
GPIO_setDirMode(gpioBaseAddr, pinNum, GPIO_DIRECTION_OUTPUT);
GPIO_pinWriteHigh(gpioBaseAddr, pinNum);
}
const gpio = scripting.addModule("/drivers/gpio/gpio", {}, false);
const gpio1 = gpio.addInstance();
gpio1.$name = "GPIO_VPP";
gpio1.pinDir = "OUTPUT";
gpio1.GPIO.$assign = "GPIO1";
gpio1.GPIO.gpioPin.$assign = "MMC1_SDWP";
Once complete, signed binaries are egenerated by runme.sh
if SIGNING_KEY
environment variable is set pointing to the public TODO TODO key.
After generating SolidRun have tested programming efuses, and booting signed binaries with an internal key that has been generated by the steps outlined below:
E.g. using docker: docker run --rm -i -t -v "$PWD":/ti_build -e SIGNING_KEY=./solidrun_am64_mpk_pub.pem ti_am64x_build -u $(id -u) -g $(id -g)
AM64 SoC and SolidRun SoM support using the eMMC RPMB partition for secure storage.
Activation of the RPMB partition for OPTEE-OS is a one-time irreversible operation during which a secret key derived from protected efuses in the SoC is programmed to the eMMC.
When this key is not programmed, secure variable access consistently fails with the error message below:
I/TC: RPMB: Using generated key
I/TC: HUK Initialized
E/TC:? 0 tee_rpmb_verify_key_sync_counter:1014 Verify key returning 0xffff0008
E/LD: init_elf:493 sys_open_ta_bin(023f8f1a-292a-432b-8fc4-de8471358067)
E/TC:? 0 ldelf_init_with_ldelf:152 ldelf failed with res: 0xffff0009
Note: 0xffff0008
is defined as TEE_ERROR_ITEM_NOT_FOUND.
A special build of optee-os with the CFG_RPMB_WRITE_KEY
option set to y
can automatically program a secure key derived from protected efuses inside the SoC.
This options is disabled by default to avoid accidental use, but can be enabled in runme.sh
when building a custom boot image.
The key gets programmed automatically during any access of secure storage, e.g. by u-boot optee_rpmb
command:
=> optee_rpmb read_pvalue hello 0x1
I/TC: RPMB: Using generated key
I/TC: HUK Initialized
E/TC:? 0 tee_rpmb_verify_key_sync_counter:1014 Verify key returning 0xffff0008
E/TA: read_persist_value:338 Can't open named object value, res = 0xffff0008
Failed to read persistent value
If writing the key succeeded, any future read commands will not include the error messages above, and just complain that the requested object "hello" as expected does not exist.
=> optee_rpmb read_pvalue hello 0x1
I/TC: RPMB: Using generated key
I/TC: HUK Initialized
E/TA: read_persist_value:338 Can't open named object value, res = 0xffff0008
Failed to read persistent value
Secure Storage on RPMB is now active.
The build script supports several customisation options that can be applied through environment variables:
- BOARD: Choose target Board
- evm
- hummingboard-t (default)
- SOC_VERSION: Choose Silicon Revision
- sr1 (AM6442A - SR 1.0)
- sr2 (AM6442B - SR 2.0, default)
- SOC_TYPE: Choose SoC Type (secure boot)
- gp (general purpose, sr1 only)
- hs-fs (high security, field-securable - before burning customer key to efuses, sr2 and later, default)
- hs-se (high security, security-enabled - after burning customer key to efuses, sr2 and later)
- SIGNING_KEY: set specific code signing key (file path) for hs-fs/hs-se builds
- DISTRO: Choose Linux distribution for rootfs
- buildroot (default)
- debian
- BUILDROOT_VERSION
- 2023.02.6 (default)
- BUILDROOT_DEFCONFIG: Choose specific config file name from
config/
folder- am64xx_solidrun_defconfig (default)
- BR2_PRIMARY_SITE: Use specific (local) buildroot mirror
- DEBIAN_VERSION
- bookworm (default)
- bullseye
- DEBIAN_ROOTFS_SIZE
- 936M (default)
A docker image providing a consistent build environment can be used as below:
-
build container image (first time only)
docker build -t ti_am64x_build docker # optional with an apt proxy, e.g. apt-cacher-ng # docker build --build-arg APTPROXY=http://127.0.0.1:3142 -t ti_am64x_build docker
-
invoke build script in working directory
docker run --rm -i -t -v "$PWD":/ti_build ti_am64x_build -u $(id -u) -g $(id -g)
Due to the way podman performs user-id mapping, the root user inside the container (uid=0, gid=0) will be mapped to the user running podman (e.g. 1000:100).
Therefore in order for the build directory to be owned by current user, -u 0 -g 0
have to be passed to docker run.
This can only work on Debian-based host, and has been tested only on Debian 11.
The build script will check for required tools, clone and build images and place results in output/ directory:
./runme.sh