August 28, 2010

Froyo on Nitrogen-E

Froyo for i.MX51 has arrived!

We’ve been waiting for the Froyo release from Freescale to enable our efforts in Android integration, and the wait is now over. Freescale’s imx-android-r9 release is based on Froyo and has some nice new features.

In this article, I’ll walk through the steps I used to acquire, compile and deploy Froyo for our Nitrogen-E board.

To begin with, everything starts with the 400+MB package imx-android-r9.tar.gz. The steps I’ll walk through below are largely based on the file doc/i_MX_Android_R9_User_Guide.html contained within, tailored to show where we differ from the Freescale Babbage platform.

The Freescale notes explain how to get the Froyo baseline release:

    $ mkdir ~/myandroid
    $ cd ~/myandroid
    $ wget http://android.git.kernel.org/repo
    $ chmod a+x ./repo
    $ ./repo init -u git://android.git.kernel.org/platform/manifest.git -b froyo
    $ cp /opt/imx-android-r9/code/r9/default.xml .repo/manifests/default.xml
    $ ./repo sync

They also explain how to retrieve the Freescale kernel and U-Boot patches from their respective repositories:

    $ cd ~/myandroid
    $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-2.6.31.y.git kernel_imx
    $ cd ~/myandroid/bootable/bootloader
    $ git clone git://git.denx.de/u-boot.git uboot-imx

Then they explain how to patch Android, U-Boot, and Linux with the Freescale updates using a provided patch script.

$ cd ~/myandroid
$ . /opt/imx-android-r9/code/r9/and_patch.sh
$ help                  # You should see "c_patch" function
$ c_patch /opt/imx-android-r9/code/r9 imx_r9

If everything goes smoothly, you should see a message like this:

    **************************************************************
    Success: Now you can build android code for FSL i.MX platform
    **************************************************************

Even though we have separate repositories for our Linux kernel and U-Boot, I allowed c_patch to perform its updates. Alternatively, you could skip the clones of the kernel and U-Boot trees by removing the first two lines of /opt/imx-android-r9/code/r9/baseversion:

1	CHANGE	3d35d87d5482de23cd5dc4d7721b1086107cae50	bootable/bootloader/uboot-imx	platform/bootable/bootloader/uboot-imx
2	NEW	74fca6a42863ffacaf7ba6f1936a9f228950f657	kernel_imx	kernel/imx

I believe that each line of this file tells c_patch to add, update, or keep a particular directory within the tree parented at the current working directory.

So, now we have a working tree, allowing us to compile U-Boot, Linux, and Android. We’ll take a little detour first, because we’ll want to use the Boundary versions of kernel and U-Boot.

I created a new branch in our kernel tree named imx-android-r9. I checked it out and compiled it like so:

user@host:~/myandroid$ rm -rf kernel_imx
user@host:~/myandroid$ git clone -b imx-android-r9 https://boundarydevices.com/git-repos/linux-bd.git kernel_imx
user@host:~/myandroid$ cd kernel_imx
user@host:~/myandroid/kernel_imx$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- nitrogen_android_defconfig
user@host:~/myandroid/kernel_imx$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage modules

In the U-Boot case, I just checked out and built the current head, boundary20100817:

user@host:~/myandroid/bootable/bootloader$ rm -rf uboot-imx
user@host:~/myandroid/bootable/bootloader$ git clone -b boundary20100817 https://boundarydevices.com/git-repos/u-boot-nitrogen.git uboot-imx
user@host:~/myandroid/bootable/bootloader$ cd uboot-imx
user@host:~/myandroid/bootable/bootloader/uboot-imx$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- nitrogen_config
user@host:~/myandroid/bootable/bootloader/uboot-imx$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- all

At this point, we can build Froyo as described in the Freescale manual. We’re basing our Nitrogen-E platform on the Freescale Babbage, so the command line is this:

user@host:~/myandroid$ make PRODUCT-imx51_bbg-eng 2>&1 | tee build_imx51_bbg_android.log

And, as mentioned in the Freescale docs, the output is placed in ~/myandroid/out/target/:

user@host:~/myandroid$ ls -l out/target/product/imx51_bbg/
total 313748
-rw-r--r--  1 ericn ericn        16 2010-08-24 16:40 android-info.txt
-rw-r--r--  1 ericn ericn      8866 2010-08-27 15:59 clean_steps.mk
drwxr-xr-x  3 ericn ericn      4096 2010-08-17 12:47 data
-rw-r--r--  1 ericn ericn     24942 2010-08-27 16:02 installed-files.txt
drwxr-xr-x 13 ericn ericn      4096 2010-08-24 16:40 obj
-rw-r--r--  1 ericn ericn       189 2010-08-27 15:59 previous_build_config.mk
-rw-r--r--  1 ericn ericn    212576 2010-08-27 16:02 ramdisk.img
drwxr-xr-x  3 ericn ericn      4096 2010-08-24 16:40 recovery
-rw-r--r--  1 ericn ericn   4710400 2010-08-27 16:02 recovery.img
drwxr-xr-x  8 ericn ericn      4096 2010-08-27 14:35 root
drwxr-xr-x  4 ericn ericn      4096 2010-08-17 12:47 symbols
drwxr-xr-x 11 ericn ericn      4096 2010-08-27 16:03 system
-rw-r--r--  1 ericn ericn 106344448 2010-08-27 16:02 system.img
-rw-r--r--  1 ericn ericn 209715200 2010-08-24 16:40 userdata.img

The .img files are ext3 filesystem images with one exception: ramdisk.img is a gzipped cpio archive, which makes it easier to create a RAM disk suitable for use with U-Boot.

When creating a bootable SD card, I’ll use the directories instead. I’ll also assume that you have a completely blank SD card to start with.

The first step will be to partition the card. I’ll use roughly the same partitioning scheme that the Freescale docs outline, with a VFAT partition labelled BOOT, followed by four ext3 partitions labelled SYSTEM, DATA, CACHE, and RECOVERY respectively. Then I’ll add an second VFAT partition to house MEDIA to keep it away from our boot partition. Note that these instructions are for a 4GB card. You’ll want to rework things for other sizes.

I’ll also install our first-level boot loader at offset 1k:

user@host:~$ sudo dd bs=512 seek=2 if=sdmmc of=/dev/mmcblk0
user@host:~$ echo -e "nnpn1nn+100Mnnnpn2nn+200Mnnnen3nn+1Gnnnpnn+300Mnnnn+100Mnnnn+100Mnnnn+100Mntn1nbntn2n83ntn4n83ntn5n83ntn6n83ntn7nbnwn" | sudo fdisk /dev/mmcblk0
user@host:~$ sudo fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 3999 MB, 3999268864 bytes
4 heads, 16 sectors/track, 122048 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x986e3cfa

        Device Boot      Start         End      Blocks   Id  System
/dev/mmcblk0p1               1        3201      102424    b  W95 FAT32
/dev/mmcblk0p2            3202        9602      204832   83  Linux
/dev/mmcblk0p3            9603       42371     1048608    5  Extended
/dev/mmcblk0p4           42372       51972      307232   83  Linux
/dev/mmcblk0p5            9603       12803      102424   83  Linux
/dev/mmcblk0p6           12804       16004      102424   83  Linux
/dev/mmcblk0p7           16005       19205      102424    b  W95 FAT32
user@host:~$ sudo mkdosfs /dev/mmcblk0p1 -n BOOT
user@host:~$ sudo mkfs.ext3 /dev/mmcblk0p2 -L SYSTEM
user@host:~$ sudo mkfs.ext3 /dev/mmcblk0p4 -L RECOVERY
user@host:~$ sudo mkfs.ext3 /dev/mmcblk0p5 -L DATA
user@host:~$ sudo mkfs.ext3 /dev/mmcblk0p6 -L CACHE
user@host:~$ sudo mkdosfs /dev/mmcblk0p7 -n MEDIA
user@host:~$ sync

Removing and re-inserting the SD card, you can see the resulting volumes more clearly:

user@host:~$ df -h | grep media | sort
/dev/mmcblk0p1        100M     0  100M   0% /media/BOOT
/dev/mmcblk0p2        194M  5.6M  179M   4% /media/SYSTEM
/dev/mmcblk0p4        291M   11M  266M   4% /media/RECOVERY
/dev/mmcblk0p5         97M  5.6M   87M   7% /media/DATA
/dev/mmcblk0p6         97M  5.6M   87M   7% /media/CACHE
/dev/mmcblk0p7        2.8G  4.0K  2.8G   1% /media/MEDIA

Since we’ve already copied the first-level loader sdmmc, there are three partitions that we need to create:

  1. out/target/product/imx51_bbg/system/* goes into the /media/SYSTEM partition
  2. out/target/product/imx51_bbg/system/recovery/root goes into /media/RECOVERY
  3. U-Boot, the Linux kernel, and the initial RAM disk go into the /media/BOOT partition

The first two can be done directly:

user@host:~$ sudo cp -arvf ~/myandroid/out/target/product/imx51_bbg/system/* /media/SYSTEM/
user@host:~$ sudo cp -arvf ~/myandroid/out/target/product/imx51_bbg/recovery/root/* /media/RECOVERY

The first two components of the BOOT partition are also just copies:

user@host:~$ cp -vf ~/myandroid/kernel_imx/arch/arm/boot/uImage /media/BOOT
user@host:~$ cp -vf ~/myandroid/bootable/bootloader/uboot-imx/u-boot.bin /media/BOOT

The third requires that we wrap the ramdisk with a U-Boot header:

user@host:~$ mkimage -A arm -O linux -T ramdisk -n "Initial Ram Disk"
                      -d ~/myandroid/out/target/product/imx51_bbg/ramdisk.img
                      /media/BOOT/initrd.u-boot

Alright, that’s all the copying to be done. We have a couple of other steps to take before running Android, but first we need to boot this card:

user@host:~$ sync && sudo umount /media/*

Inserting this into a Nitrogen, you should be able to boot to the SD card. Interrupt the boot and set up the display and boot arguments as shown below for a 7″ CMO panel:

U-Boot > set bootargs console=ttymxc0,115200 video=mxcdi1fb:raw:24000000,800,480,1,2,2,0,18,24,90,2,4,4,1,0,565 di1_primary
               init=/init no_console_suspend
U-Boot > set bootcmd 'fatload mmc 0 92000000 uImage && fatload mmc 0 92400000 initrd.u-boot && bootm 92000000 92400000'

The ‘no_console_suspend’ clause tells Android to keep the serial console alive. Since we haven’t configured any buttons yet, this is very useful.

That’s it for now. You should be able to boot the Froyo version of Android using just these steps. If you’ve installed the Android SDK and have a USB connection to the Nitrogen, you should be able to see the device using adb:

user@host:~$ sudo ~/android-sdk-linux_86/tools/adb start-server
user@host:~$ ~/android-sdk-linux_86/tools/adb devices
List of devices attached
0123456789ABCDEF	device
user@host:~$ ~/android-sdk-linux_86/tools/adb shell
#
# ps
USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
root      1     0     312    220   c00b42b4 0000cf5c S /init
root      2     0     0      0     c0060168 00000000 S kthreadd
root      3     2     0      0     c005114c 00000000 S ksoftirqd/0
root      4     2     0      0     c005cc20 00000000 S events/0
root      5     2     0      0     c005cc20 00000000 S khelper
root      8     2     0      0     c0066020 00000000 S async/mgr
root      11    2     0      0     c005cc20 00000000 S suspend
root      177   2     0      0     c005cc20 00000000 S kblockd/0
root      187   2     0      0     c005cc20 00000000 S mxc_spi.0
root      192   2     0      0     c005cc20 00000000 S ksuspend_usbd
root      197   2     0      0     c01ca05c 00000000 S khubd
root      209   2     0      0     c005cc20 00000000 S kmmcd
root      216   2     0      0     c0225c40 00000000 S pmic-event-thre
root      299   2     0      0     c0083b20 00000000 S pdflush
root      300   2     0      0     c0083b20 00000000 S pdflush
root      301   2     0      0     c0088468 00000000 S kswapd0
root      348   2     0      0     c005cc20 00000000 S aio/0
root      357   2     0      0     c005cc20 00000000 S nfsiod
root      361   2     0      0     c005cc20 00000000 S crypto/0
root      961   2     0      0     c0197ee0 00000000 S kapmd
root      1058  2     0      0     c005cc20 00000000 S kstriped
root      1062  2     0      0     c005cc20 00000000 S kconservative/0
root      1096  2     0      0     c005cc20 00000000 S usbhid_resumer
root      1099  2     0      0     c005cc20 00000000 S binder
root      1118  2     0      0     c0239570 00000000 S mmcqd
root      1144  2     0      0     c005cc20 00000000 S rpciod/0
root      1154  2     0      0     c01e9dc0 00000000 S usb_mass_storag
root      1159  2     0      0     c0226934 00000000 S mxc_ts
root      1990  2     0      0     c010d624 00000000 S kjournald
root      1998  2     0      0     c010d624 00000000 S kjournald
root      1999  2     0      0     c010d624 00000000 S kjournald
root      2001  1     712    300   c0185ea0 afd0d8fc S /system/bin/sh
system    2002  1     780    292   c0250370 afd0db9c S /system/bin/servicemanager
root      2003  1     3712   568   ffffffff afd0e20c S /system/bin/vold
root      2004  1     3700   548   ffffffff afd0e20c S /system/bin/netd
root      2005  1     640    252   c0280bec afd0e52c S /system/bin/debuggerd
root      2006  1     120948 26936 c00b42b4 afd0dcc4 S zygote
media     2007  1     41776  4796  ffffffff afd0db9c S /system/bin/mediaserver
bluetooth 2008  1     1236   712   c00b42b4 afd0e9dc S /system/bin/dbus-daemon
root      2009  1     780    316   c02dc474 afd0d8fc S /system/bin/installd
log       2010  1     640    288   c0185ea0 afd0d8fc S /system/bin/logwrapper
root      2011  1     3380   184   ffffffff 0000f474 S /sbin/adbd
dhcp      2015  2010  820    400   c00b42b4 afd0e9dc S /system/bin/dhcpcd
system    2061  2006  268488 35968 ffffffff afd0db9c S system_server
root      2073  2     0      0     c005cc20 00000000 S z1xx_workq
app_33    2167  2006  166972 21676 ffffffff afd0eb58 S com.android.inputmethod.latin
radio     2173  2006  187884 23688 ffffffff afd0eb58 S com.android.phone
app_16    2182  2006  213292 25104 ffffffff afd0eb58 S com.android.launcher
system    2201  2006  182528 20184 ffffffff afd0eb58 S com.android.settings
app_7     2254  2006  191112 26672 ffffffff afd0eb58 S android.process.acore
app_0     2277  2006  162876 19808 ffffffff afd0eb58 S com.android.providers.calendar
app_1     2298  2006  176300 20556 ffffffff afd0eb58 S android.process.media
app_6     2326  2006  183544 20764 ffffffff afd0eb58 S com.android.mms
app_12    2349  2006  179228 21312 ffffffff afd0eb58 S com.android.email
app_19    2374  2006  161860 19936 ffffffff afd0eb58 S com.android.deskclock
app_20    2386  2006  161936 19756 ffffffff afd0eb58 S com.android.bluetooth
app_8     2394  2006  162864 19664 ffffffff afd0eb58 S com.android.quicksearchbox
app_17    2405  2006  160084 18816 ffffffff afd0eb58 S com.android.protips
app_28    2412  2006  162396 19196 ffffffff afd0eb58 S com.android.music
app_2     2421  2006  163700 20384 ffffffff afd0eb58 S com.cooliris.media
root      2431  2011  712    320   c004ed0c afd0e80c S /system/bin/sh
root      2433  2431  860    340   00000000 afd0d8fc R ps
#

In my next post, I’ll cover some of the quirks (especially touch-screen) and discuss how to actually tailor things for the Nitrogen and explain how we’re keeping track of changes.