Monday, March 7, 2011

BeagleBoard-xM u-boot without serial cable - USB console

This is a note-to-self post, if you find it useful, you're welcome. If something is not clear, just ask.

Background: I got a BeagleBoard-xM but I had no serial cable and didn't want to get one (the shop is too far, internet store shipping is too slow). The thing connects via USB to the computer, and many devices implement serial over USB, so I thought "well, I'll connect the thing and as soon as it powers up I will get a /dev/ttyUSB0 to connect and interact with the bootloader/kernel". No luck. From my previous experiences with foneras I also tried an ethernet connection, in case it comes with ssh by default, but that didn't work either (the thing comes with a very small test implemetation that doesn't even power up the ethernet hardware).

Ok, lets do some RTFM. Done. Looking aroud, turns out that there is in fact a project for a USB console. I tried it but something was so wrong that it didn't even boot. Since people were reporting success with it, I assume that is some change in the xM version that makes it incompatible. and the last commit to the git repo was in mid-2009, so there was little hope that way. Next...

Short version

Turns out that the angstrom demo page contains almost everything needed. Download MLO, u-boot.bin, put them on the boot partition of the SD card as described in the wiki and jump to the boot.scr section.

Long version

Cross compile

First problem is getting cross compiling to work. We have a x86, we want to get arm code, gcc is not enough. There are many compilers and they have their differences.

For Arch, I used the package "arm-2010-arm-none-eabi 2010.09-1" from the AUR, which is this version. It fetches the i686 version so I used an Arch VM for compiling.

To use cross compiling, invoke make with "CROSS_COMPILE=arm-none-eabi-" parameter.

WARNING1: The name may differ, for older versions is "CROSS_COMPILE=arm-none-linux-gnueabi-". For any linux "locate eabi | grep gcc" should solve your problem, in Arch "pacman -Ql PACKAGE_NAME | grep bin" will do the trick even better :)

WARNING2: It turns out that the 2010 version has a nasty bug - or maybe it's something with my VM system - and it doesn't use the cross-assembler by default. Try to compile something and it keeps dying:
Assembler messages:
Fatal error: Invalid -march= option: `armv5'
Of course it's not valid, since it's calling the x86 assembler. I worked around it with the following script:
$ emacs /usr/local/bin/as
#!/bin/sh                                                                                
for i in $@; do
    echo $i | grep "\-march=arm" > /dev/null;
    if [ "$?" == "0"  ]; then
        /usr/bin/arm-none-eabi-as $@
        exit $?
    fi
done
/usr/bin/as $@
exit $?
Just make sure that /usr/local/bin is before /usr/bin in your $PATH, and you're good to go.

U-Boot

So, now we need that u-boot configures the USB OTG as a serial device and listens to it. And the only project aimed at it so fails hard on the xM that it doesn't even boot. Let's start with the wiki:

Mainline U-Boot has good support for BeagleBoard (except for revision C4; see note below).
[...]
Note: For experimental U-Boot patches not ready for mainline yet, Steve's Beagle U-Boot git repository is used to test them. [This was the omap3-dev-usb version no longer mantained that faile hardly]
[...]
Note: For beagleboard revision C4, above sources will not work. USB EHCI does not get powered, hence devices are not detected... get a patched version of u-boot from http://gitorious.org/beagleboard-default-u-boot/beagle_uboot_revc4/ (Update on April 23 - 2010: This repository has been superseded by the U-Boot version found at http://gitorious.org/beagleboard-validation/)
Ok, so I understand that the mainline is superseeded by the omap3, which are superseeded by the beagleboard-validation repository. Very well.

Let's checkout the BeagleBoard validation which has the validation code.

It looks promising, since the default git branch is called "xm".
$ make CROSS_COMPILE=arm-none-eabi- mrproper
$ make CROSS_COMPILE=arm-none-eabi- omap3_beagle_config
$ make CROSS_COMPILE=arm-none-eabi-
$ cp u-boot.bin /mnt/SDCARD/
It boots but unfortunately it fails to create a usb device. Last commit is June 2010, so I don't expect it being developed anymore. There are mentions to the musb device in the source code, it must be doable somehow. So I try the newest possible branch, jason 20110303 - doesn't even compile.
A bit less new, jason 20110302 - it works! When plugged to a computer it is detected as /dev/ttyACM0! Hurray... not so fast. When added boot.scr (see below) and connected with screen or minicom, it's silent. Damn, so close...
Let's go one more step back koen/beagle-2010.12. Compiles, loads (with boot.scr), creates the device... and answers! Yoohoo! But wait... (yes, there still is a catch) the output is semi-garbage! Well, let's try some other u-boot version...

Looking at the commit messages turn out that the upstream version is still being developed! All the steps again, at it goes silent. Tried with the latest stable release and it was almost-working still a bit unstable some letters were a bit off from the output, but pretty usable and functional.

boot.scr

By default the bootloader listens and speaks to the hardware serial console. To convince it to do otherwise we need to put a small boot.scr file on the sd card, just after copying u-boot.bin to it. To create the file we write the script to a text file:
$ emacs myscript.txt
setenv stdin usbtty
setenv stdout usbtty
Now we download any u-boot source and we issue a "make tools" command (no cross-compiling needed). After it finishes compiling:
tools/mkimage -A arm -T script -C none -d src.txt boot.scr
Then we copy the boot.scr file to the sd card in order to have a working usb bootloader console :D
In case you don't want to do all the stuff, here is a sample file:
$ hexdump boot.scr
0000000 0527 5619 0680 b4cc 744d b50a 0000 3100
0000010 0000 0000 0000 0000 e47f 58bb 0205 0006
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0000040 0000 2900 0000 0000 6573 6574 766e 7320
0000050 6474 6e69 7520 6273 7474 0a79 6573 6574
0000060 766e 7320 6474 756f 2074 7375 7462 7974
0000070 000a                                   
0000071

Geek level: hard

Why boot.scr and not some other name?
$ emacs include/configs/omap3_beagle.h
#define CONFIG_EXTRA_ENV_SETTINGS \
        "loadaddr=0x82000000\0" \
        "usbtty=cdc_acm\0" \
        "console=ttyS2,115200n8\0" \
        "mpurate=500\0" \
        "vram=12M\0" \
        "dvimode=1024x768MR-16@60\0" \
        "defaultdisplay=dvi\0" \
        "mmcdev=0\0" \
        "mmcroot=/dev/mmcblk0p2 rw\0" \
        "mmcrootfstype=ext3 rootwait\0" \
        "nandroot=/dev/mtdblock4 rw\0" \
        "nandrootfstype=jffs2\0" \
        "mmcargs=setenv bootargs console=${console} " \
                "mpurate=${mpurate} " \
                "vram=${vram} " \
                "omapfb.mode=dvi:${dvimode} " \
                "omapfb.debug=y " \
                "omapdss.def_disp=${defaultdisplay} " \
                "root=${mmcroot} " \
                "rootfstype=${mmcrootfstype}\0" \
        "nandargs=setenv bootargs console=${console} " \
                "mpurate=${mpurate} " \
                "vram=${vram} " \
                "omapfb.mode=dvi:${dvimode} " \
                "omapfb.debug=y " \
                "omapdss.def_disp=${defaultdisplay} " \
                "root=${nandroot} " \
                "rootfstype=${nandrootfstype}\0" \
LOOK!-> "loadbootscript=fatload mmc ${mmcdev} ${loadaddr} boot.scr\0" \
        "bootscript=echo Running bootscript from mmc ...; " \
                "source ${loadaddr}\0" \
        "loaduimage=fatload mmc ${mmcdev} ${loadaddr} uImage\0" \
        "mmcboot=echo Booting from mmc ...; " \
                "run mmcargs; " \
                "bootm ${loadaddr}\0" \
        "nandboot=echo Booting from nand ...; " \
                "run nandargs; " \
                "nand read ${loadaddr} 280000 400000; " \
                "bootm ${loadaddr}\0" \
#define CONFIG_BOOTCOMMAND \
        "if mmc rescan ${mmcdev}; then " \
                "if run loadbootscript; then " \
                        "run bootscript; " \
                "else " \
                        "if run loaduimage; then " \
                                "run mmcboot; " \
                        "else run nandboot; " \
                        "fi; " \
                "fi; " \
        "else run nandboot; fi"
Btw, you can change all kinds of fun stuff there, I recommend you take a look :D

Geek level: harder

Ok, so we have a self-made u-boot.bin and boot.scr. Why not have a MLO also? (MLO is the equivalent to grub's STAGE1 bootloader).
We grab the sources.
make distclean
make make omap3530beagle_config
make CROSS_COMPILE=arm-none-eabi-
This will result in a x-load.bin file. It's not ready yet, it needs to be signed (AFAIU, its just putting some size header, not real signing).
$ gcc scripts/signGP.c
$ ./a.out
And there we go! We can copy the x-load.bin.ift to the sdcard as MLO, then out u-boot.ini, our boot.src and we are good to go!

Next step

Have a kernel/init that allows USB console logging. Or, suboptimally, maybe just use a distro with a default ssh daemon...

2 comments:

Eliahu said...
This comment has been removed by the author.
Eliahu said...
This comment has been removed by the author.