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'
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)
/* 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;
/* 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)) {
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);
#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 */
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 */
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)();
}
{
PUTS("Recovery Mode\n");
+ board_update_init();
+
/* usb download and write image */
do_usbd_down();
/* 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
*/
/* 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
#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)
{
#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)
{
/* 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: