ブログ

[A420][A440][bootloader][カスタマイズ]: USBデバイスが接続されている場合には強制的にフラッシュメモリから起動

at_nakai
2014年11月7日 14時21分

久しぶりにArmadillo-420/440のブートローダー「hermit-at」をカスタマイズしたので記事にしてみました。

【要件】

ブートローダーがLinuxを起動する際に、USBデバイスが接続されていればフラッシュメモリに格納されているシステムイメージを利用して起動する
上記が必要な場面は、電源ON/OFF(リセット)以外の制御が行えない状況下で、マイクロSDに格納されているシステムイメージを更新するといった場面です。
システムリカバリにも利用可能です。

【カスタマイズ内容】

  • USBコントローラ(USBOH)へクロックを供給
  • USBデバイスの接続状態を検出する関数を実装
  • Linux起動時にUSBデバイスの接続状態によって起動処理を変更
  • USBデバイスが接続されていれば、setbootdevice / setenv / bootコマンドの引数を無視してフラッシュメモリから起動されるように修正

【パッチ】

diff --git a/include/target/platform.h b/include/target/platform.h
index b917637..0fbc2c0 100644
--- a/include/target/platform.h
+++ b/include/target/platform.h
@@ -22,6 +22,7 @@ struct platform_info {
     void (*get_mac_address)(struct platform_info *pinfo, u8 *addr);
     void (*adjust_boot_args)(struct platform_info *pinfo,
                  int *argc, char *argv[]);
+    int (*is_usb_device_connected)(struct platform_info *pinfo, int port);
 
     void *private_data;
     char default_mtdparts[CMDLINE_MAXLEN];
diff --git a/src/target/armadillo4x0/board.c b/src/target/armadillo4x0/board.c
index 61f07cf..16d48da 100644
--- a/src/target/armadillo4x0/board.c
+++ b/src/target/armadillo4x0/board.c
@@ -33,6 +33,34 @@ static struct board_private board_priv;
 #define FLASH_ADDR(offset) (FLASH_START + (offset))
 #define RAM_ADDR(offset) (DRAM_START + (offset))
 
+static int mx25_is_usb_device_connected(struct platform_info *pinfo, int port)
+{
+    write32(0x53ff4148, 0x0);
+    write32(0x53ff4140, 0x80b02);
+    while (read32(0x53ff4140) & 0x2);
+
+    write32(0x53ff41a8, 0x3);
+    write32(0x53ff4184, 0x2001000);
+    mdelay(20);
+
+    write32(0x53ff4184, 0xe000000);
+    write32(0x53ff4140, 0x80b02);
+    while (read32(0x53ff4140) & 0x2);
+
+    write32(0x53ff41a8, 0x3);
+    write32(0x53ff4154, 0x863f9000);
+    write32(0x53ff4158, 0x863f7000);
+    write32(0x53ff4140, 0x10009);
+    write32(0x53ff4180, 0x1);
+    write32(0x53ff4148, 0x37);
+    write32(0x53ff4184, 0xc001000);
+    mdelay(20);
+
+    mdelay(100);
+
+    return read32(0x53ff4184) & 0x1;
+}
+
 static int is_valid_mac(u8 *mac)
 {
     int i;
@@ -397,6 +425,11 @@ static void armadillo4x0_setup_pmic(struct platform_info *pinfo)
     mc34704_write(2, 0x9);
 }
 
+static void armadillo4x0_setup_usbotg(struct platform_info *pinfo)
+{
+    mx25_ahb_clock_enable(12);
+}
+
 static void armadillo4x0_setup_ethernet(struct platform_info *pinfo)
 {
     struct board_private *priv = pinfo->private_data;
@@ -710,6 +743,7 @@ static void armadillo4x0_init(struct platform_info *pinfo)
     armadillo4x0_setup_watchdog(pinfo);
     armadillo4x0_setup_ethernet(pinfo);
     armadillo4x0_setup_pmic(pinfo);
+    armadillo4x0_setup_usbotg(pinfo);
 
     if (priv->type == BOARD_TYPE_ARMADILLO460)
         armadillo460_init(pinfo);
@@ -763,4 +797,6 @@ struct platform_info platform_info = {
 
     .net_dev = &mx25_fec,
     .mmcsd_dev = &mx25_mmcsd,
+
+    .is_usb_device_connected = &mx25_is_usb_device_connected,
 };
diff --git a/src/target/command/linux.c b/src/target/command/linux.c
index 0b35176..21281fc 100644
--- a/src/target/command/linux.c
+++ b/src/target/command/linux.c
@@ -327,7 +327,16 @@ static int boot_cmdfunc(int argc, char *argv[])
     char *c_argv[64];
     int ret;
     int i;
-    int mode = 0; /* NORMAL_BOOT */
+    int mode = 0; /* 0: NORMAL_BOOT, 1: MEDIA_BOOT, 2: CUSTOM_BOOT */
+
+    if (pinfo->is_usb_device_connected) {
+        ret = pinfo->is_usb_device_connected(pinfo, 0);
+        if (ret) {
+            hprintf("!! USB Device Detected. "
+                "So, do the Force boot operation...\n");
+            mode = 2;
+        }
+    }
 
     if (!strcmp(argv[0], "mediaboot"))
         mode = 1; /* MEDIA_BOOT */
@@ -337,6 +346,7 @@ static int boot_cmdfunc(int argc, char *argv[])
 
     led_on(LED_RED);
 
+    if (mode != 2)
 #if defined(CONFIG_CMD_SETENV)
     if (argc < 2) {
         char *param[64];
@@ -354,6 +364,10 @@ static int boot_cmdfunc(int argc, char *argv[])
         for (i=0; i<c_argc; i++)
             c_argv[i] = argv[i];
     }
+    else { /* mode == 2 */
+        c_argc = 1;
+        c_argv[0] = argv[0];
+    }
 
     if (pinfo->adjust_boot_args)
         pinfo->adjust_boot_args(pinfo, &c_argc, c_argv);
@@ -386,7 +400,7 @@ static int boot_cmdfunc(int argc, char *argv[])
     }
 
     ret = 1;
-    if (mode != 1) {
+    if (mode == 0) {
 #if defined(CONFIG_CMD_SETBOOTDEVICE)
         char param[CMDLINE_MAXLEN];
         ret = get_param_value("@bootdevice", param, CMDLINE_MAXLEN);
@@ -401,7 +415,7 @@ static int boot_cmdfunc(int argc, char *argv[])
                 bootdevice);
             return ret;
         }
-    } else {
+    } else if (mode == 1) {
 #if defined(CONFIG_COMPATIBLE_MEDIA_BOOT)
         char *bdevice[] = {
             "hda", "hdb", "hdc", "hdd",
@@ -416,6 +430,14 @@ static int boot_cmdfunc(int argc, char *argv[])
                 break;
         }
 #endif
+    } else if (mode == 2) {
+        hsprintf(bootdevice, "flash");
+        ret = load_image(bootdevice, 0);
+        if (ret) {
+            hprintf("failed image loading from '%s' device.\n",
+                bootdevice);
+            return ret;
+        }
     }
 
     irq_disable_all();

【動作確認】

■ 通常時 (SDブート)

Hermit-At v2.2.0-dirty (armadillo4x0) compiled at 14:50:30, Nov 05 2014
mmcsd: SD card at address 0x00000007
mmcsd: S04GG 3858432KiB
gendisk: /dev/mmcblk0p2: start=0x000f4956, size=0x00667554
gendisk: Image.gz is found. (1765042 Bytes)
Copying        kernel..done.
Uncompressing  kernel.............(割愛).................done.
Doing console=ttymxc1,115200
Doing noinitrd
Doing rootwait
Doing root=/dev/mmcblk0p2
Linux version 2.6.26-at20 (2.6.26) (atmark@atde3) (gcc version 4.3.2 (Debian 4.3.2-1.1) ) #1 PREEMPT Wed Sep 17 17:20:31 JST 2014

■ CON5下段にUSBメモリ接続時(フラッシュメモリブート)

Hermit-At v2.2.0-dirty (armadillo4x0) compiled at 14:50:30, Nov 05 2014
!! USB Device Detected. So, do the Force boot operation...
Uncompressing  kernel.............(割愛).................done.
Uncompressing ramdisk.............(割愛).................done.
Linux version 2.6.26-at19 (2.6.26) (atmark@atde3) (gcc version 4.3.2 (Debian 4.3.2-1.1) ) #3 PREEMPT Fri Jun 27 10:14:37 JST 2014