recovery: update is modified to support various image
authorSanghee Kim <sh0130.kim@samsung.com>
Fri, 30 Apr 2010 05:20:34 +0000 (14:20 +0900)
committerSanghee Kim <sh0130.kim@samsung.com>
Fri, 30 Apr 2010 05:20:34 +0000 (14:20 +0900)
both u-boot's update and recovery's update are modified.
support only OneNAND boot with fixed block size.
update target:
  ipl + recovery + u-boot / ipl + u-boot / u-boot
binary will be released using 'u-boot-recovery-evt*.bin'

common/cmd_usbd.c
include/configs/s5pc1xx_universal.h
recovery/board/samsung/universal/universal.c
recovery/recovery.c
recovery/recovery.h
recovery/serial.c
recovery/usbd.c

index 6f7dc7b..2a1c15a 100644 (file)
@@ -199,6 +199,10 @@ static int nand_cmd(int type, char *p1, char *p2, char *p3)
                printf("%s %s %s %s %s\n", argv[0], argv[1], argv[2],
                                argv[3], argv[4]);
                ret = nand_func(NULL, 0, 5, argv);
+       } else if (type == 3) {
+               char *argv[] = {nand_name, "lock", p1, p2};
+               printf("%s %s %s %s\n", argv[0], argv[1], argv[2], argv[3]);
+               ret = nand_func(NULL, 0, 4, argv);
        }
 
        if (ret)
@@ -558,7 +562,7 @@ static int write_file_system(char *ramaddr, ulong len, char *offset,
 /* Parsing received data packet and Process data */
 static int process_data(struct usbd_ops *usbd)
 {
-       ulong cmd = 0, arg = 0, len = 0, flag = 0;
+       ulong cmd = 0, arg = 0, ofs = 0, len = 0, flag = 0;
        char offset[12], length[12], ramaddr[12];
        int recvlen = 0;
        unsigned int blocks = 0;
@@ -813,6 +817,69 @@ static int process_data(struct usbd_ops *usbd)
        /* Erase and Write to NAND */
        switch (img_type) {
        case IMG_BOOT:
+               ofs = parts[part_id]->offset;
+#ifdef CONFIG_RECOVERY
+       {
+               /* block is fixed:
+                       1m = ipl(16k)+recovery(240k)+bootloader(768k)*/
+               u32 *buf = (long *)down_ram_addr;
+               u32 ofst;
+               u32 bootloader_edge = parts[part_id]->size;
+               u32 bootloader_addr = bootloader_edge >> 2;
+               u32 recovery_edge = bootloader_addr;
+               u32 recovery_addr = recovery_edge >> 4;
+               u32 ipl_edge = recovery_addr;
+               u32 ipl_addr = 0;
+               int ret, retlen;
+
+               if (len > bootloader_addr) {
+                       ofst = bootloader_addr/sizeof(buf);
+                       if (*(buf + ofst) == 0xea000012) {
+                               /* case: ipl + recovery + bootloader */
+                               printf("target: ipl + recovery + loader\n");
+                               ofs = ipl_addr;
+                       } else {
+                               /* case: unknown format */
+                               printf("target: unknown\n");
+                               *((ulong *) usbd->tx_data) = STATUS_ERROR;
+                               usbd->send_data(usbd->tx_data, usbd->tx_len);
+                               return 0;
+                       }
+               } else {
+                       ofst = recovery_addr/sizeof(buf);
+                       if (*(buf + ofst) == 0xea000012 &&
+                               *(buf + ofst - 1) == 0x00000000) {
+                               /* case: ipl + bootloader (old type) */
+                               printf("target: ipl + bootloader\n");
+                               ofs = ipl_addr;
+                       } else {
+                               /* case: bootloader only */
+                               printf("target: bootloader\n");
+                               ofs = bootloader_addr;
+
+                               /* skip revision check */
+                               down_mode = MODE_FORCE;
+                       }
+               }
+
+               sprintf(offset, "%x", ofs);
+               sprintf(length, "%x", parts[part_id]->size);
+
+               /* check block is locked/locked-tight */
+               ret = nand_cmd(3, offset, length, NULL);
+               if (ret) {
+                       printf("target is locked%s\n",
+                               (ret == 1) ? "-tight" : "");
+                       printf("-> try at recovery mode \
+                               to update 'system'.\n");
+                       printf("   how-to: reset \
+                               while pressing volume up and down.\n");
+                       *((ulong *) usbd->tx_data) = STATUS_ERROR;
+                       usbd->send_data(usbd->tx_data, usbd->tx_len);
+                       return 0;
+               }
+       }
+#endif
 #ifdef CONFIG_S5PC1XX
                /* Workaround: for prevent revision mismatch */
                if (cpu_is_s5pc110() && (down_mode != MODE_FORCE)) {
@@ -854,7 +921,16 @@ static int process_data(struct usbd_ops *usbd)
                        nand_cmd(0, offset, length, NULL);
                }
 #endif
-               /* Fall through for write bootloader */
+               sprintf(offset, "%x", ofs);
+               sprintf(length, "%x", parts[part_id]->size);
+
+               /* Erase */
+               nand_cmd(0, offset, length, NULL);
+               /* Write */
+               sprintf(length, "%x", (unsigned int) len);
+               ret = nand_cmd(1, ramaddr, offset, length);
+               break;
+
        case IMG_KERNEL:
                sprintf(offset, "%x", parts[part_id]->offset);
                sprintf(length, "%x", parts[part_id]->size);
index 7db3b45..c4ffa75 100644 (file)
@@ -37,6 +37,7 @@
 #define CONFIG_S5PC110         1       /* which is in a S5PC110 */
 #define CONFIG_UNIVERSAL       1       /* working with Universal */
 #define CONFIG_MACH_AQUILA     1       /* working with Aquila */
+#define CONFIG_RECOVERY                1       /* working with recovery block */
 
 #include <asm/arch/cpu.h>              /* get chip and board defs */
 
index 6041202..02a4388 100644 (file)
@@ -99,70 +99,132 @@ static int check_block(void)
        struct mtd_info *mtd = onenand_ops->mtd;
        struct onenand_chip *this = mtd->priv;
        int i;
-       int page_to_check = 4;
-       int ret, retlen = 0;
-       ulong blocksize = 1 << this->erase_shift;
-       ulong pagesize = 1 << this->page_shift;
-       u_char *down_ram_addr;
-       ulong uboot_addr;
-       u_char verify_buf[0x10];
-
-       down_ram_addr = (unsigned char *)CONFIG_SYS_DOWN_ADDR;
-       uboot_addr = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
-
-       onenand_ops->read(uboot_addr, blocksize, &retlen, down_ram_addr, 0);
-       if (retlen != blocksize)
+       int retlen = 0;
+       u32 from = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
+       u32 len = 1 << this->erase_shift;
+       u32 *buf = (u32 *)CONFIG_SYS_DOWN_ADDR;
+
+       /* check first page of bootloader*/
+       onenand_ops->read(from, len, (ssize_t *)&retlen, (u_char *)buf, 0);
+       if (retlen != len)
                return 1;
 
-       memset(verify_buf, 0xFF, sizeof(verify_buf));
+       for (i = 0; i < (this->writesize / sizeof(this->writesize)); i++)
+               if (*(buf + i) != 0xffffffff)
+                       return 0;
 
-       for (i = 0; i < page_to_check; i++) {
-               ret = memcmp(down_ram_addr + pagesize*i, verify_buf,
-                               sizeof(verify_buf));
-               if (ret)
-                       break;
-       }
-
-       if (i == page_to_check)
-               return 1;
-
-       return 0;
+       return 1;
 }
 
 int board_check_condition(void)
 {
        if (check_keypad()) {
-               PUTS("manual mode\n");
+               PUTS("check: manual\n");
                return 1;
        }
 
        if (check_block()) {
-               PUTS("bootloader image broken\n");
-               return 1;
+               PUTS("check: bootloader broken\n");
+               return 2;
        }
 
        return 0;
 }
 
-int board_load_uboot(unsigned char *buf)
+int board_load_bootloader(unsigned char *buf)
 {
        struct mtd_info *mtd = &onenand_mtd;
        struct onenand_chip *this = mtd->priv;
-       int offset;
-       size_t size;
-       size_t ret;
+       u32 ofs, len, retlen;
 
-       offset = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
-       size = CONFIG_SYS_MONITOR_LEN;
+       ofs = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
+       len = CONFIG_SYS_MONITOR_LEN;
 
-       mtd->read(mtd, offset, size, &ret, buf);
+       mtd->read(mtd, ofs, len, &retlen, buf);
 
-       if (size != ret)
+       if (len != retlen)
                return -1;
 
        return 0;
 }
 
+int board_lock_recoveryblock(void)
+{
+       struct mtd_info *mtd = &onenand_mtd;
+       struct onenand_chip *this = mtd->priv;
+       u32 ofs = 0;
+       u32 len = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
+       int ret = 0;
+
+       /* lock-tight the recovery block */
+       if (this->lock_tight != NULL)
+               ret = this->lock_tight(mtd, ofs, len);
+
+       return ret;
+}
+
+void board_update_init(void)
+{
+       struct mtd_info *mtd = &onenand_mtd;
+       struct onenand_chip *this = mtd->priv;
+
+       /* Unlock whole block */
+       this->unlock_all(mtd);
+}
+
+int board_update_image(u32 *buf, u32 len)
+{
+       struct onenand_op *onenand_ops = onenand_get_interface();
+       struct mtd_info *mtd = &onenand_mtd;
+       struct onenand_chip *this = mtd->priv;
+       u32 ofs;
+       u32 ipl_addr = 0;
+       u32 ipl_edge = CONFIG_ONENAND_START_PAGE << this->page_shift;
+       u32 recovery_addr = ipl_edge;
+       u32 recovery_edge = CONFIG_RECOVERY_UBOOT_BLOCK << this->erase_shift;
+       u32 bootloader_addr = recovery_edge;
+       u32 bootloader_edge = CONFIG_RECOVERY_BOOT_BLOCKS << this->erase_shift;
+       int ret, retlen;
+
+       if (len > bootloader_addr) {
+               if (*(buf + bootloader_addr/sizeof(buf)) == 0xea000012) {
+                       /* case: IPL + Recovery + bootloader */
+                       PUTS("target: ipl + recovery + bootloader\n");
+                       ofs = ipl_addr;
+                       /* len = bootloader_edge; */
+               } else {
+                       /* case: unknown format */
+                       PUTS("target: unknown\n");
+                       return 1;
+               }
+       } else {
+               if (*(buf + recovery_addr/sizeof(buf)) == 0xea000012 &&
+                       *(buf + recovery_addr/sizeof(buf) - 1) == 0x00000000) {
+                       /* case: old image (IPL + bootloader) */
+                       PUTS("target: ipl + bootloader (old type)\n");
+                       ofs = ipl_addr;
+                       /* len = recovery_edge; */
+               } else {
+                       /* case: bootloader only */
+                       PUTS("target: bootloader\n");
+                       ofs = bootloader_addr;
+                       /* len = bootloader_edge - recovery_edge; */
+               }
+       }
+
+       /* Erase */
+       ret = onenand_ops->erase(ofs, len, 0);
+       if (ret)
+               return ret;
+
+       /* Write */
+       onenand_ops->write(ofs, len, (ssize_t *)&retlen, (u_char *)buf);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 void board_recovery_init(void)
 {
        /* set GPIO to enable UART2 */
index 80b336e..49e94d5 100644 (file)
@@ -20,11 +20,20 @@ typedef int (init_fnc_t)(void);
 static void normal_boot(void)
 {
        uchar *buf;
+       int ret;
 
        buf = (uchar *)CONFIG_SYS_BOOT_ADDR;
 
-       board_load_uboot(buf);
+       ret = board_load_bootloader(buf);
+       if (ret)
+               hang();
 
+#if 0
+       /* this will be applied */
+       ret = board_lock_recoveryblock();
+       if (ret)
+               PUTS("fail: lock-tight");
+#endif
        ((init_fnc_t *)CONFIG_SYS_BOOT_ADDR)();
 }
 
@@ -32,6 +41,8 @@ static void recovery_boot(void)
 {
        PUTS("Recovery Mode\n");
 
+       board_update_init();
+
        /* usb download and write image */
        do_usbd_down();
 
@@ -60,6 +71,12 @@ void start_recovery_boot(void)
        /* NOTREACHED - no way out of command loop except booting */
 }
 
+void hang(void)
+{
+       PUTS("### ERROR ### Please RESET the board ###\n");
+       for (;;);
+}
+
 /*
  * origin at lib_arm/eabi_compat.c to support EABI
  */
index c4ca3a9..53e1c5e 100644 (file)
 
 /* board/.../... */
 
-extern int board_check_condition(void);
-extern int board_load_uboot(unsigned char *buf);
-extern void board_recovery_init(void);
+int board_check_condition(void);
+int board_load_bootloader(unsigned char *buf);
+int board_lock_recoveryblock(void);
+void board_update_init(void);
+int board_update_image(u32 *buf, u32 len);
+void board_recovery_init(void);
 
 #endif
index c25bf28..c7b029b 100644 (file)
@@ -6,7 +6,7 @@
 #include <common.h>
 #include <serial.h>
 
-static struct serial_device *serial_current = NULL;
+static struct serial_device *serial_current = &s5pc1xx_serial2_device;
 
 struct serial_device *__default_serial_console(void)
 {
index 6e657cc..811b788 100644 (file)
@@ -9,7 +9,6 @@
 #include <common.h>
 #include "recovery.h"
 #include "usbd.h"
-#include "onenand.h"
 
 #ifdef RECOVERY_DEBUG
 #define        PUTS(s) serial_puts(DEBUG_MARK"usb: "s)
 static struct usbd_ops usbd_ops;
 static unsigned long down_ram_addr;
 
-int update_boot_image(void)
-{
-       struct onenand_op *onenand_ops = onenand_get_interface();
-       ulong len, offset;
-
-#if 1
-       /* case: IPL, Recovery, u-boot are one file */
-       offset = 0;
-       len = CONFIG_RECOVERY_SIZE + CONFIG_RECOVERY_ADDR;
-#else
-       /* case: IPL, Recover are one file and u-boot is another */
-       offset = CONFIG_RECOVERY_ADDR;
-       len = CONFIG_RECOVERY_SIZE;
-#endif
-       /* Erase */
-       onenand_ops->erase(offset, len, 0);
-       /* Write */
-       onenand_ops->write(offset, len, NULL, (u_char *)down_ram_addr);
-
-       return 0;
-}
-
 /* Parsing received data packet and Process data */
 static int process_data(struct usbd_ops *usbd)
 {
@@ -117,7 +94,7 @@ static int process_data(struct usbd_ops *usbd)
        /* Erase and Write to NAND */
        switch (img_type) {
        case IMG_BOOT:
-               update_boot_image();
+               ret = board_update_image((u32 *)down_ram_addr, len);
                break;
 
        default: