Message ID | 1311842291-24837-4-git-send-email-simonschwarzcor@gmail.com |
---|---|
State | Superseded |
Headers | show |
On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote: > Insert some NAND driver sources into NAND SPL library. > > Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com> [snip ..] > + > +int nand_curr_device = -1; Is nand_curr_device used anywhere? > +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; > +static nand_info_t info; > +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; Is nand_info used anywhere? > +static struct nand_chip nand_chip; Is nand_chip used anywhere? I see that this definition is shadowed in function nand_init(). > + > +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512) [snip ..] > +/* > + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer > + * @mtd: MTD device structure > + * @buf: buffer to store date typo: date instead of data. > + * @len: number of bytes to read > + * > + * Default read function for 16bit buswith > + * > + * This function is based on nand_read_buf16 from nand_base.c. This version > + * reads 32bit not 16bit although the bus only has 16bit. > + */ > +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) > +{ > + int i; > + struct nand_chip *chip = mtd->priv; > + u32 *p = (u32 *) buf; Why this variable p? > + len>>= 2; > + > + for (i = 0; i< len; i++) > + p[i] = readl(chip->IO_ADDR_R); > +} Should this function be called omap_spl_read_buf32() ? Or still better, should this be added as nand_read_buf32() in nand_base.c itself? > + > +/* > + * omap_spl_read_buf - [DEFAULT] read chip data into buffer > + * @mtd: MTD device structure > + * @buf: buffer to store date > + * @len: number of bytes to read > + * > + * Default read function for 8bit buswith > + * > + * This is the same function as this from nand_base.c nand_read_buf > + */ > +static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) > +{ > + int i; > + struct nand_chip *chip = mtd->priv; > + > + for (i = 0; i< len; i++) > + buf[i] = readb(chip->IO_ADDR_R); > +} > +#endif What is the difference between this function and nand_read_buf() in nand_base.c ? best regards, Aneesh
Hi Aneesh, On 07/28/2011 01:54 PM, Aneesh V wrote: > On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote: >> Insert some NAND driver sources into NAND SPL library. >> >> Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com> > > [snip ..] > >> + >> +int nand_curr_device = -1; > > Is nand_curr_device used anywhere? Was used in nand.c - this isn't included anymore -> deleted > >> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; >> +static nand_info_t info; >> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; > > Is nand_info used anywhere? Same as above -> deleted. > >> +static struct nand_chip nand_chip; > > Is nand_chip used anywhere? I see that this definition is shadowed in > function nand_init(). Deleted the double definition. nand_chip is used in: - nand_command - nand_is_bad_block - nand_read_page - nand_init - nand_deselect > >> + >> +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512) > > [snip ..] > >> +/* >> + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer >> + * @mtd: MTD device structure >> + * @buf: buffer to store date > > typo: date instead of data. > see below for solution (btw. this typo comes from nand_base.c) >> + * @len: number of bytes to read >> + * >> + * Default read function for 16bit buswith >> + * >> + * This function is based on nand_read_buf16 from nand_base.c. This >> version >> + * reads 32bit not 16bit although the bus only has 16bit. >> + */ >> +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, >> int len) >> +{ >> + int i; >> + struct nand_chip *chip = mtd->priv; >> + u32 *p = (u32 *) buf; > > Why this variable p? It is used to cast the 8-bit buffer variable into a 32bit one. Actually the same is done for the 16bit implementation. (There it is the adaption to the bus width - why 32bit here see below) > >> + len>>= 2; >> + >> + for (i = 0; i< len; i++) >> + p[i] = readl(chip->IO_ADDR_R); >> +} > > Should this function be called omap_spl_read_buf32() ? > Or still better, should this be added as nand_read_buf32() in > nand_base.c itself? Oh. There I played around with the Access Size Adaptation of the GPMC - It is still a x16 interface - this is what the 16 refers to IMHO. But for sake of simplicity I will change this back to 16bit access - I don't think that there is a big performance impact although I didn't measure it. I cloned them because the functions in nand_base.c are static. My solution: deleted the cloned functions - use these from nand_base by removing the static modifier and add them to nand.h This leaves nand_base.c inconsistent - some functions are static, some not - maybe we should un-static all read/write functions as they are normally used in SPL? >> + >> +/* >> + * omap_spl_read_buf - [DEFAULT] read chip data into buffer >> + * @mtd: MTD device structure >> + * @buf: buffer to store date >> + * @len: number of bytes to read >> + * >> + * Default read function for 8bit buswith >> + * >> + * This is the same function as this from nand_base.c nand_read_buf >> + */ >> +static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int >> len) >> +{ >> + int i; >> + struct nand_chip *chip = mtd->priv; >> + >> + for (i = 0; i< len; i++) >> + buf[i] = readb(chip->IO_ADDR_R); >> +} >> +#endif > > What is the difference between this function and nand_read_buf() in > nand_base.c ? none - static is the problem. Did the same as with the x16 version above. > > best regards, > Aneesh Regards & thx for the review! Simon
On Thursday 28 July 2011 07:34 PM, Simon Schwarz wrote: > Hi Aneesh, > > On 07/28/2011 01:54 PM, Aneesh V wrote: >> On Thursday 28 July 2011 02:08 PM, Simon Schwarz wrote: >>> Insert some NAND driver sources into NAND SPL library. >>> >>> Signed-off-by: Simon Schwarz<simonschwarzcor@gmail.com> >> >> [snip ..] >> >>> + >>> +int nand_curr_device = -1; >> >> Is nand_curr_device used anywhere? > > Was used in nand.c - this isn't included anymore -> deleted > >> >>> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; >>> +static nand_info_t info; >>> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; >> >> Is nand_info used anywhere? > > Same as above -> deleted. > >> >>> +static struct nand_chip nand_chip; >> >> Is nand_chip used anywhere? I see that this definition is shadowed in >> function nand_init(). > > Deleted the double definition. > > nand_chip is used in: > - nand_command > - nand_is_bad_block > - nand_read_page > - nand_init > - nand_deselect > >> >>> + >>> +#if (CONFIG_SYS_NAND_PAGE_SIZE<= 512) >> >> [snip ..] >> >>> +/* >>> + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer >>> + * @mtd: MTD device structure >>> + * @buf: buffer to store date >> >> typo: date instead of data. >> > > see below for solution (btw. this typo comes from nand_base.c) > >>> + * @len: number of bytes to read >>> + * >>> + * Default read function for 16bit buswith >>> + * >>> + * This function is based on nand_read_buf16 from nand_base.c. This >>> version >>> + * reads 32bit not 16bit although the bus only has 16bit. >>> + */ >>> +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, >>> int len) >>> +{ >>> + int i; >>> + struct nand_chip *chip = mtd->priv; >>> + u32 *p = (u32 *) buf; >> >> Why this variable p? > It is used to cast the 8-bit buffer variable into a 32bit one. Actually > the same is done for the 16bit implementation. (There it is the adaption > to the bus width - why 32bit here see below) >> >>> + len>>= 2; >>> + >>> + for (i = 0; i< len; i++) >>> + p[i] = readl(chip->IO_ADDR_R); >>> +} >> >> Should this function be called omap_spl_read_buf32() ? >> Or still better, should this be added as nand_read_buf32() in >> nand_base.c itself? > > Oh. There I played around with the Access Size Adaptation of the GPMC - > It is still a x16 interface - this is what the 16 refers to IMHO. But Ok. I have to admit that I am not a NAND expert and I do not understand this code well. > for sake of simplicity I will change this back to 16bit access - I don't > think that there is a big performance impact although I didn't measure it. No. If it's an OMAP specific optimization, I don't see a reason to remove it. Looks like that may actually improve performance. However, you may have to take into account of the alignment of buffer, the size requested etc. Please have a look at the implementation in drivers/mtd /nand/davinci_nand.c(although the implementation here seems to be for 8-bit devices, something similar may be possible for 16-bit) > > I cloned them because the functions in nand_base.c are static. > > My solution: deleted the cloned functions - use these from nand_base by > removing the static modifier and add them to nand.h I hope there won't be any name-space conflict due to this. best regards, Aneesh
On Thu, 28 Jul 2011 10:38:09 +0200 Simon Schwarz <simonschwarzcor@googlemail.com> wrote: > +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) Not sure what this has to do with NAND. > +int nand_curr_device = -1; > +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; > +static nand_info_t info; > +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; > +static struct nand_chip nand_chip; It doesn't look like nand_info or nand_curr_device are used. > +/* nand_boot()-function from the old nand_spl ripped apart into > + * - nand_init() > + * - nand_spl_load_image() > + * - nand_deselect() > + */ References to what the code used to look like should go in the commit message -- they're not relevant to someone reading this code years from now. Splitting this up is going to add bytes -- is it really needed? > +void nand_init(void) > +{ > + struct nand_chip nand_chip; This is shadowing the file-scope nand_chip. > + /* > + * Init board specific nand support > + */ > + nand_chip.select_chip = NULL; > + info.priv = &nand_chip; > + nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = > + (void __iomem *)CONFIG_SYS_NAND_BASE; > + nand_chip.dev_ready = NULL; /* preset to NULL */ > + nand_chip.options = 0; Once you switch to the BSS nand_cihp, you can get rid of the zero init. > +/* Copy image from NAND to RAM > + * offs: Offset in NAND flash > + * size: size of image > + * dst: destination pointer to RAM > + */ > +void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst) > +{ > + nand_load(&info, offs, size, dst); > +} Just strip the mtd_info parameter from nand_load -- no need for a wrapper. -Scott
On 07/28/2011 09:16 PM, Scott Wood wrote: > On Thu, 28 Jul 2011 10:38:09 +0200 > Simon Schwarz<simonschwarzcor@googlemail.com> wrote: > >> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) > > Not sure what this has to do with NAND. right. This used by devkit8000 - will change the subject to "spl: add NAND and POWER library to new SPL" >> +int nand_curr_device = -1; >> +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; >> +static nand_info_t info; >> +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; >> +static struct nand_chip nand_chip; > > It doesn't look like nand_info or nand_curr_device are used. Already deleted. > >> +/* nand_boot()-function from the old nand_spl ripped apart into >> + * - nand_init() >> + * - nand_spl_load_image() >> + * - nand_deselect() >> + */ > > References to what the code used to look like should go in the commit > message -- they're not relevant to someone reading this code years from > now. Changed. > > Splitting this up is going to add bytes -- is it really needed? > Yes it is. Since nand_boot did everything in the old spl. Now we have to use the functions from the outside. The payload also can differ much more - u-boot image + environment. linux image with FDT image etc. It is also necessary for using parse_header by Aneesh. >> +void nand_init(void) >> +{ >> + struct nand_chip nand_chip; > > This is shadowing the file-scope nand_chip. Already deleted > >> + /* >> + * Init board specific nand support >> + */ >> + nand_chip.select_chip = NULL; >> + info.priv =&nand_chip; >> + nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = >> + (void __iomem *)CONFIG_SYS_NAND_BASE; >> + nand_chip.dev_ready = NULL; /* preset to NULL */ >> + nand_chip.options = 0; > > Once you switch to the BSS nand_cihp, you can get rid of the > zero init. do you mean when bss_init is done? If yes I will delete these. > >> +/* Copy image from NAND to RAM >> + * offs: Offset in NAND flash >> + * size: size of image >> + * dst: destination pointer to RAM >> + */ >> +void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst) >> +{ >> + nand_load(&info, offs, size, dst); >> +} > > Just strip the mtd_info parameter from nand_load -- no need for a wrapper. Since this was criticised by many - I will drop the old interface and get rid of mtd_info everywhere in nand_spl_simple.c > > -Scott > Regards & thx for review! Simon
Dear Simon Schwarz, In message <4E327989.6070300@gmail.com> you wrote: > On 07/28/2011 09:16 PM, Scott Wood wrote: > > On Thu, 28 Jul 2011 10:38:09 +0200 > > Simon Schwarz<simonschwarzcor@googlemail.com> wrote: > > > >> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) > > > > Not sure what this has to do with NAND. > > right. This used by devkit8000 - will change the subject to "spl: add > NAND and POWER library to new SPL" Should we not rather split this into two separate patches? Best regards, Wolfgang Denk
Hi Aneesh, On 07/28/2011 06:18 PM, Aneesh V wrote: [snip] >> >> Oh. There I played around with the Access Size Adaptation of the GPMC - >> It is still a x16 interface - this is what the 16 refers to IMHO. But > > Ok. I have to admit that I am not a NAND expert and I do not understand > this code well. > >> for sake of simplicity I will change this back to 16bit access - I don't >> think that there is a big performance impact although I didn't measure >> it. > > No. If it's an OMAP specific optimization, I don't see a reason to > remove it. Looks like that may actually improve performance. However, > you may have to take into account of the alignment of buffer, the size > requested etc. Please have a look at the implementation in drivers/mtd > /nand/davinci_nand.c(although the implementation here seems to be for > 8-bit devices, something similar may be possible for 16-bit) I literally just played around with that ;) I will add it in the standard version here. For my BA I will have to evaluate if it has a performance impact anyway - if it has I will send a patch later. > >> >> I cloned them because the functions in nand_base.c are static. >> >> My solution: deleted the cloned functions - use these from nand_base by >> removing the static modifier and add them to nand.h > > I hope there won't be any name-space conflict due to this. Me too. For devkit8000 there is none - BUILDALL will show. > > best regards, > Aneesh Regards Simon
Dear Wolfgang Denk, On 07/29/2011 11:27 AM, Wolfgang Denk wrote: > Dear Simon Schwarz, > > In message<4E327989.6070300@gmail.com> you wrote: >> On 07/28/2011 09:16 PM, Scott Wood wrote: >>> On Thu, 28 Jul 2011 10:38:09 +0200 >>> Simon Schwarz<simonschwarzcor@googlemail.com> wrote: >>> >>>> +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) >>> >>> Not sure what this has to do with NAND. >> >> right. This used by devkit8000 - will change the subject to "spl: add >> NAND and POWER library to new SPL" > > Should we not rather split this into two separate patches? Will do. > > Best regards, > > Wolfgang Denk > Regards Simon
diff --git a/doc/README.SPL b/doc/README.SPL index ce8e19f..2987f43 100644 --- a/doc/README.SPL +++ b/doc/README.SPL @@ -60,3 +60,5 @@ CONFIG_SPL_SPI_FLASH_SUPPORT (drivers/mtd/spi/libspi_flash.o) CONFIG_SPL_SPI_SUPPORT (drivers/spi/libspi.o) CONFIG_SPL_FAT_SUPPORT (fs/fat/libfat.o) CONFIG_SPL_LIBGENERIC_SUPPORT (lib/libgeneric.o) +CONFIG_SPL_POWER_SUPPORT (drivers/power/libpower.o) +CONFIG_SPL_NAND_SUPPORT (drivers/mtd/nand/libnand.o) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 8b598f6..cdc9a14 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,12 +26,16 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnand.o ifdef CONFIG_CMD_NAND +ifdef CONFIG_SPL_BUILD +COBJS-y += nand_spl.o +else COBJS-y += nand.o COBJS-y += nand_base.o COBJS-y += nand_bbt.o -COBJS-y += nand_ecc.o COBJS-y += nand_ids.o COBJS-y += nand_util.o +endif +COBJS-y += nand_ecc.o COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o diff --git a/drivers/mtd/nand/nand_spl.c b/drivers/mtd/nand/nand_spl.c new file mode 100644 index 0000000..fc78885 --- /dev/null +++ b/drivers/mtd/nand/nand_spl.c @@ -0,0 +1,268 @@ +/* + * (C) Copyright 2006-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <nand.h> +#include <asm/io.h> + +int nand_curr_device = -1; +static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; +static nand_info_t info; +nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; +static struct nand_chip nand_chip; + +#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) +/* + * NAND command for small page NAND devices (512) + */ +static int nand_command(struct mtd_info *mtd, int block, int page, int offs, + u8 cmd) +{ + struct nand_chip *this = mtd->priv; + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + + while (!this->dev_ready(mtd)) + ; + + /* Begin command latch cycle */ + this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Set ALE and clear CLE to start address cycle */ + /* Column address */ + this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); + this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */ + this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff, + NAND_CTRL_ALE); /* A[24:17] */ +#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE + /* One more address cycle for devices > 32MiB */ + this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE); /* A[28:25] */ +#endif + /* Latch in address */ + this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Wait a while for the data to be ready + */ + while (!this->dev_ready(mtd)) + ; + + return 0; +} +#else +/* + * NAND command for large page NAND devices (2k) + */ +static int nand_command(struct mtd_info *mtd, int block, int page, int offs, + u8 cmd) +{ + struct nand_chip *this = mtd->priv; + int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + + while (!this->dev_ready(mtd)) + ; + + /* Emulate NAND_CMD_READOOB */ + if (cmd == NAND_CMD_READOOB) { + offs += CONFIG_SYS_NAND_PAGE_SIZE; + cmd = NAND_CMD_READ0; + } + + /* Shift the offset from byte addressing to word addressing. */ + if (this->options & NAND_BUSWIDTH_16) + offs >>= 1; + + /* Begin command latch cycle */ + hwctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Set ALE and clear CLE to start address cycle */ + /* Column address */ + hwctrl(mtd, offs & 0xff, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ + hwctrl(mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ + /* Row address */ + hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ + hwctrl(mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE); /* A[27:20] */ +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE); /* A[31:28] */ +#endif + /* Latch in address */ + hwctrl(mtd, NAND_CMD_READSTART, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + hwctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Wait a while for the data to be ready + */ + while (!this->dev_ready(mtd)) + ; + + return 0; +} +#endif + +static int nand_is_bad_block(struct mtd_info *mtd, int block) +{ + struct nand_chip *this = mtd->priv; + + nand_command(mtd, block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, + NAND_CMD_READOOB); + + /* + * Read one byte (or two if it's a 16 bit chip). + */ + if (this->options & NAND_BUSWIDTH_16) { + if (readw(this->IO_ADDR_R) != 0xffff) + return 1; + } else { + if (readb(this->IO_ADDR_R) != 0xff) + return 1; + } + + return 0; +} + +static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) +{ + struct nand_chip *this = mtd->priv; + u_char *ecc_calc; + u_char *ecc_code; + u_char *oob_data; + int i; + int eccsize = CONFIG_SYS_NAND_ECCSIZE; + int eccbytes = CONFIG_SYS_NAND_ECCBYTES; + int eccsteps = CONFIG_SYS_NAND_ECCSTEPS; + uint8_t *p = dst; + int stat; + + nand_command(mtd, block, page, 0, NAND_CMD_READ0); + + /* No malloc available for now, just use some temporary locations + * in SDRAM + */ + ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000); + ecc_code = ecc_calc + 0x100; + oob_data = ecc_calc + 0x200; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + this->ecc.hwctl(mtd, NAND_ECC_READ); + this->read_buf(mtd, p, eccsize); + this->ecc.calculate(mtd, p, &ecc_calc[i]); + } + this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); + + /* Pick the ECC bytes out of the oob data */ + for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++) + ecc_code[i] = oob_data[nand_ecc_pos[i]]; + + eccsteps = CONFIG_SYS_NAND_ECCSTEPS; + p = dst; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + /* No chance to do something with the possible error message + * from correct_data(). We just hope that all possible errors + * are corrected by this routine. + */ + stat = this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + } + + return 0; +} + +static int nand_load(struct mtd_info *mtd, unsigned int offs, + unsigned int uboot_size, uchar *dst) +{ + unsigned int block, lastblock; + unsigned int page; + + /* + * offs has to be aligned to a page address! + */ + block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; + lastblock = (offs + uboot_size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; + page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; + + while (block <= lastblock) { + if (!nand_is_bad_block(mtd, block)) { + /* + * Skip bad blocks + */ + while (page < CONFIG_SYS_NAND_PAGE_COUNT) { + nand_read_page(mtd, block, page, dst); + dst += CONFIG_SYS_NAND_PAGE_SIZE; + page++; + } + + page = 0; + } else { + lastblock++; + } + + block++; + } + + return 0; +} + +/* nand_boot()-function from the old nand_spl ripped apart into + * - nand_init() + * - nand_spl_load_image() + * - nand_deselect() + */ +void nand_init(void) +{ + struct nand_chip nand_chip; + + /* + * Init board specific nand support + */ + nand_chip.select_chip = NULL; + info.priv = &nand_chip; + nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = + (void __iomem *)CONFIG_SYS_NAND_BASE; + nand_chip.dev_ready = NULL; /* preset to NULL */ + nand_chip.options = 0; + board_nand_init(&nand_chip); + + if (nand_chip.select_chip) + nand_chip.select_chip(&info, 0); +} + +/* Copy image from NAND to RAM + * offs: Offset in NAND flash + * size: size of image + * dst: destination pointer to RAM + */ +void nand_spl_load_image(loff_t offs, unsigned int size, uchar *dst) +{ + nand_load(&info, offs, size, dst); +} + +/* Unselect NAND chip after operation + */ +void nand_deselect(void) +{ + if (nand_chip.select_chip) + nand_chip.select_chip(&info, -1); + +} diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 99b9cef..61eac35 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -61,6 +61,55 @@ static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd, writeb(cmd, this->IO_ADDR_W); } +#ifdef CONFIG_SPL_BUILD +/* Check wait pin as dev ready indicator */ +int omap_spl_dev_ready(struct mtd_info *mtd) +{ + return gpmc_cfg->status & (1 << 8); +} + +/* + * omap_spl_read_buf16 - [DEFAULT] read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 16bit buswith + * + * This function is based on nand_read_buf16 from nand_base.c. This version + * reads 32bit not 16bit although the bus only has 16bit. + */ +static void omap_spl_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + u32 *p = (u32 *) buf; + len >>= 2; + + for (i = 0; i < len; i++) + p[i] = readl(chip->IO_ADDR_R); +} + +/* + * omap_spl_read_buf - [DEFAULT] read chip data into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + * + * Default read function for 8bit buswith + * + * This is the same function as this from nand_base.c nand_read_buf + */ +static void omap_spl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + for (i = 0; i < len; i++) + buf[i] = readb(chip->IO_ADDR_R); +} +#endif + /* * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in * GPMC controller @@ -224,6 +273,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) } } +#ifndef CONFIG_SPL_BUILD /* * omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc. * The default is to come up on s/w ecc @@ -280,6 +330,7 @@ void omap_nand_switch_ecc(int32_t hardware) nand->options &= ~NAND_OWN_BUFFERS; } +#endif /* CONFIG_SPL_BUILD */ /* * Board-specific NAND initialization. The following members of the @@ -338,7 +389,24 @@ int board_nand_init(struct nand_chip *nand) nand->chip_delay = 100; /* Default ECC mode */ +#ifndef CONFIG_SPL_BUILD nand->ecc.mode = NAND_ECC_SOFT; +#else + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.layout = &hw_nand_oob; + nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; + nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data; + nand->ecc.calculate = omap_calculate_ecc; + omap_hwecc_init(nand); + + if (nand->options & NAND_BUSWIDTH_16) + nand->read_buf = omap_spl_read_buf16; + else + nand->read_buf = omap_spl_read_buf; + nand->dev_ready = omap_spl_dev_ready; +#endif return 0; } diff --git a/spl/Makefile b/spl/Makefile index 87f13f6..0c0d3c4 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -46,6 +46,8 @@ LIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o LIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o +LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o +LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o ifeq ($(SOC),omap3) LIBS-y += $(CPUDIR)/omap-common/libomap-common.o
Insert some NAND driver sources into NAND SPL library. Signed-off-by: Simon Schwarz <simonschwarzcor@gmail.com> --- V1 changes: CHG Default to HW ecc in SPL build ADD nand_read_buf16 function, read buffer ADD omap_dev_ready function, indicte if chip is ready V2 changes: DEL GPMC_WAIT0_PIN_ACTIVE define CHG omap_dev_ready() renamed to omap_spl_dev_ready(), does not use the GPMC_WAIT0_PIN_ACTIVE-define anymore CHG ogpmc_read_buf16 renamed omap_spl_read_buf16 ADD omap_spl_read_buf, 8x buf read function ADD CONFIG_SPL_POWER_SUPPORT and CONFIG_SPL_NAND_SUPPORT to SPL CHG cosmetic CHG nand_base and nand_bbt aren't needed for SPL anymore CHG omap_nand_switch_ecc is not compiled for SPL ADD entry for CONFIG_SPL_POWER_SUPPORT and CONFIG_SPL_NAND_SUPPORT to README.SPL V3 changes: DEL cosmetic (empty line) V4 changes: nothing V5 changes: CHG nand_ecc.o is only compiled for SPL if CONFIG_OMAP34XX is set V6 changes: ADD nand_spl.c - git add, finally DEL nand_ecc barrier ifdef for OMAP3 Transition from V1 to V2 also includes that this patch is now based on - the new SPL layout by Aneesh V and Daniel Schwierzeck - the OMAP4 SPL patches by Aneesh V This Patch is related to "[U-Boot,4/5] devkit8000 nand_spl: Add SPL NAND support to omap_gpmc driver" (http://article.gmane.org/gmane.comp.boot-loaders.u-boot/102115) in V1 --- doc/README.SPL | 2 + drivers/mtd/nand/Makefile | 6 +- drivers/mtd/nand/nand_spl.c | 268 ++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/omap_gpmc.c | 68 +++++++++++ spl/Makefile | 2 + 5 files changed, 345 insertions(+), 1 deletions(-) create mode 100644 drivers/mtd/nand/nand_spl.c