From: Sanghee Kim Date: Fri, 30 Apr 2010 05:20:34 +0000 (+0900) Subject: recovery: update is modified to support various image X-Git-Tag: JD16_20100430~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=38bd08332b0d0c6ba04dab0c9c46d5355c59b18c;p=kernel%2Fu-boot.git recovery: update is modified to support various image 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' --- diff --git a/common/cmd_usbd.c b/common/cmd_usbd.c index 6f7dc7b..2a1c15a 100644 --- a/common/cmd_usbd.c +++ b/common/cmd_usbd.c @@ -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); diff --git a/include/configs/s5pc1xx_universal.h b/include/configs/s5pc1xx_universal.h index 7db3b45..c4ffa75 100644 --- a/include/configs/s5pc1xx_universal.h +++ b/include/configs/s5pc1xx_universal.h @@ -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 /* get chip and board defs */ diff --git a/recovery/board/samsung/universal/universal.c b/recovery/board/samsung/universal/universal.c index 6041202..02a4388 100644 --- a/recovery/board/samsung/universal/universal.c +++ b/recovery/board/samsung/universal/universal.c @@ -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 */ diff --git a/recovery/recovery.c b/recovery/recovery.c index 80b336e..49e94d5 100644 --- a/recovery/recovery.c +++ b/recovery/recovery.c @@ -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 */ diff --git a/recovery/recovery.h b/recovery/recovery.h index c4ca3a9..53e1c5e 100644 --- a/recovery/recovery.h +++ b/recovery/recovery.h @@ -12,8 +12,11 @@ /* 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 diff --git a/recovery/serial.c b/recovery/serial.c index c25bf28..c7b029b 100644 --- a/recovery/serial.c +++ b/recovery/serial.c @@ -6,7 +6,7 @@ #include #include -static struct serial_device *serial_current = NULL; +static struct serial_device *serial_current = &s5pc1xx_serial2_device; struct serial_device *__default_serial_console(void) { diff --git a/recovery/usbd.c b/recovery/usbd.c index 6e657cc..811b788 100644 --- a/recovery/usbd.c +++ b/recovery/usbd.c @@ -9,7 +9,6 @@ #include #include "recovery.h" #include "usbd.h" -#include "onenand.h" #ifdef RECOVERY_DEBUG #define PUTS(s) serial_puts(DEBUG_MARK"usb: "s) @@ -20,28 +19,6 @@ 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: