Prepare card

To make sure everything will run without problem wipe all data on the MMC:

$ sudo dd if=/dev/zero of=/dev/sdx bs=1k count=1024

Format the disk:

$ sudo fdisk /dev/sdx << __EOF__

Make ext4 filesystem

$ sudo mkfs.ext4 -F -O ^metadata_csum,^64bit /dev/sdx1

NOTE: You MUST replace /dev/sdx with your device, e.g. /dev/sdc.

Cross compiler

In this tutorial gcc 5.4.0 is used:

$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (Debian 5.4.0-6) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO

On Ubutuntu/Debian run:

$ sudo apt-get install gcc-5-arm-linux-gnueabihf

Optionally download toolchain from here. For example:

$ wget
$ tar -xf gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf.tar.xz -C /opt

Then export to PATH:

$ expot PATH=$PATH:/opt/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/bin/


Building U-Boot

Get sources with:

$ git clone git://
$ cd u-boot

The patch is built against specific commit, so reset repository:

$ git reset --hard b89dfcfd926b8224edd24608065eb9bb601c0d3b

Get and apply patch:

$ wget
$ git apply 0001-Add-support-for-AM335x-Olimex-boards.patch

Build image, where <board_defconfig> is am335x_olimex_som_defconfig or am335x_olimex_som_nandboot_defconfig:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- <board_defconfig>

This will produce two files:

  • MLO
  • u-boot.img

Writing U-Boot


Insert your card and write MLO and u-boot.img:

$ sudo dd if=MLO of=/dev/sdx count=1 seek=1 bs=128k
$ sudo dd if=u-boot.img of=/dev/sdx count=2 seek=1 bs=384k 


In both cases below you will need bootable MMC card. Copy MLO and u-boot.img to root (/) directory of the card.

NOTE: U-boot must be built with am335x_olimex_som_nandboot_defconfig!

From u-boot console

Boot via MMC and press any key to stop autoboot:

U-Boot SPL 2016.09-rc2-00047-gb89dfcf-dirty (Sep 15 2016 - 15:46:19)
Trying to boot from MMC1

U-Boot 2016.09-rc2-00047-gb89dfcf-dirty (Sep 15 2016 - 15:46:19 +0300)

DRAM:  512 MiB
NAND:  512 MiB
Hit any key to stop autoboot:  0 

To see nand partitions run:

=> mtd

device nand0 <nand.0>, # parts = 10
 #: name                size            offset          mask_flags
 0: NAND.SPL            0x00020000      0x00000000      0
 1: NAND.SPL.backup1    0x00020000      0x00020000      0
 2: NAND.SPL.backup2    0x00020000      0x00040000      0
 3: NAND.SPL.backup3    0x00020000      0x00060000      0
 4: NAND.u-boot-spl-os  0x00040000      0x00080000      0
 5: NAND.u-boot         0x00100000      0x000c0000      0
 6: NAND.u-boot-env     0x00020000      0x001c0000      0
 7: NAND.u-boot-env.backup10x00020000   0x001e0000      0
 8: NAND.kernel         0x00800000      0x00200000      0
 9: NAND.file-system    0x1f600000      0x00a00000      0

Erase the while chip:

=> nand erase.chip

NAND erase.chip: device 0 whole chip
Erasing at 0x1ffe0000 -- 100% complete.

Or you can erase single partition:

=> nand erase.part NAND.SPL

NAND erase.part: device 0 offset 0x0, size 0x20000
Erasing at 0x0 -- 100% complete.

NOTE: Everytime before write operation mtd partitions MUST be erased!

Write MLO:

=> nand erase.part NAND.SPL

NAND erase.part: device 0 offset 0x0, size 0x20000
Erasing at 0x0 -- 100% complete.
=> nand erase.part NAND.SPL.backup1

NAND erase.part: device 0 offset 0x20000, size 0x20000
Erasing at 0x20000 -- 100% complete.
=> nand erase.part NAND.SPL.backup2

NAND erase.part: device 0 offset 0x40000, size 0x20000
Erasing at 0x40000 -- 100% complete.
=> nand erase.part NAND.SPL.backup3

NAND erase.part: device 0 offset 0x60000, size 0x20000
Erasing at 0x60000 -- 100% complete.
=> load mmc 0 0x82000000 MLO
46044 bytes read in 32 ms (1.4 MiB/s)
=> nand write 0x82000000 NAND.SPL

NAND write: device 0 offset 0x0, size 0x20000
 131072 bytes written: OK
=> nand write 0x82000000 NAND.SPL.backup1

NAND write: device 0 offset 0x20000, size 0x20000
 131072 bytes written: OK
=> nand write 0x82000000 NAND.SPL.backup2

NAND write: device 0 offset 0x40000, size 0x20000
 131072 bytes written: OK
=> nand write 0x82000000 NAND.SPL.backup3

NAND write: device 0 offset 0x60000, size 0x20000
 131072 bytes written: OK

Write u-boot.img:

=> nand erase.part NAND.u-boot

NAND erase.part: device 0 offset 0xc0000, size 0x100000
Erasing at 0x1a0000 -- 100% complete.
=> load mmc 0 0x82000000 u-boot.img
347364 bytes read in 48 ms (6.9 MiB/s)
=> nand write 0x82000000 NAND.u-boot

NAND write: device 0 offset 0xc0000, size 0x100000
 1048576 bytes written: OK

From linux console

Boot board from MMC card. Make sure you have mtd-utils package, otherwise:

$ apt-get update
$ apt-get install mtd-utils

You should see 10 mtd devices:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00020000 00020000 "NAND.SPL"
mtd1: 00020000 00020000 "NAND.SPL.backup1"
mtd2: 00020000 00020000 "NAND.SPL.backup2"
mtd3: 00020000 00020000 "NAND.SPL.backup3"
mtd4: 00040000 00020000 "NAND.u-boot-spl-os"
mtd5: 00100000 00020000 "NAND.u-boot"
mtd6: 00020000 00020000 "NAND.u-boot-env"
mtd7: 00020000 00020000 "NAND.u-boot-env.backup1"
mtd8: 00800000 00020000 "NAND.kernel"
mtd9: 1f600000 00020000 "NAND.file-system"

To erase partition use:

# flash_erase /dev/mtd0 0 0

To write MLO:

# flash_erase /dev/mtd0 0 0
# nandwrite -p /dev/mtd1 /MLO
# flash_erase /dev/mtd1 0 0
# nandwrite -p /dev/mtd0 /MLO
# flash_erase /dev/mtd2 0 0
# nandwrite -p /dev/mtd2 /MLO
# flash_erase /dev/mtd3 0 0
# nandwrite -p /dev/mtd3 /MLO

To write u-boot.img:

# flash_erase /dev/mtd5 0 0
# nandwrite -p /dev/mtd5 /u-boot.img


We are going to use kernel 4.4 from TI.

Getting the sources

Clone into repository:

$ git clone git://
$ cd ti-linux-kernel

Get 4.4.y remote branch:

$ git checkout linux-4.4.y -b linux-4.4

Configure kernel

Load omap2plus default defconfig:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- omap2plus_defconfig

Make some modifications:

$ make ARCH=arm menuconfig
  • Enable SPIDEV
Device Drivers  --->
   [*] SPI support  --->
       <M>   User mode SPI device driver support
  • Enable DRM
Device Drivers  --->
   Graphics support  --->
       <M> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)  --->
       <M> DRM Support for TI LCDC Display Controller
           [*]   Support device tree blobs using TI LCDC Slave binding (NEW)
  • Enable SHAM and AES
-*- Cryptographic API  --->
   [*]   Hardware crypto devices  --->
       <M>   Support for OMAP MD5/SHA1/SHA2 hw accelerator
       <M>   Support for OMAP AES hw engine

Kernel build

Build kernel and modules:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules

Install modules to target directory:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=output modules_install

Patch kernel tree to get our device-tree blobs:

$ wget
$ git apply 0001-Add-support-for-OLIMEX-dtbs.patch

If patch fail, you can reset the tree:

$ git reset --hard 65fd19fc2bac06ae7e66cc3d6450c9d6dd034311

Build dtbs:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

This will produce lot of .dtb files. The interesting ones are:

  • am335x-olimex-som.dtb - The minimum configuration for AM335x-SOM to run.
  • am335x-olimex-som-nand.dtb - Same as above, but with enabled nand.
  • am335x-olimex-som-evb.dtb - Support for AM335x-SOM-EVB. Use this one, if there isn't intalled nand on AM335x-SOM
  • am335x-olimex-som-evb-nand.dtb - Save above, without dual ethernet and enabled nand.

Kernel writing

Now when you have new kernel put it on the right location

MMC card

We assume that you already installed rootfs on the card. Mount card, if its not mounted yet:

$ sudo mount /dev/sdx1 /mnt

Copy zImage and device-tree blobs:

$ sudo cp arch/arm/boot/zImage /mnt/boot/
$ sudo cp arch/arm/boot/dts/am335x-olimex-som*.dtb /mnt/boot

NAND flash

Again you must boot from MMC and have zImage and dtbs stored in some folder.

From u-boot console

Write zImage:

=> nand erase.part NAND.kernel

NAND erase.part: device 0 offset 0x200000, size 0x800000
Erasing at 0x9e0000 -- 100% complete.
=> load mmc 0 0x82000000 /boot/zImage
3667672 bytes read in 327 ms (10.7 MiB/s)
=> nand write 0x82000000 NAND.kernel 

NAND write: device 0 offset 0x200000, size 0x800000
 8388608 bytes written: OK

Write device-tree blob:

=> nand erase.part NAND.u-boot-spl-os

NAND erase.part: device 0 offset 0x80000, size 0x40000
Erasing at 0xa0000 -- 100% complete.
=> load mmc 0 0x82000000 /boot/am335x-olimex-som-evb-nand.dtb
37870 bytes read in 18 ms (2 MiB/s)
=> nand write 0x82000000 NAND.u-boot-spl-os

NAND write: device 0 offset 0x80000, size 0x40000
 262144 bytes written: OK
From linux console

To write zImage:

# flash_erase /dev/mtd8 0 0
# nandwrite -p /dev/mtd8 /boot/zImage

To write dtb:

# flash_erase /dev/mtd4 0 0
# nandwrite -p /dev/mtd4 /boot/am335x-olimex-som-evb-nand.dtb

File system

Install required tools:

$ sudo apt-get install qemu-user-static debootstrap binfmt-support 

Make target directory:

Make new file system

$ mkdir rootfs
$ sudo debootstrap --arch=armhf --foreign jessie rootfs 

Copy qemu and resolvonf:

$ sudo cp /usr/bin/qemu-arm-static rootfs/usr/bin/
$ sudo cp /etc/resolv.conf rootfs/etc 

Go into the new file system:

$ sudo chroot rootfs 

Inside the new file system do:

# export LANG=C
# /debootstrap/debootstrap --second-stage

Set apt sources.list:

# cat << __EOF__ > /etc/apt/sources.list
#                   OFFICIAL DEBIAN REPOS                    

###### Debian Main Repos
deb jessie main contrib non-free 
deb-src jessie main contrib non-free 

###### Debian Update Repos
deb jessie/updates main contrib non-free 
deb jessie-proposed-updates main contrib non-free 
deb-src jessie/updates main contrib non-free 
deb-src jessie-proposed-updates main contrib non-free 

Note: The list is generated using this tool, so feel free modify it.

Set hostname:

# echo "AM335x" > /etc/hostname

Install some packages:

# apt-get install locales dialog sudo openssh-client

Set locales:

# dpkg-reconfigure locales

Set root password:

# passwd

Add olimex user:

# adduser olimex

Make uEnv file:

# cat << __EOF__ > /uEnv.txt
optargs=loglevel=0 mtdoops.mtddev=omap2.nand

Enable heartbeat led trigger. Append ledtrig-heartbeat on the last line:

# echo "ledtrig-heartbeat" >> /etc/modules-load.d/modules.conf

Enable serial port on USB-OTG

Make script that initialize serial gadget:

# cat << __EOF__ > /usr/bin/

# variables and strings
MANUFACTURER="Olimex Ltd."          #  manufacturer attribute
SERIAL=$(ifconfig eth0 | head -n1 | awk -F" " '{print $5}' | sed 's/://g')
IDPRODUCT="0x003e"                  #  hex product ID, issued by USB Group
IDVENDOR="0x15ba"                   #  hex vendor ID, assigned by USB Group
PRODUCT="AM335x Serial Gadget"      #  cleartext product description
CONFIG_NAME="Configuration 1"       #  name of this configuration                #  name of the UDC driver to use (found in /sys/class/udc/)

# Load modules
! lsmod | grep "libcomposite" > /dev/null 2>&1 && modprobe libcomposite
! lsmod | grep "usb_f_acm" > /dev/null 2>&1 && modprobe usb_f_acm

# Mount confgsfs
[ ! -d $CONFIGS_DIR ] && mkdir $CONFIGS_DIR
mount none $CONFIGS_DIR -t configfs

# Create gadget
mkdir -p $CONFIGS_DIR/usb_gadget/serial
cd $CONFIGS_DIR/usb_gadget/serial

# Set VID and PID
echo $IDVENDOR > idVendor
echo $IDPRODUCT > idProduct

# Set strings
mkdir strings/0x409
echo $SERIAL > strings/0x409/serialnumber
echo $MANUFACTURER > strings/0x409/manufacturer
echo $PRODUCT > strings/0x409/product

# Create configuration
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "120" > configs/c.1/MaxPower
echo $CONFIG_NAME > configs/c.1/strings/0x409/configuration

# Creating functions
mkdir functions/acm.usb0

# Associate function with comfiguration
ln -s functions/acm.usb0 configs/c.1

# Enable UDC
echo $UDC > UDC

Make it executable

# chmod +x /usr/bin/

Add startup service:

# cat << __EOF__ > /lib/systemd/system/usb-serial.service
Description=Serial console on USB-OTG

ExecStart=/bin/bash -c "/usr/bin/"


Enable login on ttyGS0:

# cp -v /lib/systemd/system/serial-getty\@.service /lib/systemd/system/serial-getty\@ttyGS0.service
# nano /lib/systemd/system/serial-getty\@ttyGS0.service

Add following in [Unit] section:


Enable service:

# systemctl enable serial-getty\@ttyGS0.service

Write file system

First exit and make some cleanup:

# exit
$ sudo rm rootfs/usr/bin/qemu-arm-static
$ sudo rm rootfs/etc/resolv.conf

Copy kernel modules:

$ cp -r <kernel_dir>/output/* rootfs/

Write to MMC card

Mount the card and simply copy files:

# sudo mount /dev/sdx1 /mnt
# sudo cp -rpf rootfs/* /mnt

Write to NAND

Since NAND is MTD device thera are some extra operations.

First check nand parameters. In u-boot console run:

=> ubi part NAND.file-system
ubi0: attaching mtd1
ubi0: scanning is finished
ubi0: empty MTD device detected
ubi0: attached mtd1 (name "mtd=9", size 502 MiB)
ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 129024 bytes
ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 512
ubi0: VID header offset: 512 (aligned 512), data offset: 2048
ubi0: good PEBs: 4016, bad PEBs: 0, corrupted PEBs: 0
ubi0: user volume: 0, internal volumes: 1, max. volumes count: 128
ubi0: max/mean erase counter: 1/0, WL threshold: 4096, image sequence number: 0
ubi0: available PEBs: 3932, total reserved PEBs: 84, PEBs reserved for bad PEB handling: 80
=> ubi info
UBI: MTD device name:            "mtd=9"
UBI: MTD device size:            502 MiB
UBI: physical eraseblock size:   131072 bytes (128 KiB)
UBI: logical eraseblock size:    129024 bytes
UBI: number of good PEBs:        4016
UBI: number of bad PEBs:         0
UBI: smallest flash I/O unit:    2048
UBI: VID header offset:          512 (aligned 512)
UBI: data offset:                2048
UBI: max. allowed volumes:       128
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     0
UBI: available PEBs:             3932
UBI: total number of reserved PEBs: 84
UBI: number of PEBs reserved for bad PEB handling: 80
UBI: max/mean erase counter: 1/0

Make ubifs:

# sudo mkfs.ubifs -q -r ./rootfs -m 2048 -e 129024 -c 3932 -o rootfs.ubifs

This image canbe used in booted linux system. If you want to burn the file system from u-boot, then make ubi image:

# cat << __EOF__ > ubinize.cfg

Run ubinize:

# sudo ubinize -o rootfs.ubi -m 2048 -p $((128*1024)) -s 512 ubinize.cfg

Burn from u-boot console

This is very slow!

Copy rootfs.ubi to MMC card and do:

=> nand erase.part NAND.kernel

NAND erase.part: device 0 offset 0xa00000, size 0x1f600000
Erasing at 0x1ffe0000 -- 100% complete.
=> load mmc 0 0x82000000 rootfs.ubi
232521728 bytes read in 58315 ms (3.8 MiB/s)
=> nand write 0x82000000 NAND.file-system
Burn from linux console

Format partition and update partition:

# ubiformat /dev/mtd9
# ubiattach -p /dev/mtd9
# ubimkvol /dev/ubi0 -N rootfs -m
# ubiupdatevol /dev/ubi0_0 /rootfs.ubifs


Where to get prebuild images

You can download them from our torrent tracker. Get this torrent file.

Can boot from NAND, but not from MMC

Bootstrap pins are set in such order that NAND is before MMC. If you what to boot only from MMC and use NAND as storage then just erase nand from u-boot console:

=> nand erase.chip

Resize MMC card

If you download the image from our torrent tracker and burn it, you'll notice that rootfs is only ~900MB. This is because rootfs partition is not stretched to fill MMC. You must do this manually:

  • Using GParted

This is the easiest method. Insert MMC card into host PC and run GParted. Then select device number and click on Resize/Move. Then click OK and you're ready.

  • On booted system

Several reboots will be needed.

First delete old partition table:

# sudo fdisk /dev/sdx << __EOF__

Reboot the system. The kernel will load the new partition table.

# reboot

After that resize the file system and reboot one more time:

# resize2fs /dev/mmcblk0p1
# reboot

I've bricked my NAND


If you upload broken MLO or u-boot.img, it's possible for your board to stop booting. To fix you'll need MMC card. Insert it. Short the pins like it's showed on the image and power-up the board.

You will see some CCCCCC and then the board will boot from the MMC. You can use u-boot console to erase nand chip.

Changing display resolution

If you're using am335x-olimex-som-evb device-tree blob you can choose from 4 predefined resolutions:

  • 480x272 - 4.3' lcd
  • 800x480 - 7' lcd
  • 800x600 - VGA output
  • 1024x600 - 10' lcd

You can use 2 methods: recompilation of the device-tree file inside kernel tree or rebuilding on booted system

Recompilation in kernel tree

Go to your kernel tree and edit dts file, for example:

$ cd kernel
$ nano arch/arm/boot/dts/am335x-som-olimex-evb.dts

Go to panel/display-timings section end edit native-mode to timings0,1,2 or 3:

panel {
        display-timings {
                native-mode = <&timings0>;

Save the file and run:

$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

Then put the dtb files in /boot directory of your MMC card