It works. It is awesome to be able to do this.
If you are interested, and this isn't pretty
This a patch against 2010-06 uboot.
(been busy, but this was too good to ignore)

I will try to find some time to make it better
But for now comments are appreciated.
The Makefile and environment variable hack is ugly.

I Was going to add error checking and 2 copies of u-boot
(if a page fails, get it from the second copy)
This has an additional hack to fake the subpages.

diff -purN orig/drivers/mtd/nand/fsl_elbc_nand.c
u-boot-2010.06/drivers/mtd/nand/fsl_elbc_nand.c
--- orig/drivers/mtd/nand/fsl_elbc_nand.c       2011-06-30
14:11:27.304294055 -0500
+++ u-boot-2010.06/drivers/mtd/nand/fsl_elbc_nand.c     2011-06-30
14:10:46.880516050 -0500
@@ -86,6 +86,10 @@ struct fsl_elbc_ctrl {
        unsigned int use_mdr;    /* Non zero if the MDR is to be set
*/
        unsigned int oob;        /* Non zero if operating on OOB data
*/
        uint8_t *oob_poi;        /* Place to write ECC after read back
*/
+
+       int subpage_shift;       /* If writesize > 2048, these two
members*/
+       int subpage_mask;        /* are used to calculate the real page
*/
+                            /* address and real column address       */
 };
 
 /* These map to the positions used by the FCM hardware ECC generator */
@@ -173,10 +177,20 @@ static void set_addr(struct mtd_info *mt
        struct fsl_elbc_ctrl *ctrl = priv->ctrl;
        fsl_lbus_t *lbc = ctrl->regs;
        int buf_num;
+       u32 real_ca = column;
+
+       if (priv->page_size && ctrl->subpage_shift) {
+               real_ca = (page_addr & ctrl->subpage_mask) * 2112;
+               page_addr >>= ctrl->subpage_shift;
+       }
 
        ctrl->page = page_addr;
 
        if (priv->page_size) {
+               real_ca += (oob ? 2048 : 0);
+               ctrl->use_mdr = 1;
+               ctrl->mdr = real_ca;
+
                out_be32(&lbc->fbar, page_addr >> 6);
                out_be32(&lbc->fpar,
                         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI)
|
@@ -265,11 +279,12 @@ static void fsl_elbc_do_read(struct nand
 
        if (priv->page_size) {
                out_be32(&lbc->fir,
-                        (FIR_OP_CW0 << FIR_OP0_SHIFT) |
-                        (FIR_OP_CA  << FIR_OP1_SHIFT) |
-                        (FIR_OP_PA  << FIR_OP2_SHIFT) |
-                        (FIR_OP_CW1 << FIR_OP3_SHIFT) |
-                        (FIR_OP_RBW << FIR_OP4_SHIFT));
+                       (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                       (FIR_OP_UA  << FIR_OP1_SHIFT) |
+                       (FIR_OP_UA  << FIR_OP2_SHIFT) |
+                       (FIR_OP_PA  << FIR_OP3_SHIFT) |
+                       (FIR_OP_CW1 << FIR_OP4_SHIFT) |
+                       (FIR_OP_RBW << FIR_OP5_SHIFT));
 
                out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
                                    (NAND_CMD_READSTART <<
FCR_CMD1_SHIFT));
@@ -399,10 +414,11 @@ static void fsl_elbc_cmdfunc(struct mtd_
 
                        out_be32(&lbc->fir,
                                 (FIR_OP_CW0 << FIR_OP0_SHIFT) |
-                                (FIR_OP_CA  << FIR_OP1_SHIFT) |
-                                (FIR_OP_PA  << FIR_OP2_SHIFT) |
-                                (FIR_OP_WB  << FIR_OP3_SHIFT) |
-                                (FIR_OP_CW1 << FIR_OP4_SHIFT));
+                                (FIR_OP_UA  << FIR_OP1_SHIFT) |
+                                (FIR_OP_UA  << FIR_OP2_SHIFT) |
+                                (FIR_OP_PA  << FIR_OP3_SHIFT) |
+                                (FIR_OP_WB  << FIR_OP4_SHIFT) |
+                                (FIR_OP_CW1 << FIR_OP5_SHIFT));
                } else {
                        fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) |
                              (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
@@ -453,6 +469,10 @@ static void fsl_elbc_cmdfunc(struct mtd_
                        full_page = 1;
                }
 
+               if (priv->page_size)
+                       ctrl->use_mdr = 1;
+
+
                fsl_elbc_run_command(mtd);
 
                ctrl->oob_poi = NULL;
@@ -808,3 +828,29 @@ int board_nand_init(struct nand_chip *na
 
        return 0;
 }
+
+int board_nand_init_tail(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct fsl_elbc_mtd *priv = chip->priv;
+       struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+
+       /* Hack for supporting the flash chip whose writesize is
+        * larger than 2K bytes.
+        */
+       if (mtd->writesize > 2048) {
+               ctrl->subpage_shift = ffs(mtd->writesize >> 11) - 1;
+               ctrl->subpage_mask =
+                       (1 << ctrl->subpage_shift) - 1;
+               /* Rewrite mtd->writesize, mtd->oobsize,
chip->page_shift
+                * and chip->pagemask.
+                */
+               mtd->writesize = 2048;
+               mtd->oobsize = 64;
+               chip->page_shift = ffs(mtd->writesize) - 1;
+               chip->pagemask = (chip->chipsize >> chip->page_shift) -
1;
+               mtd->subpage_sft--;
+       }
+}
+
+
diff -purN orig/drivers/mtd/nand/nand_base.c
u-boot-2010.06/drivers/mtd/nand/nand_base.c
--- orig/drivers/mtd/nand/nand_base.c   2011-06-30 14:11:27.408242045
-0500
+++ u-boot-2010.06/drivers/mtd/nand/nand_base.c 2011-06-30
14:10:46.920496045 -0500
@@ -2998,6 +2998,7 @@ int nand_scan_tail(struct mtd_info *mtd)
                }
        }
        chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
+printf("sps=%d\n", chip->subpagesize);
 
        /* Initialize state */
        chip->state = FL_READY;
diff -purN orig/drivers/mtd/nand/nand.c
u-boot-2010.06/drivers/mtd/nand/nand.c
--- orig/drivers/mtd/nand/nand.c        2011-06-30 14:11:27.452220050
-0500
+++ u-boot-2010.06/drivers/mtd/nand/nand.c      2011-06-30
14:10:46.948482047 -0500
@@ -74,6 +74,9 @@ static void nand_init_chip(struct mtd_in
                mtd->name = NULL;
                mtd->size = 0;
        }
+#ifdef CONFIG_SYS_NAND_INIT_TAIL
+       board_nand_init_tail(mtd);
+#endif
 
 }
 
diff -purN orig/include/nand.h u-boot-2010.06/include/nand.h
--- orig/include/nand.h 2010-06-29 16:28:28.000000000 -0500
+++ u-boot-2010.06/include/nand.h       2011-06-30 14:10:46.888512049
-0500
@@ -31,7 +31,9 @@ extern void nand_init(void);
 #include <linux/mtd/nand.h>
 
 extern int board_nand_init(struct nand_chip *nand);
-
+#ifdef CONFIG_SYS_NAND_INIT_TAIL
+extern int board_nand_init_tail(struct mtd_info *mtd);
+#endif
 typedef struct mtd_info nand_info_t;
 
 extern int nand_curr_device;
diff -purN orig/Makefile u-boot-2010.06/Makefile
--- orig/Makefile       2010-06-29 16:28:28.000000000 -0500
+++ u-boot-2010.06/Makefile     2011-06-30 14:10:46.892510049 -0500
@@ -371,7 +371,7 @@ $(NAND_SPL):        $(TIMESTAMP_FILE) $(VERSION
                $(MAKE) -C nand_spl/board/$(BOARDDIR) all
 
 $(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
+               cat $(obj)nand_spl/u-boot-spl-pad.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
diff -purN orig/nand_spl/board/freescale/mpc8313erdb/Makefile
u-boot-2010.06/nand_spl/board/freescale/mpc8313erdb/Makefile
--- orig/nand_spl/board/freescale/mpc8313erdb/Makefile  2011-06-30
14:11:27.196348060 -0500
+++ u-boot-2010.06/nand_spl/board/freescale/mpc8313erdb/Makefile
2011-06-30 14:10:46.900506048 -0500
@@ -24,7 +24,17 @@
 
 NAND_SPL := y
 TEXT_BASE := 0xfff00000
-PAD_TO := 0xfff04000
+
+NAND_BLOCK_SIZE ?= 128K
+NAND_PAGE_SIZE ?= 2K
+
+ifeq ($(NAND_BLOCK_SIZE),256K)
+PAD_TO := 0xfff40000
+endif
+ifeq ($(NAND_BLOCK_SIZE),128K)
+PAD_TO := 0xfff20000
+endif
+PAD_TO ?= 0xfff04000
 
 include $(TOPDIR)/config.mk
 
@@ -44,12 +54,21 @@ LNDIR       := $(OBJTREE)/nand_spl/board/$(BOA
 
 nandobj        := $(OBJTREE)/nand_spl/
 
-ALL    = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin
$(nandobj)u-boot-spl-16k.bin
+ALL    = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin
$(nandobj)u-boot-spl-pad.bin
 
 all:   $(obj).depend $(ALL)
 
-$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl
+$(nandobj)u-boot-spl-pad.bin: $(nandobj)u-boot-spl
        $(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@
+ifeq ($(NAND_PAGE_SIZE),4K)
+       dd if=$@ bs=2048 count=1 > p0
+       dd if=$@ bs=2048 count=1 skip=1 > p1
+       dd if=$@ bs=2048 count=1 skip=2 > p2
+       dd if=$@ bs=2048 count=1 skip=3 > p3
+       dd if=$@ bs=2048 skip=4 > p4
+       cat p0 p2 p1 p3 p4 > $@
+       rm -f p0 p1 p2 p3 p4
+endif
 
 $(nandobj)u-boot-spl.bin:      $(nandobj)u-boot-spl
        $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
diff -purN orig/nand_spl/nand_boot_fsl_elbc.c
u-boot-2010.06/nand_spl/nand_boot_fsl_elbc.c
--- orig/nand_spl/nand_boot_fsl_elbc.c  2010-06-29 16:28:28.000000000
-0500
+++ u-boot-2010.06/nand_spl/nand_boot_fsl_elbc.c        2011-06-30
14:10:56.715596060 -0500
@@ -47,6 +47,59 @@ static void nand_wait(void)
        }
 }
 
+#if CONFIG_SYS_NAND_PAGE_SIZE > 2048
+#define PAGE_MULT (CONFIG_SYS_NAND_PAGE_SIZE/2048)
+#define BLOCK_PAGES
(CONFIG_SYS_NAND_BLOCK_SIZE/CONFIG_SYS_NAND_PAGE_SIZE)
+static void nand_load(unsigned int offs, int uboot_size, uchar *dst)
+{
+       fsl_lbus_t *regs = (fsl_lbus_t *)(CONFIG_SYS_IMMR + 0x5000);
+       uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE;
+       int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2;
+       int page_addr2k = offs/2048;
+       int j, page_in_block, col, buf_ofs;
+       int pos = 0;
+
+       fmr |= FMR_ECCM;
+       out_be32(&regs->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+                            (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+       out_be32(&regs->fir,
+                (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+                (FIR_OP_UA  << FIR_OP1_SHIFT) |
+                (FIR_OP_UA  << FIR_OP2_SHIFT) |
+                (FIR_OP_PA  << FIR_OP3_SHIFT) |
+                (FIR_OP_CW1 << FIR_OP4_SHIFT) |
+                (FIR_OP_RBW << FIR_OP5_SHIFT));
+
+       out_be32(&regs->fbcr, 0);
+       clrsetbits_be32(&regs->bank[0].br, BR_DECC, BR_DECC_CHK_GEN);
+
+       while (pos < uboot_size) {
+               page_in_block = page_addr2k/PAGE_MULT & (BLOCK_PAGES-1);
+               col = (page_addr2k & (PAGE_MULT-1))*2112;
+
+               if(page_in_block == 0 && col == 0)
+                       out_be32(&regs->fbar,
+
page_addr2k/(CONFIG_SYS_NAND_BLOCK_SIZE/2048)
+                       );
+
+               out_be32(&regs->ltesr, ~0);
+               out_be32(&regs->lteatr, 0);
+               out_be32(&regs->fpar, page_in_block << 12);
+               out_be32(&regs->fmr, fmr);
+               out_be32(&regs->mdr, col);
+               out_be32(&regs->lsor, 0);
+               nand_wait();
+
+               buf_ofs = (page_in_block & 1) * 4096;
+
+               for (j = 0; j < 2048; j++)
+                       dst[pos + j] = buf[buf_ofs + j];
+
+               page_addr2k++;
+               pos += 2048;
+       }
+}
+#else
 static void nand_load(unsigned int offs, int uboot_size, uchar *dst)
 {
        fsl_lbus_t *regs = (fsl_lbus_t *)(CONFIG_SYS_IMMR + 0x5000);
@@ -122,6 +175,7 @@ static void nand_load(unsigned int offs,
                } while ((offs & (block_size - 1)) && (pos <
uboot_size));
        }
 }
+#endif
 
 /*
  * The main entry for NAND booting. It's necessary that SDRAM is
already


-----Original Message-----
From: Scott Wood [mailto:[email protected]] 
Sent: Tuesday, July 05, 2011 6:13 PM
To: Matthew L. Creech
Cc: Mike Hench; [email protected]; [email protected]
Subject: Re: [PATCH 2/2] mtd/nand : workaround for Freescale FCM to
supportlarge-page Nand chip

On Tue, 5 Jul 2011 19:08:21 -0400
"Matthew L. Creech" <[email protected]> wrote:

> On Tue, Jun 28, 2011 at 12:30 PM, Scott Wood <[email protected]>
wrote:
> > On Tue, 28 Jun 2011 11:35:12 -0400
> > Mike Hench <[email protected]> wrote:
> >
> >>
> >> Any boot ideas ?
> >> Will the FCM load 2k and run it?
> >
> > The 4K boot region will have to be split over pages 0 and 2 (2k
view) or
> > the first half of pages 0 and 1 (4k view).
> >
> 
> (Redirecting to the U-Boot list)
> 
> Hi Scott,
> 
> Does this kind of page-splitting only apply to the IPL and nothing
> else?

Yes, because that's loaded directly by the hardware which doesn't
implement this workaround.

> If so, it seems that if:
> 
> 1. modifications are made to U-Boot's fsl_elbc_nand driver similar to
> Liu Shuo's kernel mods, and
> 2. an option is added to generate u-boot-nand.bin with its IPL split
> into two 2k chunks
> 
> then we can boot and run entirely from a 4k page device on MPC 83xx,
correct?

That's the plan, though I don't know whether it's been tried yet.

-Scott

_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to