Skip to content

Instantly share code, notes, and snippets.

@hxmuller
Last active February 5, 2023 22:37
Show Gist options
  • Save hxmuller/f1091f9b04b583db0d56b6f893747482 to your computer and use it in GitHub Desktop.
Save hxmuller/f1091f9b04b583db0d56b6f893747482 to your computer and use it in GitHub Desktop.
Program the SPI NOR flash on a Pinebook Pro using a micro SD card and u-boot

Program SPI NOR Flash on Pinebook Pro with u-boot on micro SD Card

TL;DR: This describes the process, hardware, and software used to perform in-circuit programming of the 128Mbit SPI NOR flash (flash) in the Pinebook Pro (PBP) using u-boot on a micro SD Card.

Warning

You, the user of this information bear ALL responsibility for ANY outcome of its use, whether negative or positive.

The flash (identified below) this document refers to is rated for a minimum 100000 program/erase cycles. Exercising it beyond that limit will likely require its replacement which is non-trivial.

Programming flash is done for a purpose which is not covered here, this only documents the how. Improper use of this information or a bad idbloader and u-boot image can result in a system which will not boot without shorting pins on the flash. Recovering from this type of situation is not covered here and is left as an exercise for the user.

You, the user of this information, are responsible for ANY and ALL outcomes of its use.

Introduction

This method uses u-boot on a micro SD card to program flash on the PBP and requires a host connected to it via serial connection. There are two different flash chips in use (winbond W25Q128JV and GigaDevice GD25Q127C). They each have the same characteristics.

Using this method is preferable to the In-circuit Programming Method documented previously as it requires less hardware and reduces risk. However it is not possible to recover from a bad image written to the flash using this method.

I used an ARM64 single board computer (SBC) to perform the compilations, you can use the Pinebook Pro itself to do the compilation but you will still need a host machine to use the u-boot monitor (shell).

NOTE: This document only discusses the "how to write u-boot to flash using u-boot on a micro SD card."

NOTE: The version of u-boot this document is based on is: 2020.10-rc4-g9de3126e. This was based on the results of running within the u-boot source:

$ cat include/config/uboot.release | tr -d \"

NOTE: The Pinebook Pro should be fully charged and plugged in during this process.

Minimum Hardware Requirements

  • Pinebook Pro
  • USB Serial cable with audio plug
  • ARM SBC with keyboard and monitor running linux os (I used Debian arm64)
  • USB [micro] SD card reader
  • internet access

NOTE: If you use an external hard drive to compile with on a ARM SBC, increase the current to USB if possible to the maximum allowable. If you cannot increase current to usb, then attach external hard drive to powered USB hub. I thought tmux was freezing, but it was uninterruptible processes operating on the external hard drive which was creating the freeze.

I connected an ARM64 SBC to my local area network (LAN) and ssh'd to it using an x86_64 host. Although I compiled u-boot natively on the SBC, it is possible to cross compile on a host with different architecture but that is not covered here.

Software Requirements

This assumes a Debian or Debian based distribution is installed. Packages that are necessary to install on the ARM SBC are:

Distributed Version Control System

  • git

Compiler and Compilation support

  • build-essential (provides libc6-dev, gcc, g++, make)
  • libncurses-dev
  • bison
  • flex
  • device-tree-compiler
  • bc
  • gcc-arm-none-eabi

Serial Communication

  • picocom

NOTE: Add the user to the dialout group to use picocom, afterwards logout and back in:

$ sudo adduser $USER dialout

NOTE: A terminal multiplexer is handy but not required (screen or tmux)

Procedures

Compiling mainline u-boot and ATF, make special idbloader.img

The ARM SBC is used to natively compile u-boot (and ATF). First create a working source directory:

$ mkdir sources
$ cd sources/

Compile mainline Arm Trusted Firmware

u-boot compilation uses a product of this compilation, bl31.elf.

Obtain the mainline Arm Trusted Firmware (ATF) sources:

$ git clone --depth 1 https://github.com/ARM-software/arm-trusted-firmware.git

You can instruct make to use as many processors/threads the host has for compilation using -j# where # is the number to use up to the max number the host has. The pipe and tee command are a convenience and not necessary.

Compile ATF with the following, items in brackets optional, do not type the brackets:

$ cd arm-trusted-firmware/
$ make realclean
$ make [-j4] PLAT=rk3399 all [2>&1 | tee make.log]
$ cd ..

When the compilation finishes note the path to bl31.elf as you will use this in the next step.

Compile mainline u-boot

Same as above items in brackets are optional, do not type the brackets. You should now be in the sources directory.

Obtain the mainline u-boot sources:

$ git clone --depth 1 https://gitlab.denx.de/u-boot/u-boot.git

Compile u-boot using the following, items in brackets optional, do not type the brackets. Also replace /path/to with the path you noted at the end of ATF compilation:

$ export BL31=/path/to/bl31.elf
$ cd u-boot/
$ make distclean
$ make pinebook-pro-rk3399_defconfig
$ make [-j4] all [2>&1 | tee make.log]

Create special version of idbloader.img for SPI flash

The rk3399 BROM needs a special version of idbloader.img to read it from SPI flash, so create it:

$ ./tools/mkimage -n rk3399 -T rkspi -d tpl/u-boot-tpl.bin:spl/u-boot-spl.bin idbloader_spi.img
$ cd ..

Everything we need has been compiled and made, next we create an image to be burned to a micro SD card.

Create micro SD card image

These operations can be done directly to the micro SD card, but I elected to create an image which reduced the overall writes to the micro SD card as it was an iterative process.

Install prerequisites

Additional software is required for this step, install these packages if they are not on your system:

  • qemu-utils
  • parted
  • kpartx
  • dosfstools

Create an empty image

An image size of 32M is more than enough for our needs, but if you later want to extract a copy of the SPI flash contents, you may want to change the size from 32M to 64M just to have spare room.

We are also going to use the image name a few times so we put it in a variable for convenience.

$ image=uboot_spi.img
$ qemu-img create -q -f raw $image 32M

Partition the image

12MiB may seem like an excessive amount of space to reserve before the partition starts, but if you later check on where we write the files to on the image and the file sizes, you will see why.

$ sudo parted $image mklabel msdos
$ sudo parted $image mkpart primary fat16 12MiB 100%

Map the partition

We are going to use the mapped partition a few times, so I send it to a variable:

$ mapped_partition=/dev/mapper/$( sudo kpartx -av $image | awk '{print $3}' )

Create a FAT filesystem on the partition

$ sudo mkfs.fat -F 16 -n BOOT $mapped_partition

Mount the partition and files to it

We need the special idbloader_spi.img file we made and u-boot.itb. Mount the partition:

$ mount_point=$( mktemp -d )
$ sudo mount $mapped_partition $mount_point
$ sudo cp u-boot/idbloader_spi.img ${mount_point}/
$ sudo cp u-boot/u-boot.itb ${mount_point}/
$ sync
$ sudo umount $mount_point

Remove partion mapping

sudo kpartx -dsv $image

Write u-boot to the image so it boots

We will be using the loop device in commands twice, so send it to a variable:

loop_device=$( sudo losetup --find --partscan --show $image )

Now we burn the necessary u-boot files to their locations:

$ sudo dd if=u-boot/idbloader.img of=${loop_device} seek=64 conv=fsync
$ sudo dd if=u-boot/u-boot.itb of=${loop_device} seek=16384 conv=fsync
$ sync
$ sudo losetup -D

The image is now ready and may be burned to the micro SD card.

Write image to the micro SD card

Take an empty micro SD card that has no data on it, insert it into a USB [micro] SD card reader.

Insert the card reader into an open USB port on the ARM64 SBC. Check to see if it has been automounted:

$ lsblk

If the card has been automounted, unmount it. And then write the image to the micro SD card, where is the device of your card reader.

WARNING: Writing to the wrong device can destroy data and/or make your ARM64 device unbootable.

We first zero the first 8M of the sd card to eliminate any partition information, and then write the image to the card:

$ sudo dd if=/dev/zero of=/dev/<device> bs=4M count=2 conv=fsync
$ sudo dd if=$image of=/dev/<device> bs=4M conv=fsync
$ sync

You can remove the card reader from the ARM64 SBC, and the micro SD card from the card reader. It is ready to boot.

Write u-boot to the PBP SPI NOR flash

Prepare the Pinebook Pro

To prepare the Pinebook Pro:

  • Turn it off
  • Unscrew the back from the device
  • Turn the eMMC switch off (see the Pine64 Pinebook Pro wiki)
  • Turn the UART switch on (see the Pine64 Pinebook Pro wiki)
  • Screw the back onto the device

Plug the USB Serial UART cable into an open USB port on the ARM64 SBC. Plug the audio jack end of the cable into the Pinebook Pro.

Initiate a serial connection to the PBP on the ARM64 SBC:

$ picocom /dev/ttyUSB0 -b 1500000

Open the PBP lid, and turn it on. You should see a stream of text, you can hit a key to keep it from trying to autoboot because in this state it will not boot into anything but you should have a u-boot prompt:

=>

and that is all we need.

Write u-boot to SPI NOR flash

First probe the flash:

=> sf probe 1:0

The flash should be detected.

Now write the special idbloader image to flash:

=> load mmc 1:1 $kernel_addr_r idbloader_spi.img
=> sf erase 0 +$filesize
=> sf write $kernel_addr_r 0 $filesize

Now write the u-boot image to flash:

=> load mmc 1:1 $kernel_addr_r u-boot.itb
=> sf erase 0x60000 +$filesize
=> sf write $kernel_addr_r 0x60000 $filesize

You can now turn off the PBP by holding the power button for about 10 seconds, remove the micro SD card, and turn the PBP back on. With the eMMC disabled and no micro SD card installed you should see u-boot start on the terminal. The Pinebook Pro has just started u-boot from SPI NOR flash.

That alone is not going to do much for you other than demonstrate that it can be done.

Erase u-boot from SPI NOR flash

The process we just went through is reversible, we just skip the 'sf write' steps. Insert the micro SD card back into the PBP. Start the serial connection again if you stopped it (picocom), then turn the PBP back on. It will boot from SPI NOR flash. To erase what you wrote to it earlier:

=> sf probe 1:0
=> load mmc 1:1 $kernel_addr_r idbloader_spi.img
=> sf erase 0 +$filesize
=> load mmc 1:1 $kernel_addr_r u-boot.itb
=> sf erase 0x60000 +$filesize

Much simpler than the Pomona clip method. I hope you enjoyed this as much as I did.

Troubleshooting

If the Pinebook Pro does not boot to u-boot prompt (while connected over USB serial) and you do not see u-boot messages it is one of the following:

  1. The Pinebook Pro was not fully charged and plugged in:

With a low charge, I wrote u-boot to flash and it appeared to be successful, but it would not boot to u-boot prompt. Plugging the PBP in and flashing it again was successful and booted to u-boot prompt.

  1. You copied and wrote idbloader.img to flash instead of idbloader_spi.img:

This can be easily checked by checking the size of the idbloader_spi.img file on the micro SD card. It should be 335872 bytes (328K bytes), which is twice the size of idbloader.img.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment