recovery: restructure the recovery source tree, modify OneNAND driver
authorSangHee Kim <sh0130.kim@samsung.com>
Mon, 19 Apr 2010 09:02:19 +0000 (18:02 +0900)
committerSangHee Kim <sh0130.kim@samsung.com>
Mon, 19 Apr 2010 09:02:19 +0000 (18:02 +0900)
Makefile
cpu/arm_cortexa8/start.S
recovery/board/samsung/universal/Makefile
recovery/board/samsung/universal/recovery.lds
recovery/onenand.c
recovery/onenand.h
recovery/recovery.c
recovery/usbd.c
recovery/usbd.h

index 5695fae..423ddd5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -378,19 +378,19 @@ $(obj)u-boot.lds: $(LDSCRIPT)
                $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@
 
 $(NAND_SPL):   $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
-               $(MAKE) -C nand_spl/board/$(BOARDDIR) all
+               $(MAKE) -C nand_spl/board/$(BOARDDIR) all || exit 1
 
 $(U_BOOT_NAND):        $(NAND_SPL) $(obj)u-boot.bin
                cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin
 
 $(ONENAND_IPL):        $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
-               $(MAKE) -C onenand_ipl/board/$(BOARDDIR) all
+               $(MAKE) -C onenand_ipl/board/$(BOARDDIR) all || exit 1
 
 $(U_BOOT_ONENAND):     $(ONENAND_IPL) $(obj)u-boot.bin
                cat $(ONENAND_BIN) $(obj)u-boot.bin > $(obj)u-boot-onenand.bin
 
 $(RECOVERY_BLOCK):     $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk $(ONENAND_IPL)
-               $(MAKE) -C recovery/board/$(BOARDDIR) all
+               $(MAKE) -C recovery/ all || exit 1
 
 $(U_BOOT_RECOVERY):    $(RECOVERY_BLOCK) $(obj)u-boot.bin
                cat $(RECOVERY_BIN) $(obj)u-boot.bin > $(obj)u-boot-recovery.bin
index 3926bbd..e91c82e 100644 (file)
@@ -166,7 +166,7 @@ copy_loop:                          @ copy 32 bytes at a time
        /* Set up the stack */
 stack_setup:
        ldr     r0, _TEXT_BASE          @ upper 128 KiB: relocated uboot
-#if defined(CONFIG_ONENAND_IPL) || defined(CONFIG_RECOVERY_BLOCK)
+#if defined(CONFIG_ONENAND_IPL)
        sub     sp, r0, #128            @ leave 32 words for abort-stack
 #else
        sub     r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area
index 569c0ce..59b8f10 100644 (file)
 
 include $(TOPDIR)/config.mk
 
-# Recovery block' size should be 1 block (256K)
-# Recovery block includes the onenand_ipl(16K), so actual size is 240K
-TEXT_BASE      = 0x34000000
-# 256K - 16K(IPL Size)
-TEXT_BASE_256K         = 0x3403C000
+RECOVERYCFG = config.mk
+include $(RECOVERYCFG)
 
-LDSCRIPT= $(TOPDIR)/recovery/board/$(BOARDDIR)/recovery.lds
-LDFLAGS        = -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
-AFLAGS += -DCONFIG_RECOVERY_BLOCK -g -UTEXT_BASE -DTEXT_BASE=$(TEXT_BASE)
-CFLAGS += -DCONFIG_RECOVERY_BLOCK -g -D__HAVE_ARCH_MEMCPY32
-OBJCFLAGS += --gap-fill=0x00
+LIB    := $(obj)lib$(BOARD).a
 
-SOBJS  += start.o _memcpy32.o
-COBJS  += recovery.o onenand.o
-COBJS  += usbd.o usb_downloader.o usb-hs-otg.o
+SOBJS = start.o reset.o _memcpy32.o
+COBJS = string.o dlmalloc.o
+COBJS += usb_downloader.o usb-hs-otg.o
+COBJS += gpio.o
+COBJS += universal.o
 
-SRCS   := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c))
-OBJS   := $(addprefix $(obj),$(SOBJS) $(COBJS))
-__OBJS := $(SOBJS) $(COBJS)
-LNDIR  := $(OBJTREE)/recovery/board/$(BOARDDIR)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
 
-recoveryobj    := $(OBJTREE)/recovery/
+all:   $(LIB)
 
-ALL    = $(recoveryobj)recovery $(recoveryobj)recovery.bin $(recoveryobj)recovery-256k.bin
-
-all:   $(obj).depend $(ALL)
-
-$(recoveryobj)recovery-256k.bin:       $(recoveryobj)recovery
-       $(OBJCOPY) ${OBJCFLAGS} --pad-to=$(TEXT_BASE_256K) -O binary $< $@
-       cat $(OBJTREE)/onenand_ipl/onenand-ipl-16k-evt0.bin $@ > $(recoveryobj)recovery-evt0.bin
-       cat $(OBJTREE)/onenand_ipl/onenand-ipl-16k-fused.bin $@ > $(recoveryobj)recovery-fused.bin
-       cat $(OBJTREE)/onenand_ipl/onenand-ipl-16k.bin $@ > $(recoveryobj)recovery.bin
-
-$(recoveryobj)recovery.bin:    $(recoveryobj)recovery
-       $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
-
-$(recoveryobj)recovery:        $(OBJS)
-       cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
-               -Map $@.map -o $@
+$(LIB):        $(obj).depend $(SOBJS) $(OBJS) $(RECOVERYCFG)
+       $(AR) $(ARFLAGS) $@ $(SOBJS) $(OBJS)
 
 # create symbolic links from common files
 
-# from cpu directory
 $(obj)start.S:
        @rm -f $@
-       ln -s $(SRCTREE)/cpu/$(CPU)/start.S $@
+       ln -s $(SRCTREE)/cpu/$(CPU)/$@ $@
 
-# from SoC directory
+$(obj)reset.S:
+       @rm -f $@
+       ln -s $(SRCTREE)/cpu/$(CPU)/s5pc1xx/$@ $@
 
-# from lib_arm
 $(obj)_memcpy32.S:
-       ln -sf $(SRCTREE)/lib_arm/_memcpy32.S $@
-
-# from recovery directory
-$(obj)recovery.c:
-       @rm -f $@
-       ln -s $(SRCTREE)/recovery/recovery.c $@
+       ln -sf $(SRCTREE)/lib_arm/$@ $@
 
-$(obj)onenand.h:
+$(obj)string.c:
        @rm -f $@
-       ln -s $(SRCTREE)/recovery/onenand.h $@
+       ln -s $(SRCTREE)/lib_generic/$@ $@
 
-$(obj)onenand.c:       $(obj)onenand.h
+$(obj)dlmalloc.c:
        @rm -f $@
-       ln -s $(SRCTREE)/recovery/onenand.c $@
+       ln -s $(SRCTREE)/common/$@ $@
 
-$(obj)usbd.h:
-       @rm -f $@
-       ln -s $(SRCTREE)/recovery/usbd.h $@
+clean:
+       @rm -rf ../../../$(BOARDHEADER)
 
-$(obj)usbd.c:  $(obj)usbd.h
-       @rm -f $@
-       ln -s $(SRCTREE)/recovery/usbd.c $@
+#########################################################################
 
 $(obj)%.o:     $(obj)%.S
        $(CC) $(AFLAGS) -c -o $@ $<
@@ -93,11 +64,8 @@ $(obj)%.o:   $(obj)%.S
 $(obj)%.o:     $(obj)$.c
        $(CC) $(CFLAGS) -c -o $@ $<
 
-# defines $(obj).depend target
 include $(SRCTREE)/rules.mk
 
 sinclude $(obj).depend
 
-clean:
-       rm recovery.c onenand.c
-
+#########################################################################
index 559f9f2..1c98cf3 100644 (file)
@@ -33,7 +33,7 @@ SECTIONS
        . = ALIGN(4);
        .text      :
        {
-         start.o       (.text)
+         board/samsung/universal/start.o       (.text)
          *(.text)
        }
 
index 7409c68..55b31c5 100644 (file)
  */
 
 #include <common.h>
+#include <malloc.h>
+
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
 
 #include <asm/io.h>
-#include <asm/string.h>
 
 #include "onenand.h"
 
-#define onenand_block_address(block)           (block)
-#define onenand_sector_address(page)           (page << 2)
-#define onenand_buffer_address()               ((1 << 3) << 8)
-#define onenand_bufferram_address(block)       (0)
-
-#ifdef __HAVE_ARCH_MEMCPY32
-extern void *memcpy32(void *dest, void *src, int size);
+#ifdef printk
+#undef printk
+#endif
+#define printk(...)    do{} while(0)
+#define puts(...)      do{} while(0)
+#ifdef printf
+#undef printf
 #endif
+#define printf(...)    do{} while(0)
+
+struct mtd_info onenand_mtd;
+struct onenand_chip onenand_chip;
+struct onenand_op onenand_ops;
+
+static __attribute__((unused)) char dev_name[] = "onenand0";
+static struct mtd_info *mtd = &onenand_mtd;
 
-int (*onenand_read_page)(ulong block, ulong page, u_char *buf, int pagesize);
+static loff_t next_ofs;
+static loff_t skip_ofs;
 
-/* read a page with ECC */
-static int generic_onenand_read_page(ulong block, ulong page,
-                               u_char * buf, int pagesize)
+static inline int str2long(char *p, ulong *num)
 {
-       unsigned long *base;
+       char *endptr;
 
-#ifndef __HAVE_ARCH_MEMCPY32
-       unsigned int offset, value;
-       unsigned long *p;
+       *num = simple_strtoul(p, &endptr, 16);
+       return (*p != '\0' && *endptr == '\0') ? 1 : 0;
+}
+#if 0
+static int arg_off_size(int argc, char *argv[], ulong *off, ssize_t *size)
+{
+       if (argc >= 1) {
+               if (!(str2long(argv[0], off))) {
+                       printf("'%s' is not a number\n", argv[0]);
+                       return -1;
+               }
+       } else {
+               *off = 0;
+       }
+
+       if (argc >= 2) {
+               if (!(str2long(argv[1], (ulong *)size))) {
+                       printf("'%s' is not a number\n", argv[1]);
+                       return -1;
+               }
+       } else {
+               *size = mtd->size - *off;
+       }
+
+       if ((*off + *size) > mtd->size) {
+               printf("total chip size (0x%llx) exceeded!\n", mtd->size);
+               return -1;
+       }
+#if 0
+       if (*size == mtd->size)
+               puts("whole chip\n");
+       else
+               printf("offset 0x%lx, size 0x%x\n", *off, *size);
+#endif
+       return 0;
+}
 #endif
+static int onenand_block_read(loff_t from, ssize_t len,
+                             ssize_t *retlen, u_char *buf, int oob)
+{
+       struct onenand_chip *this = mtd->priv;
+       int blocksize = (1 << this->erase_shift);
+       loff_t ofs = from;
+       struct mtd_oob_ops ops = {
+               .retlen         = 0,
+       };
+       ssize_t thislen;
+       int ret;
 
-       onenand_writew(onenand_block_address(block),
-                       ONENAND_REG_START_ADDRESS1);
+       while (len > 0) {
+               thislen = min_t(ssize_t, len, blocksize);
+               thislen = ALIGN(thislen, mtd->writesize);
 
-       onenand_writew(onenand_bufferram_address(block),
-                       ONENAND_REG_START_ADDRESS2);
+               ret = mtd->block_isbad(mtd, ofs);
+               if (ret) {
+                       printk("Bad blocks %d at 0x%x\n",
+                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       ofs += blocksize;
+                       /* FIXME need to check how to handle the 'len' */
+                       len -= blocksize;
+                       continue;
+               }
 
-       onenand_writew(onenand_sector_address(page),
-                       ONENAND_REG_START_ADDRESS8);
+               if (oob) {
+                       ops.oobbuf = buf;
+                       ops.ooblen = thislen;
+               } else {
+                       ops.datbuf = buf;
+                       ops.len = thislen;
+               }
 
-       onenand_writew(onenand_buffer_address(),
-                       ONENAND_REG_START_BUFFER);
+               ops.retlen = 0;
+               ret = mtd->read_oob(mtd, ofs, &ops);
+               if (ret) {
+                       printk("Read failed 0x%x, %d\n", (u32)ofs, ret);
+                       ofs += thislen;
+                       continue;
+               }
+               ofs += thislen;
+               buf += thislen;
+               len -= thislen;
+               *retlen += ops.retlen;
+       }
 
-       onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT);
+       return 0;
+}
 
-       onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND);
+static int onenand_block_write(loff_t to, ssize_t len,
+                              ssize_t *retlen, u_char * buf)
+{
+       struct onenand_chip *this = mtd->priv;
+       int blocksize = (1 << this->erase_shift);
+       struct mtd_oob_ops ops = {
+               .retlen         = 0,
+               .oobbuf         = NULL,
+       };
+       loff_t ofs;
+       ssize_t thislen;
+       int ret;
 
-#ifndef __HAVE_ARCH_MEMCPY32
-       p = (unsigned long *) buf;
-#endif
-       base = (unsigned long *) (CONFIG_SYS_ONENAND_BASE + ONENAND_DATARAM);
+       if (to == next_ofs) {
+               next_ofs = to + len;
+               to += skip_ofs;
+       } else {
+               next_ofs = to + len;
+               skip_ofs = 0;
+       }
+       ofs = to;
 
-       while (!(READ_INTERRUPT() & ONENAND_INT_READ))
-               continue;
+       while (len > 0) {
+               thislen = min_t(ssize_t, len, blocksize);
+               thislen = ALIGN(thislen, mtd->writesize);
 
-       /* Check for invalid block mark */
-       if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff))
-               return 1;
+               ret = mtd->block_isbad(mtd, ofs);
+               if (ret) {
+                       printk("Bad blocks %d at 0x%x\n",
+                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       skip_ofs += blocksize;
+                       goto next;
+               }
 
-#ifdef __HAVE_ARCH_MEMCPY32
-       /* 32 bytes boundary memory copy */
-       memcpy32(buf, base, pagesize);
-#else
-       for (offset = 0; offset < (pagesize >> 2); offset++) {
-               value = *(base + offset);
-               *p++ = value;
+               ops.datbuf = (u_char *) buf;
+               ops.len = thislen;
+               ops.retlen = 0;
+               ret = mtd->write_oob(mtd, ofs, &ops);
+               if (ret) {
+                       printk("Write failed 0x%x, %d", (u32)ofs, ret);
+                       skip_ofs += thislen;
+                       goto next;
+               }
+
+               buf += thislen;
+               len -= thislen;
+               if (retlen != NULL)
+                       *retlen += ops.retlen;
+next:
+               ofs += blocksize;
        }
-#endif
 
        return 0;
 }
 
-#ifndef CONFIG_ONENAND_START_PAGE
-#define CONFIG_ONENAND_START_PAGE      1
-#endif
-#define ONENAND_PAGES_PER_BLOCK                64
-
-static int onenand_generic_init(int *page_is_4KiB, int *page)
+static int onenand_block_erase(u32 start, u32 size, int force)
 {
-       int dev_id, density;
-
-       if (onenand_readw(ONENAND_REG_TECHNOLOGY))
-               *page_is_4KiB = 1;
-       dev_id = onenand_readw(ONENAND_REG_DEVICE_ID);
-       density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
-       density &= ONENAND_DEVICE_DENSITY_MASK;
-       if (density >= ONENAND_DEVICE_DENSITY_4Gb &&
-           !(dev_id & ONENAND_DEVICE_IS_DDP))
-               *page_is_4KiB = 1;
-
-       return ONENAND_USE_DEFAULT;
-}
+       struct onenand_chip *this = mtd->priv;
+       struct erase_info instr = {
+               .callback       = NULL,
+       };
+       loff_t ofs;
+       int ret;
+       int blocksize = 1 << this->erase_shift;
 
-int onenand_board_init(int *page_is_4KiB, int *page)
-       __attribute__((weak, alias("onenand_generic_init")));
+       for (ofs = start; ofs < (start + size); ofs += blocksize) {
+               ret = mtd->block_isbad(mtd, ofs);
+               if (ret && !force) {
+                       printf("Skip erase bad block %d at 0x%x\n",
+                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       continue;
+               }
 
-/**
- * onenand_read_block - Read CONFIG_RECOVERY_BOOT_BLOCKS from block #1
- * @return 0 on success
- */
-int onenand_read_block(unsigned char *buf)
+               instr.addr = ofs;
+               instr.len = blocksize;
+               instr.priv = force;
+               instr.mtd = mtd;
+               ret = mtd->erase(mtd, &instr);
+               if (ret) {
+                       printf("erase failed block %d at 0x%x\n",
+                              (u32)(ofs >> this->erase_shift), (u32)ofs);
+                       continue;
+               }
+       }
+
+       return 0;
+}
+#if 0
+static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
 {
-       int block, nblocks;
-       int page = 0, offset = 0;
-       int pagesize, erase_shift;
-       int page_is_4KiB = 0, ret;
-
-       pagesize = 2048; /* OneNAND has 2KiB pagesize */
-       erase_shift = 17;
-       onenand_read_page = generic_onenand_read_page;
-
-       ret = onenand_board_init(&page_is_4KiB, &page);
-       if (ret == ONENAND_USE_GENERIC)
-               onenand_generic_init(&page_is_4KiB, &page);
-
-       if (page_is_4KiB) {
-               pagesize = 4096; /* OneNAND has 4KiB pagesize */
-               erase_shift = 18;
+       int i;
+       u_char *datbuf, *oobbuf, *p;
+       struct mtd_oob_ops ops;
+       loff_t addr;
+
+       datbuf = malloc(mtd->writesize + mtd->oobsize);
+       oobbuf = malloc(mtd->oobsize);
+       if (!datbuf || !oobbuf) {
+               puts("No memory for page buffer\n");
+               return 1;
+       }
+       off &= ~(mtd->writesize - 1);
+       addr = (loff_t) off;
+       memset(&ops, 0, sizeof(ops));
+       ops.datbuf = datbuf;
+       ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
+       ops.len = mtd->writesize;
+       ops.ooblen = mtd->oobsize;
+       ops.retlen = 0;
+       i = mtd->read_oob(mtd, addr, &ops);
+       if (i < 0) {
+               printf("Error (%d) reading page %08lx\n", i, off);
+               free(datbuf);
+               free(oobbuf);
+               return 1;
        }
+       printf("Page %08lx dump:\n", off);
+       i = mtd->writesize >> 4;
+       p = datbuf;
 
-       nblocks = CONFIG_RECOVERY_BOOT_BLOCKS;
-
-       /* NOTE: you must read page from page 1 of block 0 */
-       /* read the block page by page */
-       for (block = 1; block < nblocks; block++) {
-               for (; page < ONENAND_PAGES_PER_BLOCK; page++) {
-                       if (onenand_read_page(block, page, buf + offset,
-                                               pagesize)) {
-                               /* This block is bad. Skip it
-                                * and read next block */
-                               offset -= page * pagesize;
-                               nblocks++;
-                               break;
-                       }
-                       offset += pagesize;
-               }
-               page = 0;
+       while (i--) {
+               if (!only_oob)
+                       printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
+                              "  %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                              p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+                              p[8], p[9], p[10], p[11], p[12], p[13], p[14],
+                              p[15]);
+               p += 16;
+       }
+       puts("OOB:\n");
+       p = oobbuf;
+       i = mtd->oobsize >> 3;
+       while (i--) {
+               printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
+                      p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+               p += 8;
        }
+       free(datbuf);
+       free(oobbuf);
 
        return 0;
 }
+#endif
+void onenand_set_interface(struct onenand_op *onenand)
+{
+       onenand->read = onenand_block_read;
+       onenand->write = onenand_block_write;
+       onenand->erase = onenand_block_erase;
+       
+       onenand->mtd = &onenand_mtd;
+       onenand->this = &onenand_chip;
+}
+
+struct onenand_op *onenand_get_interface(void)
+{
+       return &onenand_ops;
+}
+
+void onenand_init(void)
+{
+       memset(&onenand_mtd, 0, sizeof(struct mtd_info));
+       memset(&onenand_chip, 0, sizeof(struct onenand_chip));
+       memset(&onenand_ops, 0, sizeof(struct onenand_op));
+
+       onenand_mtd.priv = &onenand_chip;
+
+       onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE;
+       /*onenand_chip.options |= ONENAND_RUNTIME_BADBLOCK_CHECK;*/
+
+       onenand_scan(&onenand_mtd, 1);
+
+#if 0
+       if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND)
+               puts("Flex-");
+       puts("OneNAND: ");
+       print_size(onenand_chip.chipsize, "\n");
+#endif
+
+#if 0
+       /*
+        * Add MTD device so that we can reference it later
+        * via the mtdcore infrastructure (e.g. ubi).
+        */
+       onenand_mtd.name = dev_name;
+       add_mtd_device(&onenand_mtd);
+#else
+       onenand_set_interface(&onenand_ops);
+#endif
+}
+
index 70dcb53..e629cce 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  */
+#ifndef _ONENAND_H
+#define _ONENAND_H
 
-#ifndef _ONENAND_IPL_H
-#define _ONENAND_IPL_H
+struct onenand_op {
+       int (*read)(loff_t, ssize_t, ssize_t *, u_char *, int);
+       int (*write)(loff_t, ssize_t, ssize_t *, u_char *);
+       int (*erase)(u32, u32, int);
 
-#include <linux/mtd/onenand_regs.h>
-
-#define onenand_readw(a)        readw(THIS_ONENAND(a))
-#define onenand_writew(v, a)    writew(v, THIS_ONENAND(a))
-
-#define THIS_ONENAND(a)         (CONFIG_SYS_ONENAND_BASE + (a))
-
-#define READ_INTERRUPT()       onenand_readw(ONENAND_REG_INTERRUPT)
-
-enum {
-       ONENAND_USE_DEFAULT,
-       ONENAND_USE_GENERIC,
-       ONENAND_USE_BOARD,
+       struct mtd_info *mtd;
+       struct onenand_chip *this;
 };
 
-extern int (*onenand_read_page)(ulong block, ulong page,
-                               u_char *buf, int pagesize);
-extern int onenand_read_block(unsigned char *buf);
+struct onenand_op *onenand_get_interface(void);
+void onenand_init(void);
+
 #endif
index b509805..7c56132 100644 (file)
  */
 
 #include <common.h>
+#include <malloc.h>
+#include "common.h"
+#include "usbd.h"
 #include "onenand.h"
 
 typedef int (init_fnc_t)(void);
 
-void start_recovery_boot(void)
+void normal_boot(void)
 {
        uchar *buf;
 
        buf = (uchar *)CONFIG_SYS_BOOT_ADDR;
 
-       onenand_read_block(buf);
+       board_load_uboot(buf);
 
        ((init_fnc_t *)CONFIG_SYS_BOOT_ADDR)();
+}
+
+void recovery_boot(void)
+{
+       /* usb download and write image */
+       do_usbd_down();
+       
+       /* reboot */
+       reset_cpu(0);
+}
+
+void start_recovery_boot(void)
+{
+       /* armboot_start is defined in the board-specific linker script */
+       mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
+                       CONFIG_SYS_MALLOC_LEN);
+
+       onenand_init();
+
+       board_recovery_init();
+       
+       if (board_check_condition()) {
+               recovery_boot();
+       } else {
+               normal_boot();
+       }
+       /* NOTREACHED - no way out of command loop except booting */
+}
 
-       /* should never come here */
+/*
+ * origin at lib_arm/eabi_compat.c to support EABI
+ */
+int raise (int signum)
+{
+       return 0;
 }
index a850718..c26ffc2 100644 (file)
@@ -7,7 +7,8 @@
  */
 
 #include <common.h>
-#include <usbd.h>
+#include "usbd.h"
+#include "onenand.h"
 
 #define OPS_READ       0
 #define OPS_WRITE      1
 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)
 {
@@ -83,11 +106,7 @@ static int process_data(struct usbd_ops *usbd)
        /* Erase and Write to NAND */
        switch (img_type) {
        case IMG_BOOT:
-               /* TO DO */
-               /* Erase */
-               /* Write */
-               /* offset: CONFIG_RECOVERY_ADDR */
-               /* size: CONFIG_RECOVERY_SIZE */
+               update_boot_image();
                break;
 
        default:
index 2728ee5..66bfdaf 100644 (file)
@@ -119,6 +119,7 @@ struct usbd_ops {
        void (*cpu_reset)(void);
 };
 
+int do_usbd_down(void);
 /* This function is interfaced between USB Device Controller and USB Downloader
  * Must Implementation this function at USB Controller!! */
 struct usbd_ops *usbd_set_interface(struct usbd_ops *);