Bringing up and booting an Atmel SAM9 with openocd
The boot process on this SoC family is generally:
- ROM bootstrap loader runs and tries to find a suitable bootstrap program to load into internal SRAM. If that fails (ex: there is no bootstrap programmed yet), the ROM bootstrap sits in a monitor program, intended to be used with the SAM-BA tool from Atmel.
- The bootstrap program is executed from SRAM. It sets up various hardware, including external DDR RAM. It then copies the next application (ex: u-boot or the Linux kernel itself) into DDR RAM and jumps there.
A fresh board can be set up by running u-boot from RAM and in turn using that
to transfer over the Linux kernel and other components and then write them to
the NAND Flash (or whatever your boot source is). The at91bootstrap
program,
however, must run first in order to set up DDR and other hardware.
This can be achieved with openocd by:
- Resetting and halting the target.
- Loading and executing the bootstrap program. This would normally load u-boot from Flash but the Flash is erased.
- Stopping the bootstrap program right before it jumps to the application (with DDR now set up).
- Loading u-boot into the right address.
- Letting the target continue and thereby jump in to u-boot.
This process can be automated but here is an interactive way to run through it.
I assume that you have a serial interface connected to the DBGU
port on the
SoC, that is where serial output from bootloaders is typically sent. The
configuration for this is the typical 115200 8N1.
at91bootstrap
First, you will need to build the at91bootstrap
program for your specific
target (or whatever development kit is closest to your production hardware).
Grab the bootstrap program and configure it, for example:
git clone git://github.com/linux4sam/at91bootstrap.git
cd at91bootstrap
make mrproper
make at91sam9x5eknf_uboot_defconfig
make CROSS_COMPILE=arm-none-linux-gnueabi-
The output will be found in binaries/
, specifically the ELF file can be used
with GDB and the bin file can be written to Flash. Find the appropriate
_defconfig
file in board/<name>/
and note that nf
means “NAND Flash” and
the uboot
configs try to load u-boot whereas the the image configs try to
load a Linux kernel directly. I used a configuration for the sam9x5 evaluation
kits with NAND Flash and u-boot. You can customize further, after setting the
defconfig by running:
make menuconfig
and then building the binaries.
openocd
Tell openocd what JTAG interface you are using and what board you are
targetting. In my case the at91sam9rl-ek
configuration was close enough to
the one I am actually using and my debugger is an Atmel-branded J-Link, my
openocd.cfg
file looks like:
source [find interface/jlink.cfg]
source [find board/atmel_at91sam9rl-ek.cfg]
Make sure you know where your SRAM is located and how large it is (this varies between the various SAM9 sub-families) and verify that the openocd board and target scripts match up. You may have to edit or create your own scripts if things do not look right for your particular chip.
Start openocd with your configuration file and make sure that it is able to find the CPU and report the number of breakpoints. Make sure you see something like:
Info : Embedded ICE version 6
Info : at91sam9rl.cpu: hardware has 2 breakpoint/watchpoint units
in your openocd output before proceeding.
GDB
We can now use GDB to start the bootstrap program. Tell GDB to connect and immediately halt the target and let it know what ELF file you would like to use:
arm-none-linux-gnueabi-gdb -ex "target remote localhost:3333" -ex "mon reset halt" binaries/at91sam9x5ek-nandflashboot-uboot-3.7.elf
From the GDB console, we can enable DCC downloads:
mon mon arm7_9 fast_memory_access enable
And now tell GDB to load the program into RAM:
load
We need a breakpoint right at the end of main()
, check main.c for the line
number, for example:
b main.c:170
Now let the program run and hit the breakpoint:
c
At this point the bootstrap has completed hardware setup and is ready to jump
to the u-boot address, which in my case is 0x26f00000
.
Now we just need u-boot.bin
loaded at 0x26f00000
. We can use load_image
in openocd to do this:
mon load_image /tftpboot/u-boot.bin 0x26f00000 bin
and then continue:
c
The u-boot console should now appear on DBGU
, press Enter to start
interactive mode.
u-boot
From here you can use u-boot to transfer files into RAM (via Ethernet or USB or
MMC or even the serial port). You could also continue to use JTAG to transfer
images into RAM (openocd load_image
) and then use u-boot to write them to
Flash.
For example, we can interrupt the target in GDB by pressing control+c and then
load a uImage into RAM at 0x22000000
:
mon load_image /tftpboot/uImage 0x22000000 bin
c
Then tell u-boot to run this via its console:
bootm 0x22000000
or, similarly, you could have u-boot write the image to NAND Flash or whatever
is needed. See the example memory map for ideas on where to
put things in NAND Flash. Given the typical boot sequence, I would start by
writing the appropriate at91bootstrap
program into Flash, writing u-boot into
Flash as well, and then seeing if a reset of the board gets you the expected
results.