In my intended application, my BBB absolutely must default to booting from
the uSD when power is applied. I know I could short the boot switch, or
move pull-up/down resistors, or create a hardware switch gated from reset,
but I don't want to lose hardware compatibility with other BBB boards, or
give up the option of manually booting from eMMC occasionally. My goal is a
uSD configuration that can simply be inserted and booted by any BBB,
without making any hardware or software changes to the board or its eMMC.
Because this is so dependent on the boot environment of the BBB you are
using and the distro you want to boot, nobody can hand you an all-purpose
uEnv.txt file that will always work. This post is more of a play-by-play
description of how I made my two installations work together. It will
hopefully help other users analyze their own environments.
For now I'm accepting a limitation that the target BBB will be rev A6 or
newer, and the eMMC will contain the default Angstrom version
BBB-eMMC-flasher-2013.06.20 or BBB-eMMC-flasher-2013.09.04 - with a 3.8
kernel and compatible U-Boot version. Both of these have the default
bootcmd set to:
-----
bootcmd=gpio set 53; i2c mw 0x24 1 0x3e; run findfdt; mmc dev 0; if mmc
rescan ; then echo micro SD card found;setenv mmcdev 0;else echo No micro
SD card found, setting mmcdev to 1;setenv mmcdev 1;fi;setenv bootpart
${mmcdev}:2;mmc dev ${mmcdev}; if mmc rescan; then gpio set 54; echo SD/MMC
found on device ${mmcdev};if run loadbootenv; then echo Loaded environment
from ${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running
uenvcmd ...;run uenvcmd;fi;gpio set 55; if run loaduimage; then gpio set
56; run loadfdt;run mmcboot;fi;fi;
-----
While it is true that the BBB "checks for an inserted uSD at boot time", it
does not read the initial boot command from the uSD without the hardware
boot switch activated. MLO is read from the first (FAT) partition of the
eMMC, and it loads U-Boot.img from the eMMC. That bootcmd is compiled into
MLO, so given my boot process goal I'm stuck with it. Here's what it does:
bootcmd=
gpio set 53; [first LED]
i2c mw 0x24 1 0x3e; [raise input power limit]
run findfdt; [configure fdt file location]
mmc dev 0; [start search for valid boot partition at uSD]
if mmc rescan ; then echo micro SD card found; setenv mmcdev 0;
else echo No micro SD card found, setting mmcdev to 1; setenv mmcdev 1;
fi; [leave mmcdev set to first valid boot partition]
setenv bootpart ${mmcdev}:2; mmc dev ${mmcdev};
if mmc rescan; then gpio set 54; echo SD/MMC found on device ${mmcdev};
if run loadbootenv; then echo Loaded environment from ${bootenv};run
importbootenv;
fi; [load and "import" uEnv.txt --> now uSD can change things!]
if test -n $uenvcmd; then echo Running uenvcmd ...; run uenvcmd;
fi; [default uenvcmd is <null> so no action]
gpio set 55; [third LED]
if run loaduimage; then gpio set 56; run loadfdt; run mmcboot;
fi; [load uImage from /boot, am335x-boneblack.dtb, boot those]
fi;
Using uEnv.txt we can change the boot environment, but we can't change the
already running bootcmd. My choice of Ubuntu 12.04 for the uSD image uses
the more recent zImage format rather than Angstrom's uImage, so it would be
difficult to hack that final loaduimage process.
We can't just delete unwanted commands. The "test" command can cope with a
missing file, but the "run" command can't:
---
U-Boot# run loaduimage
## Error: "loaduimage" not defined
U-Boot# <INTERRUPT>
---
We could change the command itself, but it is tricky because substitutions
for the ${variables} are performed during the setenv:
---
U-Boot# setenv loaduimage load mmc ${bootpart} ${loadaddr}
${bootdir}/${bootfile}
U-Boot# echo $loaduimage
load mmc 0:2 0x80200000 /boot/uImage
---
In case you are testing these functions in U-Boot, avoid the temptation to
type "boot" or "bootd".
U-Boot# boot --> boot default, i.e., run 'bootcmd'
U-Boot# bootd --> boot default, i.e., run 'bootcmd'
In our scenario the default bootcmd is already running before we get to
insert our modifications, and we probably don't want to start over by
running it again.
If you aren't automatically dumped to the U-Boot prompt by a boot failure,
you need to be ready to hit a terminal key when the "Hit any key to stop
autoboot:" prompt appears. Obviously you need a debug terminal adapter
connected to the J1 serial port header. That prompt is the only place you
can stop the boot process; to "single-step" through the rest of your boot
you'll need to manually type or paste the commands to the U-Boot prompt.
It seems much simpler and closer to the design intention to add an
appropriate uenvcmd to our uEnv.txt. With that we can intercept the boot
process before it gets to loaduimage.
There are several critical clues we need in order to modify uEnv.txt
successfully:
1. The file must have UNIX line endings (<CR> only, not <CRLF>), and must
have a blank line as the last line.
2. A sequence of commands intended as a single variable value must be
delimited by ';' within a single line of the uEnv.txt file. If manually
entered at the U-Boot prompt for testing, the sequence must be enclosed by
double quotes.
3. Using "if" in a command without a matching "fi" produces a syntax error
from U-Boot!
4. The active uEnv.txt file is the one in the first (FAT) partition of the
boot medium. Once you are booted to Linux, it might be mounted as
/boot/uboot, and this warning is true: "The boot device will always be seen
by the OS as /dev/mmcblk0. U-Boot checks for an uSD card and swaps the
ordering if it's found." But while you are still in U-Boot, the uSD is
always 0 and the eMMC is always 1. The way to be sure you are changing the
right file is to check from within U-Boot. For the uSD (my 8GB card with
Ubuntu 12.04):
---
U-Boot# echo $mmcdev
0
U-Boot# mmc part
Partition Map for MMC device 0 -- Partition Type: DOS
Part Start Sector Num Sectors UUID Type
1 2048 2048 0005a754-01 01 Boot
2 4096 15640576 0005a754-02 83
U-Boot# ls mmc 0:1
104320 mlo
370652 u-boot.img
340 uenv.txt
---
For the eMMC (with default Angstrom):
---
U-Boot# ls mmc 1:1
99976 mlo
379428 u-boot.img
26 uenv.txt
---
The uenvcmd we want to add will depend upon the Linux distribution we want
to boot from our uSD. I'm working with
ubuntu-precise-12.04.3-armhf-3.8.13-bone30, which normally boots like this:
---
bootcmd=run findfdt; run mmcboot;setenv mmcdev 1; setenv bootpart 1:2; run
mmcboot;run nandboot;
---
If the uSD boot is successful, only this part gets executed:
---
run findfdt; run mmcboot;
---
Here's findfdt:
---
findfdt=if test $board_name = A335BONE; then setenv fdtfile
am335x-bone.dtb; fi; if test $board_name = A335BNLT; then setenv fdtfile
am335x-boneblack.dtb; fi; if test $board_name = A33515BB; then setenv
fdtfile am335x-evm.dtb; fi; if test $board_name = A335X_SK; then setenv
fdtfile am335x-evmsk.dtb; fi; if test $fdtfile = undefined; then echo
WARNING: Could not determine device tree to use; fi;
---
The second option succeeds - fdtfile=am335x-boneblack.dtb. No other
effects.
And here's mmcboot, which executes to its end:
---
mmcboot=mmc dev ${mmcdev}; if mmc rescan; then echo SD/MMC found on device
${mmcdev};if run loadbootenv; then echo Loaded environment from
${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running
uenvcmd ...;run uenvcmd;fi;if run loadimage; then run mmcloados;fi;fi;
---
Loadbootenv and importbootenv read and apply uEnv.txt, which we will
already have done by the time our replacement mmcboot runs.
Since we will have co-opted uenvcmd, we need to remember not to run uenvcmd
again here!
Loadimage loads a zImage file.
Mmcloados loads the fdt file (if available) and the actual zImage:
---
mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try;
then if run loadfdt; then bootz ${loadaddr} - ${fdtaddr}; else if test
${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi;
else bootz; fi;
---
We need to keep the loadfdt and bootz parts.
Mmcargs sets several things that didn't seem important at first, but proved
necessary! Without these, the boot process will look exactly like a good
boot on your terminal, but the BBB will just lock up after "Uncompressing
Linux... done, booting the kernel". All the correct arguments may be
visible in your printenv, but if they are not set into "bootargs" the boot
fails.
---
mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot}
rootfstype=${mmcrootfstype}
---
Other possible causes of failure at this point:
<http://processors.wiki.ti.com/index.php/Kernel_-_Common_Problems_Booting_Linux>
-----
Problem #2 - No more output is seen on the console after "booting the
kernel"
Cause #1 - The linux console boot parameter is incorrect
Cause #2 - Mis-match between boot-loader and kernel machine numbers
Cause #3 - A software bug
-----
Booting Ubuntu normally via the boot switch produces this console output:
---
mmc0 is current device
SD/MMC found on device 0
reading uEnv.txt
340 bytes read in 3 ms (110.4 KiB/s)
Loaded environment from uEnv.txt
Importing environment from mmc ...
Running uenvcmd ...
3314544 bytes read in 474 ms (6.7 MiB/s)
24884 bytes read in 32 ms (758.8 KiB/s)
Kernel image @ 0x80200000 [ 0x000000 - 0x329370 ]
## Flattened Device Tree blob at 80f80000
Booting using the fdt blob at 0x80f80000
Using Device Tree in place at 80f80000, end 80f89133
Starting kernel ...
---
So our new unevcmd is simple:
+++
uenvcmd=run findfdt; run mmcboot;
+++
The default Angstrom findfdt produces the same result so we don't need to
worry about it:
---
findfdt=if test $board_name = A33515BB; then setenv fdtfile am335x-evm.dtb;
fi; if test $board_name = A335X_SK; then setenv fdtfile am335x-evmsk.dtb;
fi;if test $board_name = A335BONE; then setenv fdtfile am335x-bone.dtb; fi;
if test $board_name = A335BNLT; then setenv fdtfile am335x-boneblack.dtb; fi
---
The default Ubuntu mmcboot would read uEnv.txt again, and run uenvcmd
again, so we'll need to change this command:
---
mmcboot=mmc dev ${mmcdev}; if mmc rescan; then echo SD/MMC found on device
${mmcdev};if run loadbootenv; then echo Loaded environment from
${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running
uenvcmd ...;run uenvcmd;fi;if run loadimage; then run mmcloados;fi;fi;
---
The default Angstrom mmcboot is looking for a uImage, so it won't work
either:
---
mmcboot=echo Booting from mmc ...; run mmcargs; bootm ${kloadaddr} -
${fdtaddr}
---
We already know we want to boot from a good uSD, and have dealt with
uEnv.txt, so our new mmcboot can go directly to:
+++
mmcboot=if run loadimage; then run mmcloados; fi;
+++
Since we know we have an fdt file, mmcloados can go directly to:
+++
mmcloados=run mmcargs; if run loadfdt; then bootz ${loadaddr} - ${fdtaddr};
fi;
+++
The uEnv.txt file for our uSD needs these additions. In case there are
immediate substitutions, it is probably smart to apply them in order of
reference:
+++
mmcloados=run mmcargs; if run loadfdt; then bootz ${loadaddr} - ${fdtaddr};
fi;
mmcboot=if run loadimage; then run mmcloados; fi;
uenvcmd=run findfdt; run mmcboot;
+++
There are many more prerequisites we need to control before those three
commands can run successfully...
The default Ubuntu uenv.txt contains:
---
mmcpart=2
optargs=fixrtc
uenvcmd=i2c mw 0x24 1 0x3e; kd=0; if test $mmcdev -eq 1; then mmc dev 0; if
mmc rescan; then kd=1; fi; mmc dev 1; fi; setenv mmcroot
/dev/mmcblk${kd}p${mmcpart} ro
loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdtaddr} ${bootdir}/dtbs/${fdtfile}
loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${bootdir}/${bootfile}
-----
Mmcpart seems to be used in the Ubuntu boot only by the two load...
commands, which are reaching into the Linux filesystem (mmc 0:2) to load
the fdt file and Kernel. It shouldn't break any of our other functions.
Optargs=fixrtc seems to be in every uEnv, but I can't find an explanation.
Uenvcmd we will change - but we might want to preserve the option for
booting via the BBB boot switch using the environment on the uSD. So the
essential parts of what it does might need to be moved to other commands...
Loadfdt we call from mmcloados from mmcboot. But the Angstrom version of
loadfdt is slightly different:
---
loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
---
So we need to be sure the Ubuntu version is loaded:
+++
loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdtaddr} ${bootdir}/dtbs/${fdtfile}
+++
As it normally is from the Ubuntu uEnv.txt.
Incidentally, loadfdt can complain explicitly about File not found!
Eliminates some possibilities for the source of any problems...
U-Boot# run loadfdt
** File not found /boot/dtbs/am335x-boneblack.dtb **
If it is successful you see something like:
U-Boot# run loadfdt
24808 bytes read in 51 ms (474.6 KiB/s)
Loadimage we call from mmcboot. It is not set by Angstrom, so we need the
version from the Ubuntu uEnv.txt. That uses bootfile, which is set to
uImage in Angstrom; we must reset it to zImage before adding loadimage:
+++
bootfile=zImage
loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${bootdir}/${bootfile}
+++
The default Ubuntu uenvcmd, which will be completely replaced. These
functions might need to be performed by some other mechanism:
---
i2c mw 0x24 1 0x3e;
kd=0;
if test $mmcdev -eq 1;
then mmc dev 0;
if mmc rescan;
then kd=1;
fi;
mmc dev 1;
fi;
setenv mmcroot /dev/mmcblk${kd}p${mmcpart} ro
---
"i2c mw 0x24 1 0x3e" is a standalone power limit command in many uEnv.txt
files, and can be in ours.
The rest of that code just sets mmcdev which is already set by several
commands, and mmcroot which is part of the mmcargs/bootargs configuration
and can be left at the default "mmcroot=/dev/mmcblk0p2 ro" set by both boot
environments.
With variables organized in the order they will be needed for replacements
into higher commands, the final uEnv.txt looks like this:
+++
i2c mw 0x24 1 0x3e
optargs=fixrtc earlyprintk=serial,ttyO0,115200n8 print_fatal_signals=1
mmcpart=2
bootfile=zImage
loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdtaddr} ${bootdir}/dtbs/${fdtfile}
loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} ${bootdir}/${bootfile}
mmcloados=run mmcargs; if run loadfdt; then bootz ${loadaddr} - ${fdtaddr};
fi;
mmcboot=if run loadimage; then run mmcloados; fi;
uenvcmd=run findfdt; run mmcboot;
+++
My Windows sftp client can't copy the file to /boot/uboot within Ubuntu,
even though it sees the files there (/dev/mmcblk0p1 1004K 470K 534K 47%
/boot/uboot). Lack of permissions, I guess. I can copy it to /home and then
copy it onward from within Ubuntu. Copying it to the first FAT partition of
the uSD via a card reader in Windows or another Linux machine also works.
Once the changed file appears to be in place on the uSD, you _must_ use
something like "sudo shutdown -h now" in order to force it to be written to
the uSD. Just cycling power will leave you with your previous file!
And... After days of rich "learning experiences", it works! When I apply
power, my uSD boots. When I remove the uSD and apply power, Angstrom boots
from the eMMC. Seems that is how it should work by default...
In web posts I found several "optargs" that supposedly give you more boot
log information sooner in the process. I haven't tried them individually,
but using:
optargs=fixrtc earlyprintk=serial,ttyO0,115200n8 debug ignore_loglevel
log_buf_len=10M print_fatal_signals=1 LOGLEVEL=8
instead of:
optargs=fixrtc earlyprintk=serial,ttyO0,115200n8 print_fatal_signals=1
did add detail. But it kept adding detail after the boot was complete,
making normal terminal interaction on the same tty impossible.
Additional info began at the "<--" mark:
-----
Uncompressing Linux... done, booting the kernel.
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Linux version 3.8.13-bone30 (root@imx6q-sabrelite-1gb-1)
(gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #1 SMP Thu Nov 14
11:19:20 UTC 2013
[ 0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7),
cr=10c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing
instruction cache
[ 0.000000] Machine: Generic AM33XX (Flattened Device Tree), model: TI
AM335x BeagleBone
[ 0.000000] bootconsole [earlycon0] enabled
[ 0.000000] debug: ignoring loglevel setting. <-- full logging begins
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.000000] On node 0 totalpages: 130816
[ 0.000000] free_area_init_node: node 0, pgdat c09ba540, node_mem_map
c0a35000
[ 0.000000] Normal zone: 1024 pages used for memmap
[ 0.000000] Normal zone: 0 pages reserved
[ 0.000000] Normal zone: 129792 pages, LIFO batch:31
[ 0.000000] AM335X ES1.0 (neon )
-----
I'm not sure the added info would help much. Apparently the best way to
look into the early boot process is to re-build your kernel with
CONFIG_DEBUG_LL enabled. Haven't tried that. I suspect my main failure mode
didn't get to the actual kernel at all, despite claiming to have loaded
something to the correct address and uncompressed it.
=====
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.