[U-Boot] [PATCH 2/2] mtd/nand : workaround for Freescale FCM to supportlarge-page Nand chip
Mike Hench
mhench at elutions.com
Wed Jul 6 02:04:02 CEST 2011
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(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+ out_be32(®s->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(®s->fbcr, 0);
+ clrsetbits_be32(®s->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(®s->fbar,
+
page_addr2k/(CONFIG_SYS_NAND_BLOCK_SIZE/2048)
+ );
+
+ out_be32(®s->ltesr, ~0);
+ out_be32(®s->lteatr, 0);
+ out_be32(®s->fpar, page_in_block << 12);
+ out_be32(®s->fmr, fmr);
+ out_be32(®s->mdr, col);
+ out_be32(®s->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:scottwood at freescale.com]
Sent: Tuesday, July 05, 2011 6:13 PM
To: Matthew L. Creech
Cc: Mike Hench; b35362 at freescale.com; u-boot at lists.denx.de
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" <mlcreech at gmail.com> wrote:
> On Tue, Jun 28, 2011 at 12:30 PM, Scott Wood <scottwood at freescale.com>
wrote:
> > On Tue, 28 Jun 2011 11:35:12 -0400
> > Mike Hench <mhench at elutions.com> 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
More information about the U-Boot
mailing list