[U-Boot] [PATCH v4 0/6] tegra: Add NAND flash support

This series adds NAND flash support to Tegra and enables it on Seaboard.
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Changes in v2: - Add new patch to align default buffers in nand_base - Added comment about the behaviour of the 'resp' register - Call set_bus_width_page_size() at init to report errors earlier - Change set_bus_width_page_size() to return an error when needed - Change timing structure member to u32 to match device tree - Check for supported bus width in board_nand_init() - Fix tegra nand header file to remove BIT defines - Implement a dummy nand_select_chip() instead of nand_hwcontro() - Make nand_command() display an error on an unknown command - Minor code tidy-ups in driver for style - Move cache logic into a separate dma_prepare() function - Remove CMD_TRANS_SIZE_BYTESx enum - Remove space after casts - Remove use of 'register' variables - Rename struct nand_info to struct nand_drv to avoid nand_info_t confusion - Support 4096 byte page devices, drop 1024 and 2048 - Tidy up nand_waitfor_cmd_completion() logic - Update NAND binding to add "nvidia," prefix - Use s32 for device tree integer values
Changes in v3: - Add reg property for unit address (should be used for chip select) - Change note in fdt binding about the need for a hardware-specific binding - Fix up typos in fdt binding, and rename the file - Update fdt binding to make everything Nvidia-specific
Changes in v4: - Align buffer length to cache line size in dma_prepare() - Fix "Write Page 0x0 timeout with ECC" error on 4.4.1 - Fix the issue that read_byte can read at most 4 times - Get some information from Read ID data instead of from device tree - In nand_command, set NAND_CMD_RNDOUT as unsupported command - Modify eccoob layout - Move to using CONFIG_SYS_NAND_SELF_INIT - Remove "DEFAULT" from comment because that function is not default - Remove fdt bindings related to page structure - Remove local read_buf and write_buf functions - Remove some fields in fdt_nand structure - Rename CONFIG_TEGRA2_NAND to CONFIG_TEGRA_NAND - Rename variables my_* as our_* - Use virt_to_phys() when filling address register
Jim Lin (1): tegra: nand: Add Tegra NAND driver
Simon Glass (5): nand: Try to align the default buffers tegra: Add NAND support to funcmux tegra: fdt: Add NAND controller binding and definitions tegra: fdt: Add NAND definitions to fdt tegra: Enable NAND on Seaboard
arch/arm/cpu/tegra20-common/funcmux.c | 7 + arch/arm/dts/tegra20.dtsi | 7 + arch/arm/include/asm/arch-tegra20/funcmux.h | 3 + arch/arm/include/asm/arch-tegra20/tegra20.h | 1 + board/nvidia/dts/tegra20-seaboard.dts | 10 + .../nand/nvidia,tegra20-nand.txt | 53 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/nand_base.c | 3 +- drivers/mtd/nand/tegra_nand.c | 1026 ++++++++++++++++++++ drivers/mtd/nand/tegra_nand.h | 257 +++++ include/configs/seaboard.h | 9 + include/configs/tegra20-common.h | 2 + include/fdtdec.h | 1 + include/linux/mtd/nand.h | 7 +- lib/fdtdec.c | 1 + 15 files changed, 1384 insertions(+), 4 deletions(-) create mode 100644 doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt create mode 100644 drivers/mtd/nand/tegra_nand.c create mode 100644 drivers/mtd/nand/tegra_nand.h

The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bfd668f..891af1f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2936,7 +2936,8 @@ int nand_scan_tail(struct mtd_info *mtd) struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS)) - chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); + chip->buffers = memalign(ARCH_DMA_MINALIGN, + sizeof(*chip->buffers)); if (!chip->buffers) return -ENOMEM;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..dc839e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -391,9 +391,10 @@ struct nand_ecc_ctrl { * consecutive order. */ struct nand_buffers { - uint8_t ecccalc[NAND_MAX_OOBSIZE]; - uint8_t ecccode[NAND_MAX_OOBSIZE]; - uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE]; + uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; + uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)]; + uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, + ARCH_DMA_MINALIGN)]; };
/**

On 07/30/2012 01:53 AM, Simon Glass wrote:
The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
Acked-by: Scott Wood <scottwood@freescale.com.
-Scott

Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 1/6] nand: Try to align the default buffers
The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bfd668f..891af1f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2936,7 +2936,8 @@ int nand_scan_tail(struct mtd_info *mtd) struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
chip->buffers = memalign(ARCH_DMA_MINALIGN,
if (!chip->buffers) return -ENOMEM;sizeof(*chip->buffers));
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..dc839e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -391,9 +391,10 @@ struct nand_ecc_ctrl {
- consecutive order.
*/ struct nand_buffers {
- uint8_t ecccalc[NAND_MAX_OOBSIZE];
- uint8_t ecccode[NAND_MAX_OOBSIZE];
- uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
- uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE,
ARCH_DMA_MINALIGN)];
};
This causes build failures in the M28EVK build (./MAKEALL -a arm, with current u-boot-tegra/next & gcc 4.4.1):
In file included from mxs_nand.c:29: /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: warning: implicit declaration of function 'ALIGN' /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: 'ARCH_DMA_MINALIGN' undeclared here (not in a function) /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: variably modified 'ecccalc' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:395: error: variably modified 'ecccode' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:397: error: variably modified 'databuf' at file scope make[1]: *** [mxs_nand.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [drivers/mtd/nand/libnand.o] Error 2 make: *** Waiting for unfinished jobs....
PTAL. Thanks,
Tom
/**
1.7.7.3

Dear Tom Warren,
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 1/6] nand: Try to align the default buffers
The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bfd668f..891af1f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2936,7 +2936,8 @@ int nand_scan_tail(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
chip->buffers = memalign(ARCH_DMA_MINALIGN,
sizeof(*chip->buffers));
if (!chip->buffers)
return -ENOMEM;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..dc839e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -391,9 +391,10 @@ struct nand_ecc_ctrl {
- consecutive order.
*/
struct nand_buffers {
- uint8_t ecccalc[NAND_MAX_OOBSIZE];
- uint8_t ecccode[NAND_MAX_OOBSIZE];
- uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
- uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE,
ARCH_DMA_MINALIGN)];
};
include asm/cache.h or something ?
This causes build failures in the M28EVK build (./MAKEALL -a arm, with current u-boot-tegra/next & gcc 4.4.1):
In file included from mxs_nand.c:29: /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: warning: implicit declaration of function 'ALIGN' /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: 'ARCH_DMA_MINALIGN' undeclared here (not in a function) /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: variably modified 'ecccalc' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:395: error: variably modified 'ecccode' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:397: error: variably modified 'databuf' at file scope make[1]: *** [mxs_nand.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [drivers/mtd/nand/libnand.o] Error 2 make: *** Waiting for unfinished jobs....
PTAL. Thanks,
Tom
/**
-- 1.7.7.3
Best regards, Marek Vasut

Marek,
-----Original Message----- From: Marek Vasut [mailto:marex@denx.de] Sent: Friday, September 07, 2012 11:43 AM To: u-boot@lists.denx.de Cc: Tom Warren; Simon Glass; Scott Wood Subject: Re: [U-Boot] [PATCH v4 1/6] nand: Try to align the default buffers
Dear Tom Warren,
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 1/6] nand: Try to align the default buffers
The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bfd668f..891af1f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2936,7 +2936,8 @@ int nand_scan_tail(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
chip->buffers = memalign(ARCH_DMA_MINALIGN,
sizeof(*chip->buffers));
if (!chip->buffers)
return -ENOMEM;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..dc839e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -391,9 +391,10 @@ struct nand_ecc_ctrl {
- consecutive order.
*/
struct nand_buffers {
- uint8_t ecccalc[NAND_MAX_OOBSIZE];
- uint8_t ecccode[NAND_MAX_OOBSIZE];
- uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
- uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE,
ARCH_DMA_MINALIGN)];
};
include asm/cache.h or something ?
Thanks, Marek. Mxs_nand.c appears to be 99% yours (and you're listed as the maintainer of m28evk) - would you be willing to submit a patch? That'll also fix apx4devkit, which fails w/the same errors.
Tom
This causes build failures in the M28EVK build (./MAKEALL -a arm, with current u-boot-tegra/next & gcc 4.4.1):
In file included from mxs_nand.c:29: /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: warning: implicit declaration of function 'ALIGN' /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: 'ARCH_DMA_MINALIGN' undeclared here (not in a function) /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:394: error: variably modified 'ecccalc' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:395: error: variably modified 'ecccode' at file scope /home/tom/denx/uboot-tegra/include/linux/mtd/nand.h:397: error: variably modified 'databuf' at file scope make[1]: *** [mxs_nand.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [drivers/mtd/nand/libnand.o] Error 2 make: *** Waiting for unfinished jobs....
PTAL. Thanks,
Tom
/**
-- 1.7.7.3
Best regards, Marek Vasut

Dear Tom Warren,
Marek,
-----Original Message----- From: Marek Vasut [mailto:marex@denx.de] Sent: Friday, September 07, 2012 11:43 AM To: u-boot@lists.denx.de Cc: Tom Warren; Simon Glass; Scott Wood Subject: Re: [U-Boot] [PATCH v4 1/6] nand: Try to align the default buffers
Dear Tom Warren,
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 1/6] nand: Try to align the default buffers
The NAND layer needs to use cache-aligned buffers by default. Towards this goal. align the default buffers and their members according to the minimum DMA alignment defined for the architecture.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add new patch to align default buffers in nand_base
drivers/mtd/nand/nand_base.c | 3 ++- include/linux/mtd/nand.h | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bfd668f..891af1f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2936,7 +2936,8 @@ int nand_scan_tail(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
chip->buffers = kmalloc(sizeof(*chip->buffers),
GFP_KERNEL);
chip->buffers = memalign(ARCH_DMA_MINALIGN,
sizeof(*chip->buffers));
if (!chip->buffers)
return -ENOMEM;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 82704de..dc839e7 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -391,9 +391,10 @@ struct nand_ecc_ctrl {
- consecutive order.
*/
struct nand_buffers {
- uint8_t ecccalc[NAND_MAX_OOBSIZE];
- uint8_t ecccode[NAND_MAX_OOBSIZE];
- uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
- uint8_t ecccalc[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t ecccode[ALIGN(NAND_MAX_OOBSIZE, ARCH_DMA_MINALIGN)];
- uint8_t databuf[ALIGN(NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE,
ARCH_DMA_MINALIGN)];
};
include asm/cache.h or something ?
Thanks, Marek. Mxs_nand.c appears to be 99% yours (and you're listed as the maintainer of m28evk) - would you be willing to submit a patch? That'll also fix apx4devkit, which fails w/the same errors.
I think it's simple enough, just mising one common define. Generate the patch and I'll ack it :)
Tom
[...]
Best regards, Marek Vasut

Add selection of NAND flash pins to the funcmux.
Signed-off-by: Simon Glass sjg@chromium.org Acked-by: Stephen Warren swarren@nvidia.com ---
arch/arm/cpu/tegra20-common/funcmux.c | 7 +++++++ arch/arm/include/asm/arch-tegra20/funcmux.h | 3 +++ 2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/tegra20-common/funcmux.c b/arch/arm/cpu/tegra20-common/funcmux.c index 8cfed64..b2129ad 100644 --- a/arch/arm/cpu/tegra20-common/funcmux.c +++ b/arch/arm/cpu/tegra20-common/funcmux.c @@ -234,6 +234,13 @@ int funcmux_select(enum periph_id id, int config) } break;
+ case PERIPH_ID_NDFLASH: + if (config == FUNCMUX_NDFLASH_ATC) { + pinmux_set_func(PINGRP_ATC, PMUX_FUNC_NAND); + pinmux_tristate_disable(PINGRP_ATC); + } + break; + default: debug("%s: invalid periph_id %d", __func__, id); return -1; diff --git a/arch/arm/include/asm/arch-tegra20/funcmux.h b/arch/arm/include/asm/arch-tegra20/funcmux.h index 258f7b6..bd511db 100644 --- a/arch/arm/include/asm/arch-tegra20/funcmux.h +++ b/arch/arm/include/asm/arch-tegra20/funcmux.h @@ -57,6 +57,9 @@ enum {
/* Serial Flash configs */ FUNCMUX_SPI1_GMC_GMD = 0, + + /* NAND flags */ + FUNCMUX_NDFLASH_ATC = 0, };
/**

Add a NAND controller along with a bindings file for review.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Update NAND binding to add "nvidia," prefix
Changes in v3: - Add reg property for unit address (should be used for chip select) - Change note in fdt binding about the need for a hardware-specific binding - Fix up typos in fdt binding, and rename the file - Update fdt binding to make everything Nvidia-specific
Changes in v4: - Remove fdt bindings related to page structure
arch/arm/dts/tegra20.dtsi | 7 +++ .../nand/nvidia,tegra20-nand.txt | 53 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 0 deletions(-) create mode 100644 doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index f95be58..d936b1e 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -204,4 +204,11 @@ compatible = "nvidia,tegra20-kbc"; reg = <0x7000e200 0x0078>; }; + + nand: nand-controller@70008000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-nand"; + reg = <0x70008000 0x100>; + }; }; diff --git a/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt new file mode 100644 index 0000000..86ae408 --- /dev/null +++ b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt @@ -0,0 +1,53 @@ +NAND Flash +---------- + +(there isn't yet a generic binding in Linux, so this describes what is in +U-Boot. There should not be Linux-specific or U-Boot specific binding, just +a binding that describes this hardware. But agreeing a binding in Linux in +the absence of a driver may be beyond my powers.) + +The device node for a NAND flash device is as follows: + +Required properties : + - compatible : Should be "manufacturer,device", "nand-flash" + +This node should sit inside its controller. + + +Nvidia NAND Controller +---------------------- + +The device node for a NAND flash controller is as follows: + +Optional properties: + +nvidia,wp-gpios : GPIO of write-protect line, three cells in the format: + phandle, parameter, flags +nvidia,nand-width : bus width of the NAND device in bits + + - nvidia,nand-timing : Timing parameters for the NAND. Each is in ns. + Order is: MAX_TRP_TREA, TWB, Max(tCS, tCH, tALS, tALH), + TWHR, Max(tCS, tCH, tALS, tALH), TWH, TWP, TRH, TADL + + MAX_TRP_TREA is: + non-EDO mode: Max(tRP, tREA) + 6ns + EDO mode: tRP timing + +The 'reg' property should provide the chip select used by the flash chip. + + +Example +------- + +nand-controller@0x70008000 { + compatible = "nvidia,tegra20-nand"; + #address-cells = <1>; + #size-cells = <0>; + nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */ + nvidia,nand-width = <8>; + nvidia,timing = <26 100 20 80 20 10 12 10 70>; + nand@0 { + reg = <0>; + compatible = "hynix,hy27uf4g2b", "nand-flash"; + }; +};

On 07/30/2012 01:53 AM, Simon Glass wrote:
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index f95be58..d936b1e 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -204,4 +204,11 @@ compatible = "nvidia,tegra20-kbc"; reg = <0x7000e200 0x0078>; };
- nand: nand-controller@70008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra20-nand";
reg = <0x70008000 0x100>;
- };
}; diff --git a/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt new file mode 100644 index 0000000..86ae408 --- /dev/null +++ b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt @@ -0,0 +1,53 @@ +NAND Flash +----------
+(there isn't yet a generic binding in Linux, so this describes what is in +U-Boot. There should not be Linux-specific or U-Boot specific binding, just +a binding that describes this hardware. But agreeing a binding in Linux in +the absence of a driver may be beyond my powers.)
Please at least attempt to get a binding accepted in Linux, or perhaps in a neutral repository such as devicetree.org (but point out on devicetree-discuss that you've posted it there). The device tree is supposed to describe the hardware, not what Linux currently uses.
+Example +-------
+nand-controller@0x70008000 {
- compatible = "nvidia,tegra20-nand";
- #address-cells = <1>;
- #size-cells = <0>;
- nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */
- nvidia,nand-width = <8>;
- nvidia,timing = <26 100 20 80 20 10 12 10 70>;
- nand@0 {
reg = <0>;
compatible = "hynix,hy27uf4g2b", "nand-flash";
- };
+};
Where is "reg" in the parent node? You're not supposed to have a unit address without reg. Also, most bus bindings don't put 0x in the unit address).
I see that it's OK in the actual .dtsi -- it's just the example that needs fixing.
-Scott

Hi Scott,
On Tue, Jul 31, 2012 at 12:05 AM, Scott Wood scottwood@freescale.com wrote:
On 07/30/2012 01:53 AM, Simon Glass wrote:
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index f95be58..d936b1e 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -204,4 +204,11 @@ compatible = "nvidia,tegra20-kbc"; reg = <0x7000e200 0x0078>; };
nand: nand-controller@70008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra20-nand";
reg = <0x70008000 0x100>;
};
}; diff --git a/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt new file mode 100644 index 0000000..86ae408 --- /dev/null +++ b/doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt @@ -0,0 +1,53 @@ +NAND Flash +----------
+(there isn't yet a generic binding in Linux, so this describes what is in +U-Boot. There should not be Linux-specific or U-Boot specific binding, just +a binding that describes this hardware. But agreeing a binding in Linux in +the absence of a driver may be beyond my powers.)
Please at least attempt to get a binding accepted in Linux, or perhaps in a neutral repository such as devicetree.org (but point out on devicetree-discuss that you've posted it there). The device tree is supposed to describe the hardware, not what Linux currently uses.
+Example +-------
+nand-controller@0x70008000 {
compatible = "nvidia,tegra20-nand";
#address-cells = <1>;
#size-cells = <0>;
nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */
nvidia,nand-width = <8>;
nvidia,timing = <26 100 20 80 20 10 12 10 70>;
nand@0 {
reg = <0>;
compatible = "hynix,hy27uf4g2b", "nand-flash";
};
+};
Where is "reg" in the parent node? You're not supposed to have a unit address without reg. Also, most bus bindings don't put 0x in the unit address).
I see that it's OK in the actual .dtsi -- it's just the example that needs fixing.
OK I will fix these and send a new patch.
Regards, Simon
-Scott

Add a flash node to handle the NAND, including memory timings and page / block size information.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Update NAND binding to add "nvidia," prefix
Changes in v3: - Add reg property for unit address (should be used for chip select) - Update fdt binding to make everything Nvidia-specific
Changes in v4: - Remove fdt bindings related to page structure
board/nvidia/dts/tegra20-seaboard.dts | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index 3352539..25a63a0 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -153,4 +153,14 @@ 0x1f04008a>; linux,fn-keymap = <0x05040002>; }; + + nand-controller@70008000 { + nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */ + nvidia,width = <8>; + nvidia,timing = <26 100 20 80 20 10 12 10 70>; + nand@0 { + reg = <0>; + compatible = "hynix,hy27uf4g2b", "nand-flash"; + }; + }; };

On 07/30/2012 01:53 AM, Simon Glass wrote:
Add a flash node to handle the NAND, including memory timings and page / block size information.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Update NAND binding to add "nvidia," prefix
Changes in v3:
- Add reg property for unit address (should be used for chip select)
- Update fdt binding to make everything Nvidia-specific
Changes in v4:
- Remove fdt bindings related to page structure
board/nvidia/dts/tegra20-seaboard.dts | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index 3352539..25a63a0 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -153,4 +153,14 @@ 0x1f04008a>; linux,fn-keymap = <0x05040002>; };
- nand-controller@70008000 {
nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */
nvidia,width = <8>;
nvidia,timing = <26 100 20 80 20 10 12 10 70>;
nand@0 {
reg = <0>;
compatible = "hynix,hy27uf4g2b", "nand-flash";
};
- };
Are #address-cells, #size-cells, and reg on the controller node provided by an /include/?
-Scott

Hi Scott,
On Mon, Jul 30, 2012 at 11:49 PM, Scott Wood scottwood@freescale.com wrote:
On 07/30/2012 01:53 AM, Simon Glass wrote:
Add a flash node to handle the NAND, including memory timings and page / block size information.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Update NAND binding to add "nvidia," prefix
Changes in v3:
- Add reg property for unit address (should be used for chip select)
- Update fdt binding to make everything Nvidia-specific
Changes in v4:
- Remove fdt bindings related to page structure
board/nvidia/dts/tegra20-seaboard.dts | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/dts/tegra20-seaboard.dts b/board/nvidia/dts/tegra20-seaboard.dts index 3352539..25a63a0 100644 --- a/board/nvidia/dts/tegra20-seaboard.dts +++ b/board/nvidia/dts/tegra20-seaboard.dts @@ -153,4 +153,14 @@ 0x1f04008a>; linux,fn-keymap = <0x05040002>; };
nand-controller@70008000 {
nvidia,wp-gpios = <&gpio 59 0>; /* PH3 */
nvidia,width = <8>;
nvidia,timing = <26 100 20 80 20 10 12 10 70>;
nand@0 {
reg = <0>;
compatible = "hynix,hy27uf4g2b", "nand-flash";
};
};
Are #address-cells, #size-cells, and reg on the controller node provided by an /include/?
Yes that's right, in the previous patch:
nand: nand-controller@70008000 { #address-cells = <1>; #size-cells = <0>; compatible = "nvidia,tegra20-nand"; reg = <0x70008000 0x100>; };
Regards, Simon
-Scott

From: Jim Lin jilin@nvidia.com
A device tree is used to configure the NAND, including memory timings and block/pages sizes.
If this node is not present or is disabled, then NAND will not be initialized.
Signed-off-by: Jim Lin jilin@nvidia.com Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Added comment about the behaviour of the 'resp' register - Call set_bus_width_page_size() at init to report errors earlier - Change set_bus_width_page_size() to return an error when needed - Change timing structure member to u32 to match device tree - Check for supported bus width in board_nand_init() - Fix tegra nand header file to remove BIT defines - Implement a dummy nand_select_chip() instead of nand_hwcontro() - Make nand_command() display an error on an unknown command - Minor code tidy-ups in driver for style - Move cache logic into a separate dma_prepare() function - Remove CMD_TRANS_SIZE_BYTESx enum - Remove space after casts - Remove use of 'register' variables - Rename struct nand_info to struct nand_drv to avoid nand_info_t confusion - Support 4096 byte page devices, drop 1024 and 2048 - Tidy up nand_waitfor_cmd_completion() logic - Update NAND binding to add "nvidia," prefix - Use s32 for device tree integer values
Changes in v3: - Update fdt binding to make everything Nvidia-specific
Changes in v4: - Align buffer length to cache line size in dma_prepare() - Fix "Write Page 0x0 timeout with ECC" error on 4.4.1 - Fix the issue that read_byte can read at most 4 times - Get some information from Read ID data instead of from device tree - In nand_command, set NAND_CMD_RNDOUT as unsupported command - Modify eccoob layout - Move to using CONFIG_SYS_NAND_SELF_INIT - Remove "DEFAULT" from comment because that function is not default - Remove local read_buf and write_buf functions - Remove some fields in fdt_nand structure - Rename variables my_* as our_* - Use virt_to_phys() when filling address register
arch/arm/include/asm/arch-tegra20/tegra20.h | 1 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/tegra_nand.c | 1026 +++++++++++++++++++++++++++ drivers/mtd/nand/tegra_nand.h | 257 +++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 6 files changed, 1287 insertions(+), 0 deletions(-) create mode 100644 drivers/mtd/nand/tegra_nand.c create mode 100644 drivers/mtd/nand/tegra_nand.h
diff --git a/arch/arm/include/asm/arch-tegra20/tegra20.h b/arch/arm/include/asm/arch-tegra20/tegra20.h index 6750754..b2fb50e 100644 --- a/arch/arm/include/asm/arch-tegra20/tegra20.h +++ b/arch/arm/include/asm/arch-tegra20/tegra20.h @@ -39,6 +39,7 @@ #define NV_PA_APB_UARTC_BASE (NV_PA_APB_MISC_BASE + 0x6200) #define NV_PA_APB_UARTD_BASE (NV_PA_APB_MISC_BASE + 0x6300) #define NV_PA_APB_UARTE_BASE (NV_PA_APB_MISC_BASE + 0x6400) +#define TEGRA20_NAND_BASE (NV_PA_APB_MISC_BASE + 0x8000) #define TEGRA20_SPI_BASE (NV_PA_APB_MISC_BASE + 0xC380) #define TEGRA20_PMC_BASE (NV_PA_APB_MISC_BASE + 0xE400) #define TEGRA20_FUSE_BASE (NV_PA_APB_MISC_BASE + 0xF800) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 29dc20e..beb99ca 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -62,6 +62,7 @@ COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o +COBJS-$(CONFIG_TEGRA_NAND) += tegra_nand.o COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o endif diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c new file mode 100644 index 0000000..8c1de34 --- /dev/null +++ b/drivers/mtd/nand/tegra_nand.c @@ -0,0 +1,1026 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com> + * (C) Copyright 2006 Detlev Zundel, dzu@denx.de + * (C) Copyright 2006 DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <asm/io.h> +#include <nand.h> +#include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> +#include <asm/arch/funcmux.h> +#include <asm/arch/gpio.h> +#include <asm/errno.h> +#include <asm-generic/gpio.h> +#include <fdtdec.h> +#include "tegra_nand.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define NAND_CMD_TIMEOUT_MS 10 + +#define SKIPPED_SPARE_BYTES 4 + +/* ECC bytes to be generated for tag data */ +#define TAG_ECC_BYTES 4 + +/* 64 byte oob block info for large page (== 2KB) device + * + * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC: + * Skipped bytes(4) + * Main area Ecc(36) + * Tag data(20) + * Tag data Ecc(4) + * + * Yaffs2 will use 16 tag bytes. + */ +static struct nand_ecclayout eccoob = { + .eccbytes = 36, + .eccpos = { + 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, + }, + .oobavail = 20, + .oobfree = { + { + .offset = 40, + .length = 20, + }, + } +}; + +enum { + ECC_OK, + ECC_TAG_ERROR = 1 << 0, + ECC_DATA_ERROR = 1 << 1 +}; + +/* Timing parameters */ +enum { + FDT_NAND_MAX_TRP_TREA, + FDT_NAND_TWB, + FDT_NAND_MAX_TCR_TAR_TRR, + FDT_NAND_TWHR, + FDT_NAND_MAX_TCS_TCH_TALS_TALH, + FDT_NAND_TWH, + FDT_NAND_TWP, + FDT_NAND_TRH, + FDT_NAND_TADL, + + FDT_NAND_TIMING_COUNT +}; + +/* Information about an attached NAND chip */ +struct fdt_nand { + struct nand_ctlr *reg; + int enabled; /* 1 to enable, 0 to disable */ + struct fdt_gpio_state wp_gpio; /* write-protect GPIO */ + s32 width; /* bit width, normally 8 */ + u32 timing[FDT_NAND_TIMING_COUNT]; +}; + +struct nand_drv { + struct nand_ctlr *reg; + + /* + * When running in PIO mode to get READ ID bytes from register + * RESP_0, we need this variable as an index to know which byte in + * register RESP_0 should be read. + * Because common code in nand_base.c invokes read_byte function two + * times for NAND_CMD_READID. + * And our controller returns 4 bytes at once in register RESP_0. + */ + int pio_byte_index; + struct fdt_nand config; +}; + +static struct nand_drv nand_ctrl; +static struct mtd_info *our_mtd; +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; + +#ifdef CONFIG_SYS_DCACHE_OFF +static inline void dma_prepare(void *start, unsigned long length, + int is_writing) +{ +} +#else +/** + * Prepare for a DMA transaction + * + * For a write we flush out our data. For a read we invalidate, since we + * need to do this before we read from the buffer after the DMA has + * completed, so may as well do it now. + * + * @param start Start address for DMA buffer (should be cache-aligned) + * @param length Length of DMA buffer in bytes + * @param is_writing 0 if reading, non-zero if writing + */ +static void dma_prepare(void *start, unsigned long length, int is_writing) +{ + unsigned long addr = (unsigned long)start; + + length = ALIGN(length, ARCH_DMA_MINALIGN); + if (is_writing) + flush_dcache_range(addr, addr + length); + else + invalidate_dcache_range(addr, addr + length); +} +#endif + +/** + * Wait for command completion + * + * @param reg nand_ctlr structure + * @return + * 1 - Command completed + * 0 - Timeout + */ +static int nand_waitfor_cmd_completion(struct nand_ctlr *reg) +{ + u32 reg_val; + int running; + int i; + + for (i = 0; i < NAND_CMD_TIMEOUT_MS * 1000; i++) { + if ((readl(®->command) & CMD_GO) || + !(readl(®->status) & STATUS_RBSY0) || + !(readl(®->isr) & ISR_IS_CMD_DONE)) { + udelay(1); + continue; + } + reg_val = readl(®->dma_mst_ctrl); + /* + * If DMA_MST_CTRL_EN_A_ENABLE or DMA_MST_CTRL_EN_B_ENABLE + * is set, that means DMA engine is running. + * + * Then we have to wait until DMA_MST_CTRL_IS_DMA_DONE + * is cleared, indicating DMA transfer completion. + */ + running = reg_val & (DMA_MST_CTRL_EN_A_ENABLE | + DMA_MST_CTRL_EN_B_ENABLE); + if (!running || (reg_val & DMA_MST_CTRL_IS_DMA_DONE)) + return 1; + udelay(1); + } + return 0; +} + +/** + * Read one byte from the chip + * + * @param mtd MTD device structure + * @return data byte + * + * Read function for 8bit bus-width + */ +static uint8_t read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + u32 dword_read; + struct nand_drv *info; + + info = (struct nand_drv *)chip->priv; + + /* In PIO mode, only 4 bytes can be transferred with single CMD_GO. */ + if (info->pio_byte_index > 3) { + info->pio_byte_index = 0; + writel(CMD_GO | CMD_PIO + | CMD_RX | CMD_CE0, + &info->reg->command); + if (!nand_waitfor_cmd_completion(info->reg)) + printf("Command timeout\n"); + } + + dword_read = readl(&info->reg->resp); + dword_read = dword_read >> (8 * info->pio_byte_index); + info->pio_byte_index++; + return (uint8_t)dword_read; +} + +/** + * Check NAND status to see if it is ready or not + * + * @param mtd MTD device structure + * @return + * 1 - ready + * 0 - not ready + */ +static int nand_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + int reg_val; + struct nand_drv *info; + + info = (struct nand_drv *)chip->priv; + + reg_val = readl(&info->reg->status); + if (reg_val & STATUS_RBSY0) + return 1; + else + return 0; +} + +/* Dummy implementation: we don't support multiple chips */ +static void nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + switch (chipnr) { + case -1: + case 0: + break; + + default: + BUG(); + } +} + +/** + * Clear all interrupt status bits + * + * @param reg nand_ctlr structure + */ +static void nand_clear_interrupt_status(struct nand_ctlr *reg) +{ + u32 reg_val; + + /* Clear interrupt status */ + reg_val = readl(®->isr); + writel(reg_val, ®->isr); +} + +/** + * Send command to NAND device + * + * @param mtd MTD device structure + * @param command the command to be sent + * @param column the column address for this command, -1 if none + * @param page_addr the page address for this command, -1 if none + */ +static void nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd->priv; + struct nand_drv *info; + + info = (struct nand_drv *)chip->priv; + + /* + * Write out the command to the device. + * + * Only command NAND_CMD_RESET or NAND_CMD_READID will come + * here before mtd->writesize is initialized. + */ + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + assert(mtd->writesize != 0); + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Adjust columns for 16 bit bus-width */ + if (column != -1 && (chip->options & NAND_BUSWIDTH_16)) + column >>= 1; + + nand_clear_interrupt_status(info->reg); + + /* Stop DMA engine, clear DMA completion status */ + writel(DMA_MST_CTRL_EN_A_DISABLE + | DMA_MST_CTRL_EN_B_DISABLE + | DMA_MST_CTRL_IS_DMA_DONE, + &info->reg->dma_mst_ctrl); + + /* + * Program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + case NAND_CMD_READID: + writel(NAND_CMD_READID, &info->reg->cmd_reg1); + writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_PIO + | CMD_RX | + ((4 - 1) << CMD_TRANS_SIZE_SHIFT) + | CMD_CE0, + &info->reg->command); + info->pio_byte_index = 0; + break; + case NAND_CMD_READ0: + writel(NAND_CMD_READ0, &info->reg->cmd_reg1); + writel(NAND_CMD_READSTART, &info->reg->cmd_reg2); + writel((page_addr << 16) | (column & 0xFFFF), + &info->reg->addr_reg1); + writel(page_addr >> 16, &info->reg->addr_reg2); + return; + case NAND_CMD_SEQIN: + writel(NAND_CMD_SEQIN, &info->reg->cmd_reg1); + writel(NAND_CMD_PAGEPROG, &info->reg->cmd_reg2); + writel((page_addr << 16) | (column & 0xFFFF), + &info->reg->addr_reg1); + writel(page_addr >> 16, + &info->reg->addr_reg2); + return; + case NAND_CMD_PAGEPROG: + return; + case NAND_CMD_ERASE1: + writel(NAND_CMD_ERASE1, &info->reg->cmd_reg1); + writel(NAND_CMD_ERASE2, &info->reg->cmd_reg2); + writel(page_addr, &info->reg->addr_reg1); + writel(CMD_GO | CMD_CLE | CMD_ALE | + CMD_SEC_CMD | CMD_CE0 | CMD_ALE_BYTES3, + &info->reg->command); + break; + case NAND_CMD_ERASE2: + return; + case NAND_CMD_STATUS: + writel(NAND_CMD_STATUS, &info->reg->cmd_reg1); + writel(CMD_GO | CMD_CLE | CMD_PIO | CMD_RX + | ((1 - 0) << CMD_TRANS_SIZE_SHIFT) + | CMD_CE0, + &info->reg->command); + info->pio_byte_index = 0; + break; + case NAND_CMD_RESET: + writel(NAND_CMD_RESET, &info->reg->cmd_reg1); + writel(CMD_GO | CMD_CLE | CMD_CE0, + &info->reg->command); + break; + case NAND_CMD_RNDOUT: + default: + printf("%s: Unsupported command %d\n", __func__, command); + return; + } + if (!nand_waitfor_cmd_completion(info->reg)) + printf("Command 0x%02X timeout\n", command); +} + +/** + * Check whether the pointed buffer are all 0xff (blank). + * + * @param buf data buffer for blank check + * @param len length of the buffer in byte + * @return + * 1 - blank + * 0 - non-blank + */ +static int blank_check(u8 *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (buf[i] != 0xFF) + return 0; + return 1; +} + +/** + * After a DMA transfer for read, we call this function to see whether there + * is any uncorrectable error on the pointed data buffer or oob buffer. + * + * @param reg nand_ctlr structure + * @param databuf data buffer + * @param a_len data buffer length + * @param oobbuf oob buffer + * @param b_len oob buffer length + * @return + * ECC_OK - no ECC error or correctable ECC error + * ECC_TAG_ERROR - uncorrectable tag ECC error + * ECC_DATA_ERROR - uncorrectable data ECC error + * ECC_DATA_ERROR + ECC_TAG_ERROR - uncorrectable data+tag ECC error + */ +static int check_ecc_error(struct nand_ctlr *reg, u8 *databuf, + int a_len, u8 *oobbuf, int b_len) +{ + int return_val = ECC_OK; + u32 reg_val; + + if (!(readl(®->isr) & ISR_IS_ECC_ERR)) + return ECC_OK; + + /* + * Area A is used for the data block (databuf). Area B is used for + * the spare block (oobbuf) + */ + reg_val = readl(®->dec_status); + if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) { + reg_val = readl(®->bch_dec_status_buf); + /* + * If uncorrectable error occurs on data area, then see whether + * they are all FF. If all are FF, it's a blank page. + * Not error. + */ + if ((reg_val & BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK) && + !blank_check(databuf, a_len)) + return_val |= ECC_DATA_ERROR; + } + + if ((reg_val & DEC_STATUS_B_ECC_FAIL) && oobbuf) { + reg_val = readl(®->bch_dec_status_buf); + /* + * If uncorrectable error occurs on tag area, then see whether + * they are all FF. If all are FF, it's a blank page. + * Not error. + */ + if ((reg_val & BCH_DEC_STATUS_FAIL_TAG_MASK) && + !blank_check(oobbuf, b_len)) + return_val |= ECC_TAG_ERROR; + } + + return return_val; +} + +/** + * Set GO bit to send command to device + * + * @param reg nand_ctlr structure + */ +static void start_command(struct nand_ctlr *reg) +{ + u32 reg_val; + + reg_val = readl(®->command); + reg_val |= CMD_GO; + writel(reg_val, ®->command); +} + +/** + * Clear command GO bit, DMA GO bit, and DMA completion status + * + * @param reg nand_ctlr structure + */ +static void stop_command(struct nand_ctlr *reg) +{ + /* Stop command */ + writel(0, ®->command); + + /* Stop DMA engine and clear DMA completion status */ + writel(DMA_MST_CTRL_GO_DISABLE + | DMA_MST_CTRL_IS_DMA_DONE, + ®->dma_mst_ctrl); +} + +/** + * Set up NAND bus width and page size + * + * @param info nand_info structure + * @param *reg_val address of reg_val + * @return 0 if ok, -1 on error + */ +static int set_bus_width_page_size(struct fdt_nand *config, + u32 *reg_val) +{ + if (config->width == 8) + *reg_val = CFG_BUS_WIDTH_8BIT; + else if (config->width == 16) + *reg_val = CFG_BUS_WIDTH_16BIT; + else { + debug("%s: Unsupported bus width %d\n", __func__, + config->width); + return -1; + } + + if (our_mtd->writesize == 512) + *reg_val |= CFG_PAGE_SIZE_512; + else if (our_mtd->writesize == 2048) + *reg_val |= CFG_PAGE_SIZE_2048; + else if (our_mtd->writesize == 4096) + *reg_val |= CFG_PAGE_SIZE_4096; + else { + debug("%s: Unsupported page size %d\n", __func__, + our_mtd->writesize); + return -1; + } + + return 0; +} + +/** + * Page read/write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + * @param page page number + * @param with_ecc 1 to enable ECC, 0 to disable ECC + * @param is_writing 0 for read, 1 for write + * @return 0 when successfully completed + * -EIO when command timeout + */ +static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page, int with_ecc, int is_writing) +{ + u32 reg_val; + int tag_size; + struct nand_oobfree *free = chip->ecc.layout->oobfree; + /* 4*128=512 (byte) is the value that our HW can support. */ + ALLOC_CACHE_ALIGN_BUFFER(u32, tag_buf, 128); + char *tag_ptr; + struct nand_drv *info; + struct fdt_nand *config; + + if ((uintptr_t)buf & 0x03) { + printf("buf %p has to be 4-byte aligned\n", buf); + return -EINVAL; + } + + info = (struct nand_drv *)chip->priv; + config = &info->config; + if (set_bus_width_page_size(config, ®_val)) + return -EINVAL; + + /* Need to be 4-byte aligned */ + tag_ptr = (char *)tag_buf; + + stop_command(info->reg); + + writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a); + writel(virt_to_phys(buf), &info->reg->data_block_ptr); + + if (with_ecc) { + writel(virt_to_phys(tag_ptr), &info->reg->tag_ptr); + if (is_writing) + memcpy(tag_ptr, chip->oob_poi + free->offset, + chip->ecc.layout->oobavail + + TAG_ECC_BYTES); + } else { + writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); + } + + /* Set ECC selection, configure ECC settings */ + if (with_ecc) { + tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES; + reg_val |= (CFG_SKIP_SPARE_SEL_4 + | CFG_SKIP_SPARE_ENABLE + | CFG_HW_ECC_CORRECTION_ENABLE + | CFG_ECC_EN_TAG_DISABLE + | CFG_HW_ECC_SEL_RS + | CFG_HW_ECC_ENABLE + | CFG_TVAL4 + | (tag_size - 1)); + + if (!is_writing) + tag_size += SKIPPED_SPARE_BYTES; + dma_prepare(tag_ptr, tag_size, is_writing); + } else { + tag_size = mtd->oobsize; + reg_val |= (CFG_SKIP_SPARE_DISABLE + | CFG_HW_ECC_CORRECTION_DISABLE + | CFG_ECC_EN_TAG_DISABLE + | CFG_HW_ECC_DISABLE + | (tag_size - 1)); + dma_prepare(chip->oob_poi, tag_size, is_writing); + } + writel(reg_val, &info->reg->config); + + dma_prepare(buf, 1 << chip->page_shift, is_writing); + + writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); + + writel(tag_size - 1, &info->reg->dma_cfg_b); + + nand_clear_interrupt_status(info->reg); + + reg_val = CMD_CLE | CMD_ALE + | CMD_SEC_CMD + | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) + | CMD_A_VALID + | CMD_B_VALID + | (CMD_TRANS_SIZE_PAGE << CMD_TRANS_SIZE_SHIFT) + | CMD_CE0; + if (!is_writing) + reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); + else + reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); + writel(reg_val, &info->reg->command); + + /* Setup DMA engine */ + reg_val = DMA_MST_CTRL_GO_ENABLE + | DMA_MST_CTRL_BURST_8WORDS + | DMA_MST_CTRL_EN_A_ENABLE + | DMA_MST_CTRL_EN_B_ENABLE; + + if (!is_writing) + reg_val |= DMA_MST_CTRL_DIR_READ; + else + reg_val |= DMA_MST_CTRL_DIR_WRITE; + + writel(reg_val, &info->reg->dma_mst_ctrl); + + start_command(info->reg); + + if (!nand_waitfor_cmd_completion(info->reg)) { + if (!is_writing) + printf("Read Page 0x%X timeout ", page); + else + printf("Write Page 0x%X timeout ", page); + if (with_ecc) + printf("with ECC"); + else + printf("without ECC"); + printf("\n"); + return -EIO; + } + + if (with_ecc && !is_writing) { + memcpy(chip->oob_poi, tag_ptr, + SKIPPED_SPARE_BYTES); + memcpy(chip->oob_poi + free->offset, + tag_ptr + SKIPPED_SPARE_BYTES, + chip->ecc.layout->oobavail); + reg_val = (u32)check_ecc_error(info->reg, (u8 *)buf, + 1 << chip->page_shift, + (u8 *)(tag_ptr + SKIPPED_SPARE_BYTES), + chip->ecc.layout->oobavail); + if (reg_val & ECC_TAG_ERROR) + printf("Read Page 0x%X tag ECC error\n", page); + if (reg_val & ECC_DATA_ERROR) + printf("Read Page 0x%X data ECC error\n", + page); + if (reg_val & (ECC_DATA_ERROR | ECC_TAG_ERROR)) + return -EIO; + } + return 0; +} + +/** + * Hardware ecc based page read function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf buffer to store read data + * @param page page number to read + * @return 0 when successfully completed + * -EIO when command timeout + */ +static int nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + return nand_rw_page(mtd, chip, buf, page, 1, 0); +} + +/** + * Hardware ecc based page write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + */ +static void nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + int page; + struct nand_drv *info; + + info = (struct nand_drv *)chip->priv; + + page = (readl(&info->reg->addr_reg1) >> 16) | + (readl(&info->reg->addr_reg2) << 16); + + nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); +} + + +/** + * Read raw page data without ecc + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf buffer to store read data + * @param page page number to read + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + return nand_rw_page(mtd, chip, buf, page, 0, 0); +} + +/** + * Raw page write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param buf data buffer + */ +static void nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + int page; + struct nand_drv *info; + + info = (struct nand_drv *)chip->priv; + page = (readl(&info->reg->addr_reg1) >> 16) | + (readl(&info->reg->addr_reg2) << 16); + + nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); +} + +/** + * OOB data read/write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to read + * @param with_ecc 1 to enable ECC, 0 to disable ECC + * @param is_writing 0 for read, 1 for write + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int with_ecc, int is_writing) +{ + u32 reg_val; + int tag_size; + struct nand_oobfree *free = chip->ecc.layout->oobfree; + struct nand_drv *info; + + if (((int)chip->oob_poi) & 0x03) + return -EINVAL; + info = (struct nand_drv *)chip->priv; + if (set_bus_width_page_size(&info->config, ®_val)) + return -EINVAL; + + stop_command(info->reg); + + writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); + + /* Set ECC selection */ + tag_size = mtd->oobsize; + if (with_ecc) + reg_val |= CFG_ECC_EN_TAG_ENABLE; + else + reg_val |= (CFG_ECC_EN_TAG_DISABLE); + + reg_val |= ((tag_size - 1) | + CFG_SKIP_SPARE_DISABLE | + CFG_HW_ECC_CORRECTION_DISABLE | + CFG_HW_ECC_DISABLE); + writel(reg_val, &info->reg->config); + + dma_prepare(chip->oob_poi, tag_size, is_writing); + + writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); + + if (is_writing && with_ecc) + tag_size -= TAG_ECC_BYTES; + + writel(tag_size - 1, &info->reg->dma_cfg_b); + + nand_clear_interrupt_status(info->reg); + + reg_val = CMD_CLE | CMD_ALE + | CMD_SEC_CMD + | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) + | CMD_B_VALID + | CMD_CE0; + if (!is_writing) + reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); + else + reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); + writel(reg_val, &info->reg->command); + + /* Setup DMA engine */ + reg_val = DMA_MST_CTRL_GO_ENABLE + | DMA_MST_CTRL_BURST_8WORDS + | DMA_MST_CTRL_EN_B_ENABLE; + if (!is_writing) + reg_val |= DMA_MST_CTRL_DIR_READ; + else + reg_val |= DMA_MST_CTRL_DIR_WRITE; + + writel(reg_val, &info->reg->dma_mst_ctrl); + + start_command(info->reg); + + if (!nand_waitfor_cmd_completion(info->reg)) { + if (!is_writing) + printf("Read OOB of Page 0x%X timeout\n", page); + else + printf("Write OOB of Page 0x%X timeout\n", page); + return -EIO; + } + + if (with_ecc && !is_writing) { + reg_val = (u32)check_ecc_error(info->reg, 0, 0, + (u8 *)(chip->oob_poi + free->offset), + chip->ecc.layout->oobavail); + if (reg_val & ECC_TAG_ERROR) + printf("Read OOB of Page 0x%X tag ECC error\n", page); + } + return 0; +} + +/** + * OOB data read function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to read + * @param sndcmd flag whether to issue read command or not + * @return 1 - issue read command next time + * 0 - not to issue + */ +static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + nand_rw_oob(mtd, chip, page, 0, 0); + return sndcmd; +} + +/** + * OOB data write function + * + * @param mtd mtd info structure + * @param chip nand chip info structure + * @param page page number to write + * @return 0 when successfully completed + * -EINVAL when chip->oob_poi is not double-word aligned + * -EIO when command timeout + */ +static int nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + + return nand_rw_oob(mtd, chip, page, 0, 1); +} + +/** + * Set up NAND memory timings according to the provided parameters + * + * @param timing Timing parameters + * @param reg NAND controller register address + */ +static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT], + struct nand_ctlr *reg) +{ + u32 reg_val, clk_rate, clk_period, time_val; + + clk_rate = (u32)clock_get_periph_rate(PERIPH_ID_NDFLASH, + CLOCK_ID_PERIPH) / 1000000; + clk_period = 1000 / clk_rate; + reg_val = ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << + TIMING_TRP_RESP_CNT_SHIFT) & TIMING_TRP_RESP_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWB] / clk_period) << + TIMING_TWB_CNT_SHIFT) & TIMING_TWB_CNT_MASK; + time_val = timing[FDT_NAND_MAX_TCR_TAR_TRR] / clk_period; + if (time_val > 2) + reg_val |= ((time_val - 2) << TIMING_TCR_TAR_TRR_CNT_SHIFT) & + TIMING_TCR_TAR_TRR_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWHR] / clk_period) << + TIMING_TWHR_CNT_SHIFT) & TIMING_TWHR_CNT_MASK; + time_val = timing[FDT_NAND_MAX_TCS_TCH_TALS_TALH] / clk_period; + if (time_val > 1) + reg_val |= ((time_val - 1) << TIMING_TCS_CNT_SHIFT) & + TIMING_TCS_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWH] / clk_period) << + TIMING_TWH_CNT_SHIFT) & TIMING_TWH_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TWP] / clk_period) << + TIMING_TWP_CNT_SHIFT) & TIMING_TWP_CNT_MASK; + reg_val |= ((timing[FDT_NAND_TRH] / clk_period) << + TIMING_TRH_CNT_SHIFT) & TIMING_TRH_CNT_MASK; + reg_val |= ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << + TIMING_TRP_CNT_SHIFT) & TIMING_TRP_CNT_MASK; + writel(reg_val, ®->timing); + + reg_val = 0; + time_val = timing[FDT_NAND_TADL] / clk_period; + if (time_val > 2) + reg_val = (time_val - 2) & TIMING2_TADL_CNT_MASK; + writel(reg_val, ®->timing2); +} + +/** + * Decode NAND parameters from the device tree + * + * @param blob Device tree blob + * @param node Node containing "nand-flash" compatble node + * @return 0 if ok, -ve on error (FDT_ERR_...) + */ +static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config) +{ + int err; + + config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg"); + config->enabled = fdtdec_get_is_enabled(blob, node); + config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8); + err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios", + &config->wp_gpio); + if (err) + return err; + err = fdtdec_get_int_array(blob, node, "nvidia,timing", + config->timing, FDT_NAND_TIMING_COUNT); + if (err < 0) + return err; + + /* Now look up the controller and decode that */ + node = fdt_next_node(blob, node, NULL); + if (node < 0) + return node; + + return 0; +} + +/** + * Board-specific NAND initialization + * + * @param nand nand chip info structure + * @return 0, after initialized, -1 on error + */ +int tegra_nand_init(struct nand_chip *nand, int devnum) +{ + struct nand_drv *info = &nand_ctrl; + struct fdt_nand *config = &info->config; + int node, ret; + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_NVIDIA_TEGRA20_NAND); + if (node < 0) + return -1; + if (fdt_decode_nand(gd->fdt_blob, node, config)) { + printf("Could not decode nand-flash in device tree\n"); + return -1; + } + if (!config->enabled) + return -1; + info->reg = config->reg; + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.layout = &eccoob; + + nand->options = LP_OPTIONS; + nand->cmdfunc = nand_command; + nand->read_byte = read_byte; + nand->ecc.read_page = nand_read_page_hwecc; + nand->ecc.write_page = nand_write_page_hwecc; + nand->ecc.read_page_raw = nand_read_page_raw; + nand->ecc.write_page_raw = nand_write_page_raw; + nand->ecc.read_oob = nand_read_oob; + nand->ecc.write_oob = nand_write_oob; + nand->select_chip = nand_select_chip; + nand->dev_ready = nand_dev_ready; + nand->priv = &nand_ctrl; + + /* Adjust controller clock rate */ + clock_start_periph_pll(PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH, 52000000); + + /* Adjust timing for NAND device */ + setup_timing(config->timing, info->reg); + + funcmux_select(PERIPH_ID_NDFLASH, FUNCMUX_DEFAULT); + fdtdec_setup_gpio(&config->wp_gpio); + gpio_direction_output(config->wp_gpio.gpio, 1); + + our_mtd = &nand_info[devnum]; + our_mtd->priv = nand; + ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); + if (ret) + return ret; + + nand->ecc.size = our_mtd->writesize; + nand->ecc.bytes = our_mtd->oobsize; + + ret = nand_scan_tail(our_mtd); + if (ret) + return ret; + + ret = nand_register(devnum); + if (ret) + return ret; + + return 0; +} + +void board_nand_init(void) +{ + struct nand_chip *nand = &nand_chip[0]; + + if (tegra_nand_init(nand, 0)) + puts("Tegra NAND init failed\n"); +} diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/tegra_nand.h new file mode 100644 index 0000000..7e74be7 --- /dev/null +++ b/drivers/mtd/nand/tegra_nand.h @@ -0,0 +1,257 @@ +/* + * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +/* register offset */ +#define COMMAND_0 0x00 +#define CMD_GO (1 << 31) +#define CMD_CLE (1 << 30) +#define CMD_ALE (1 << 29) +#define CMD_PIO (1 << 28) +#define CMD_TX (1 << 27) +#define CMD_RX (1 << 26) +#define CMD_SEC_CMD (1 << 25) +#define CMD_AFT_DAT_MASK (1 << 24) +#define CMD_AFT_DAT_DISABLE 0 +#define CMD_AFT_DAT_ENABLE (1 << 24) +#define CMD_TRANS_SIZE_SHIFT 20 +#define CMD_TRANS_SIZE_PAGE 8 +#define CMD_A_VALID (1 << 19) +#define CMD_B_VALID (1 << 18) +#define CMD_RD_STATUS_CHK (1 << 17) +#define CMD_R_BSY_CHK (1 << 16) +#define CMD_CE7 (1 << 15) +#define CMD_CE6 (1 << 14) +#define CMD_CE5 (1 << 13) +#define CMD_CE4 (1 << 12) +#define CMD_CE3 (1 << 11) +#define CMD_CE2 (1 << 10) +#define CMD_CE1 (1 << 9) +#define CMD_CE0 (1 << 8) +#define CMD_CLE_BYTE_SIZE_SHIFT 4 +enum { + CMD_CLE_BYTES1 = 0, + CMD_CLE_BYTES2, + CMD_CLE_BYTES3, + CMD_CLE_BYTES4, +}; +#define CMD_ALE_BYTE_SIZE_SHIFT 0 +enum { + CMD_ALE_BYTES1 = 0, + CMD_ALE_BYTES2, + CMD_ALE_BYTES3, + CMD_ALE_BYTES4, + CMD_ALE_BYTES5, + CMD_ALE_BYTES6, + CMD_ALE_BYTES7, + CMD_ALE_BYTES8 +}; + +#define STATUS_0 0x04 +#define STATUS_RBSY0 (1 << 8) + +#define ISR_0 0x08 +#define ISR_IS_CMD_DONE (1 << 5) +#define ISR_IS_ECC_ERR (1 << 4) + +#define IER_0 0x0C + +#define CFG_0 0x10 +#define CFG_HW_ECC_MASK (1 << 31) +#define CFG_HW_ECC_DISABLE 0 +#define CFG_HW_ECC_ENABLE (1 << 31) +#define CFG_HW_ECC_SEL_MASK (1 << 30) +#define CFG_HW_ECC_SEL_HAMMING 0 +#define CFG_HW_ECC_SEL_RS (1 << 30) +#define CFG_HW_ECC_CORRECTION_MASK (1 << 29) +#define CFG_HW_ECC_CORRECTION_DISABLE 0 +#define CFG_HW_ECC_CORRECTION_ENABLE (1 << 29) +#define CFG_PIPELINE_EN_MASK (1 << 28) +#define CFG_PIPELINE_EN_DISABLE 0 +#define CFG_PIPELINE_EN_ENABLE (1 << 28) +#define CFG_ECC_EN_TAG_MASK (1 << 27) +#define CFG_ECC_EN_TAG_DISABLE 0 +#define CFG_ECC_EN_TAG_ENABLE (1 << 27) +#define CFG_TVALUE_MASK (3 << 24) +enum { + CFG_TVAL4 = 0 << 24, + CFG_TVAL6 = 1 << 24, + CFG_TVAL8 = 2 << 24 +}; +#define CFG_SKIP_SPARE_MASK (1 << 23) +#define CFG_SKIP_SPARE_DISABLE 0 +#define CFG_SKIP_SPARE_ENABLE (1 << 23) +#define CFG_COM_BSY_MASK (1 << 22) +#define CFG_COM_BSY_DISABLE 0 +#define CFG_COM_BSY_ENABLE (1 << 22) +#define CFG_BUS_WIDTH_MASK (1 << 21) +#define CFG_BUS_WIDTH_8BIT 0 +#define CFG_BUS_WIDTH_16BIT (1 << 21) +#define CFG_LPDDR1_MODE_MASK (1 << 20) +#define CFG_LPDDR1_MODE_DISABLE 0 +#define CFG_LPDDR1_MODE_ENABLE (1 << 20) +#define CFG_EDO_MODE_MASK (1 << 19) +#define CFG_EDO_MODE_DISABLE 0 +#define CFG_EDO_MODE_ENABLE (1 << 19) +#define CFG_PAGE_SIZE_SEL_MASK (7 << 16) +enum { + CFG_PAGE_SIZE_256 = 0 << 16, + CFG_PAGE_SIZE_512 = 1 << 16, + CFG_PAGE_SIZE_1024 = 2 << 16, + CFG_PAGE_SIZE_2048 = 3 << 16, + CFG_PAGE_SIZE_4096 = 4 << 16 +}; +#define CFG_SKIP_SPARE_SEL_MASK (3 << 14) +enum { + CFG_SKIP_SPARE_SEL_4 = 0 << 14, + CFG_SKIP_SPARE_SEL_8 = 1 << 14, + CFG_SKIP_SPARE_SEL_12 = 2 << 14, + CFG_SKIP_SPARE_SEL_16 = 3 << 14 +}; +#define CFG_TAG_BYTE_SIZE_MASK 0x1FF + +#define TIMING_0 0x14 +#define TIMING_TRP_RESP_CNT_SHIFT 28 +#define TIMING_TRP_RESP_CNT_MASK (0xf << TIMING_TRP_RESP_CNT_SHIFT) +#define TIMING_TWB_CNT_SHIFT 24 +#define TIMING_TWB_CNT_MASK (0xf << TIMING_TWB_CNT_SHIFT) +#define TIMING_TCR_TAR_TRR_CNT_SHIFT 20 +#define TIMING_TCR_TAR_TRR_CNT_MASK (0xf << TIMING_TCR_TAR_TRR_CNT_SHIFT) +#define TIMING_TWHR_CNT_SHIFT 16 +#define TIMING_TWHR_CNT_MASK (0xf << TIMING_TWHR_CNT_SHIFT) +#define TIMING_TCS_CNT_SHIFT 14 +#define TIMING_TCS_CNT_MASK (3 << TIMING_TCS_CNT_SHIFT) +#define TIMING_TWH_CNT_SHIFT 12 +#define TIMING_TWH_CNT_MASK (3 << TIMING_TWH_CNT_SHIFT) +#define TIMING_TWP_CNT_SHIFT 8 +#define TIMING_TWP_CNT_MASK (0xf << TIMING_TWP_CNT_SHIFT) +#define TIMING_TRH_CNT_SHIFT 4 +#define TIMING_TRH_CNT_MASK (3 << TIMING_TRH_CNT_SHIFT) +#define TIMING_TRP_CNT_SHIFT 0 +#define TIMING_TRP_CNT_MASK (0xf << TIMING_TRP_CNT_SHIFT) + +#define RESP_0 0x18 + +#define TIMING2_0 0x1C +#define TIMING2_TADL_CNT_SHIFT 0 +#define TIMING2_TADL_CNT_MASK (0xf << TIMING2_TADL_CNT_SHIFT) + +#define CMD_REG1_0 0x20 +#define CMD_REG2_0 0x24 +#define ADDR_REG1_0 0x28 +#define ADDR_REG2_0 0x2C + +#define DMA_MST_CTRL_0 0x30 +#define DMA_MST_CTRL_GO_MASK (1 << 31) +#define DMA_MST_CTRL_GO_DISABLE 0 +#define DMA_MST_CTRL_GO_ENABLE (1 << 31) +#define DMA_MST_CTRL_DIR_MASK (1 << 30) +#define DMA_MST_CTRL_DIR_READ 0 +#define DMA_MST_CTRL_DIR_WRITE (1 << 30) +#define DMA_MST_CTRL_PERF_EN_MASK (1 << 29) +#define DMA_MST_CTRL_PERF_EN_DISABLE 0 +#define DMA_MST_CTRL_PERF_EN_ENABLE (1 << 29) +#define DMA_MST_CTRL_REUSE_BUFFER_MASK (1 << 27) +#define DMA_MST_CTRL_REUSE_BUFFER_DISABLE 0 +#define DMA_MST_CTRL_REUSE_BUFFER_ENABLE (1 << 27) +#define DMA_MST_CTRL_BURST_SIZE_SHIFT 24 +#define DMA_MST_CTRL_BURST_SIZE_MASK (7 << DMA_MST_CTRL_BURST_SIZE_SHIFT) +enum { + DMA_MST_CTRL_BURST_1WORDS = 2 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_4WORDS = 3 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_8WORDS = 4 << DMA_MST_CTRL_BURST_SIZE_SHIFT, + DMA_MST_CTRL_BURST_16WORDS = 5 << DMA_MST_CTRL_BURST_SIZE_SHIFT +}; +#define DMA_MST_CTRL_IS_DMA_DONE (1 << 20) +#define DMA_MST_CTRL_EN_A_MASK (1 << 2) +#define DMA_MST_CTRL_EN_A_DISABLE 0 +#define DMA_MST_CTRL_EN_A_ENABLE (1 << 2) +#define DMA_MST_CTRL_EN_B_MASK (1 << 1) +#define DMA_MST_CTRL_EN_B_DISABLE 0 +#define DMA_MST_CTRL_EN_B_ENABLE (1 << 1) + +#define DMA_CFG_A_0 0x34 +#define DMA_CFG_B_0 0x38 +#define FIFO_CTRL_0 0x3C +#define DATA_BLOCK_PTR_0 0x40 +#define TAG_PTR_0 0x44 +#define ECC_PTR_0 0x48 + +#define DEC_STATUS_0 0x4C +#define DEC_STATUS_A_ECC_FAIL (1 << 1) +#define DEC_STATUS_B_ECC_FAIL (1 << 0) + +#define BCH_CONFIG_0 0xCC +#define BCH_CONFIG_BCH_TVALUE_SHIFT 4 +#define BCH_CONFIG_BCH_TVALUE_MASK (3 << BCH_CONFIG_BCH_TVALUE_SHIFT) +enum { + BCH_CONFIG_BCH_TVAL4 = 0 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL8 = 1 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL14 = 2 << BCH_CONFIG_BCH_TVALUE_SHIFT, + BCH_CONFIG_BCH_TVAL16 = 3 << BCH_CONFIG_BCH_TVALUE_SHIFT +}; +#define BCH_CONFIG_BCH_ECC_MASK (1 << 0) +#define BCH_CONFIG_BCH_ECC_DISABLE 0 +#define BCH_CONFIG_BCH_ECC_ENABLE (1 << 0) + +#define BCH_DEC_RESULT_0 0xD0 +#define BCH_DEC_RESULT_CORRFAIL_ERR_MASK (1 << 8) +#define BCH_DEC_RESULT_PAGE_COUNT_MASK 0xFF + +#define BCH_DEC_STATUS_BUF_0 0xD4 +#define BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK 0xFF000000 +#define BCH_DEC_STATUS_CORR_SEC_FLAG_MASK 0x00FF0000 +#define BCH_DEC_STATUS_FAIL_TAG_MASK (1 << 14) +#define BCH_DEC_STATUS_CORR_TAG_MASK (1 << 13) +#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8) +#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF + +#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR) + +struct nand_ctlr { + u32 command; /* offset 00h */ + u32 status; /* offset 04h */ + u32 isr; /* offset 08h */ + u32 ier; /* offset 0Ch */ + u32 config; /* offset 10h */ + u32 timing; /* offset 14h */ + u32 resp; /* offset 18h */ + u32 timing2; /* offset 1Ch */ + u32 cmd_reg1; /* offset 20h */ + u32 cmd_reg2; /* offset 24h */ + u32 addr_reg1; /* offset 28h */ + u32 addr_reg2; /* offset 2Ch */ + u32 dma_mst_ctrl; /* offset 30h */ + u32 dma_cfg_a; /* offset 34h */ + u32 dma_cfg_b; /* offset 38h */ + u32 fifo_ctrl; /* offset 3Ch */ + u32 data_block_ptr; /* offset 40h */ + u32 tag_ptr; /* offset 44h */ + u32 resv1; /* offset 48h */ + u32 dec_status; /* offset 4Ch */ + u32 hwstatus_cmd; /* offset 50h */ + u32 hwstatus_mask; /* offset 54h */ + u32 resv2[29]; + u32 bch_config; /* offset CCh */ + u32 bch_dec_result; /* offset D0h */ + u32 bch_dec_status_buf; + /* offset D4h */ +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index a8f783f..474a4b9 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -63,6 +63,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */ COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */ COMPAT_NVIDIA_TEGRA20_KBC, /* Tegra20 Keyboard */ + COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index cc09e06..32d36c6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -43,6 +43,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"), + COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

On 07/30/2012 01:53 AM, Simon Glass wrote:
From: Jim Lin jilin@nvidia.com
A device tree is used to configure the NAND, including memory timings and block/pages sizes.
If this node is not present or is disabled, then NAND will not be initialized.
Signed-off-by: Jim Lin jilin@nvidia.com Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Scott Wood scottwood@freescale.com
-Scott

This enables NAND support for the Seaboard.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v4: - Move to using CONFIG_SYS_NAND_SELF_INIT - Rename CONFIG_TEGRA2_NAND to CONFIG_TEGRA_NAND
include/configs/seaboard.h | 9 +++++++++ include/configs/tegra20-common.h | 2 ++ 2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index afc4a85..479af1a 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -105,4 +105,13 @@
#include "tegra20-common-post.h"
+/* NAND support */ +#define CONFIG_CMD_NAND +#define CONFIG_TEGRA_NAND + +/* Max number of NAND devices */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 + +/* Somewhat oddly, the NAND base address must be a config option */ +#define CONFIG_SYS_NAND_BASE TEGRA20_NAND_BASE #endif /* __CONFIG_H */ diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index 1c0d235..c9e8b6b 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -207,4 +207,6 @@ #define CONFIG_SPL_GPIO_SUPPORT #define CONFIG_SPL_LDSCRIPT "$(CPUDIR)/tegra20/u-boot-spl.lds"
+#define CONFIG_SYS_NAND_SELF_INIT + #endif /* __TEGRA20_COMMON_H */

On 07/30/2012 12:53 AM, Simon Glass wrote:
This enables NAND support for the Seaboard.
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
#include "tegra20-common-post.h"
+/* NAND support */ +#define CONFIG_CMD_NAND +#define CONFIG_TEGRA_NAND
+/* Max number of NAND devices */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1
+/* Somewhat oddly, the NAND base address must be a config option */ +#define CONFIG_SYS_NAND_BASE TEGRA20_NAND_BASE
Simon, I just noticed that all these config options are added after the include of tegra20-common-post.h. That file should be included at the very end in case it needs to do something different based on the board-specific configuration. I don't suppose you could move those lines before the include?

Am Donnerstag, den 01.11.2012, 15:57 -0600 schrieb Stephen Warren:
On 07/30/2012 12:53 AM, Simon Glass wrote:
This enables NAND support for the Seaboard.
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
#include "tegra20-common-post.h"
+/* NAND support */ +#define CONFIG_CMD_NAND +#define CONFIG_TEGRA_NAND
+/* Max number of NAND devices */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1
+/* Somewhat oddly, the NAND base address must be a config option */ +#define CONFIG_SYS_NAND_BASE TEGRA20_NAND_BASE
Simon, I just noticed that all these config options are added after the include of tegra20-common-post.h. That file should be included at the very end in case it needs to do something different based on the board-specific configuration. I don't suppose you could move those lines before the include?
Also CONFIG_SYS_NAND_BASE is not really used in the current Tegra nand controller codebase, in fact you can get away with not defining it. We should probably use this define in our driver code, but then we should add this define to some common Tegra place and not to individual board files.
Regards, Lucas

Hi,
On Thu, Nov 1, 2012 at 4:13 PM, Lucas Stach dev@lynxeye.de wrote:
Am Donnerstag, den 01.11.2012, 15:57 -0600 schrieb Stephen Warren:
On 07/30/2012 12:53 AM, Simon Glass wrote:
This enables NAND support for the Seaboard.
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
#include "tegra20-common-post.h"
+/* NAND support */ +#define CONFIG_CMD_NAND +#define CONFIG_TEGRA_NAND
+/* Max number of NAND devices */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1
+/* Somewhat oddly, the NAND base address must be a config option */ +#define CONFIG_SYS_NAND_BASE TEGRA20_NAND_BASE
Simon, I just noticed that all these config options are added after the include of tegra20-common-post.h. That file should be included at the very end in case it needs to do something different based on the board-specific configuration. I don't suppose you could move those lines before the include?
Also CONFIG_SYS_NAND_BASE is not really used in the current Tegra nand controller codebase, in fact you can get away with not defining it. We should probably use this define in our driver code, but then we should add this define to some common Tegra place and not to individual board files.
OK I will look at these next week.
Regards, Simon
Regards, Lucas

Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Applied to u-boot-tegra/master AOK. ./MAKEALL -s tegra20 AOK. Able to erase/read/write NAND on my Seaboard AOK. Tested-by: Tom Warren twarren@nvidia.com
Thanks, I'll upload a new u-boot-tegra/master and /next with this change later once I see some ACKs.
Tom

On 07/30/2012 12:53 AM, Simon Glass wrote:
This series adds NAND flash support to Tegra and enables it on Seaboard.
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Along with a couple of patches that I'll post momentarily, this works for me on Harmony, so:
Tested-by: Stephen Warren swarren@wwwdotorg.org

Stephen,
-----Original Message----- From: Stephen Warren [mailto:swarren@wwwdotorg.org] Sent: Monday, July 30, 2012 10:34 AM To: Simon Glass Cc: U-Boot Mailing List; Tom Warren; Scott Wood Subject: Re: [PATCH v4 0/6] tegra: Add NAND flash support
On 07/30/2012 12:53 AM, Simon Glass wrote:
This series adds NAND flash support to Tegra and enables it on Seaboard.
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable
speed.
Along with a couple of patches that I'll post momentarily, this works for me on Harmony, so:
Tested-by: Stephen Warren swarren@wwwdotorg.org
Your two patches (Harmony NAND and env_nand) have been applied to u-boot-tegra/next (along w/Simon's NAND patchset, obviously), and pushed to denx.de. I'll apply them to u-boot-tegra/master when they're ACK'd along w/Simon's NAND work.
Thanks,
Tom

On Sun, Jul 29, 2012 at 11:53:24PM -0700, Simon Glass wrote:
This series adds NAND flash support to Tegra and enables it on Seaboard.
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
There is an issue with the nand dump command, but it was easy to fix. I'll send a patch along with support on TEC which I've tested this on successfully:
Tested-by: Thierry Reding thierry.reding@avionic-design.de

Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
Tom
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Changes in v2:
- Add new patch to align default buffers in nand_base
- Added comment about the behaviour of the 'resp' register
- Call set_bus_width_page_size() at init to report errors earlier
- Change set_bus_width_page_size() to return an error when needed
- Change timing structure member to u32 to match device tree
- Check for supported bus width in board_nand_init()
- Fix tegra nand header file to remove BIT defines
- Implement a dummy nand_select_chip() instead of nand_hwcontro()
- Make nand_command() display an error on an unknown command
- Minor code tidy-ups in driver for style
- Move cache logic into a separate dma_prepare() function
- Remove CMD_TRANS_SIZE_BYTESx enum
- Remove space after casts
- Remove use of 'register' variables
- Rename struct nand_info to struct nand_drv to avoid nand_info_t confusion
- Support 4096 byte page devices, drop 1024 and 2048
- Tidy up nand_waitfor_cmd_completion() logic
- Update NAND binding to add "nvidia," prefix
- Use s32 for device tree integer values
Changes in v3:
- Add reg property for unit address (should be used for chip select)
- Change note in fdt binding about the need for a hardware-specific binding
- Fix up typos in fdt binding, and rename the file
- Update fdt binding to make everything Nvidia-specific
Changes in v4:
- Align buffer length to cache line size in dma_prepare()
- Fix "Write Page 0x0 timeout with ECC" error on 4.4.1
- Fix the issue that read_byte can read at most 4 times
- Get some information from Read ID data instead of from device tree
- In nand_command, set NAND_CMD_RNDOUT as unsupported command
- Modify eccoob layout
- Move to using CONFIG_SYS_NAND_SELF_INIT
- Remove "DEFAULT" from comment because that function is not default
- Remove fdt bindings related to page structure
- Remove local read_buf and write_buf functions
- Remove some fields in fdt_nand structure
- Rename CONFIG_TEGRA2_NAND to CONFIG_TEGRA_NAND
- Rename variables my_* as our_*
- Use virt_to_phys() when filling address register
Jim Lin (1): tegra: nand: Add Tegra NAND driver
Simon Glass (5): nand: Try to align the default buffers tegra: Add NAND support to funcmux tegra: fdt: Add NAND controller binding and definitions tegra: fdt: Add NAND definitions to fdt tegra: Enable NAND on Seaboard
arch/arm/cpu/tegra20-common/funcmux.c | 7 + arch/arm/dts/tegra20.dtsi | 7 + arch/arm/include/asm/arch-tegra20/funcmux.h | 3 + arch/arm/include/asm/arch-tegra20/tegra20.h | 1 + board/nvidia/dts/tegra20-seaboard.dts | 10 + .../nand/nvidia,tegra20-nand.txt | 53 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/nand_base.c | 3 +- drivers/mtd/nand/tegra_nand.c | 1026 ++++++++++++++++++++ drivers/mtd/nand/tegra_nand.h | 257 +++++ include/configs/seaboard.h | 9 + include/configs/tegra20-common.h | 2 + include/fdtdec.h | 1 + include/linux/mtd/nand.h | 7 +- lib/fdtdec.c | 1 + 15 files changed, 1384 insertions(+), 4 deletions(-) create mode 100644 doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt create mode 100644 drivers/mtd/nand/tegra_nand.c create mode 100644 drivers/mtd/nand/tegra_nand.h
-- 1.7.7.3

Hi Tom,
On Fri, Sep 7, 2012 at 2:31 PM, Tom Warren TWarren@nvidia.com wrote:
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
OK thanks.
With LCD I had a few comments, but the main question is with the bindings. Can we get a resolution there?
Regards, Simon
Tom
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Changes in v2:
- Add new patch to align default buffers in nand_base
- Added comment about the behaviour of the 'resp' register
- Call set_bus_width_page_size() at init to report errors earlier
- Change set_bus_width_page_size() to return an error when needed
- Change timing structure member to u32 to match device tree
- Check for supported bus width in board_nand_init()
- Fix tegra nand header file to remove BIT defines
- Implement a dummy nand_select_chip() instead of nand_hwcontro()
- Make nand_command() display an error on an unknown command
- Minor code tidy-ups in driver for style
- Move cache logic into a separate dma_prepare() function
- Remove CMD_TRANS_SIZE_BYTESx enum
- Remove space after casts
- Remove use of 'register' variables
- Rename struct nand_info to struct nand_drv to avoid nand_info_t confusion
- Support 4096 byte page devices, drop 1024 and 2048
- Tidy up nand_waitfor_cmd_completion() logic
- Update NAND binding to add "nvidia," prefix
- Use s32 for device tree integer values
Changes in v3:
- Add reg property for unit address (should be used for chip select)
- Change note in fdt binding about the need for a hardware-specific binding
- Fix up typos in fdt binding, and rename the file
- Update fdt binding to make everything Nvidia-specific
Changes in v4:
- Align buffer length to cache line size in dma_prepare()
- Fix "Write Page 0x0 timeout with ECC" error on 4.4.1
- Fix the issue that read_byte can read at most 4 times
- Get some information from Read ID data instead of from device tree
- In nand_command, set NAND_CMD_RNDOUT as unsupported command
- Modify eccoob layout
- Move to using CONFIG_SYS_NAND_SELF_INIT
- Remove "DEFAULT" from comment because that function is not default
- Remove fdt bindings related to page structure
- Remove local read_buf and write_buf functions
- Remove some fields in fdt_nand structure
- Rename CONFIG_TEGRA2_NAND to CONFIG_TEGRA_NAND
- Rename variables my_* as our_*
- Use virt_to_phys() when filling address register
Jim Lin (1): tegra: nand: Add Tegra NAND driver
Simon Glass (5): nand: Try to align the default buffers tegra: Add NAND support to funcmux tegra: fdt: Add NAND controller binding and definitions tegra: fdt: Add NAND definitions to fdt tegra: Enable NAND on Seaboard
arch/arm/cpu/tegra20-common/funcmux.c | 7 + arch/arm/dts/tegra20.dtsi | 7 + arch/arm/include/asm/arch-tegra20/funcmux.h | 3 + arch/arm/include/asm/arch-tegra20/tegra20.h | 1 + board/nvidia/dts/tegra20-seaboard.dts | 10 + .../nand/nvidia,tegra20-nand.txt | 53 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/nand_base.c | 3 +- drivers/mtd/nand/tegra_nand.c | 1026 ++++++++++++++++++++ drivers/mtd/nand/tegra_nand.h | 257 +++++ include/configs/seaboard.h | 9 + include/configs/tegra20-common.h | 2 + include/fdtdec.h | 1 + include/linux/mtd/nand.h | 7 +- lib/fdtdec.c | 1 + 15 files changed, 1384 insertions(+), 4 deletions(-) create mode 100644 doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt create mode 100644 drivers/mtd/nand/tegra_nand.c create mode 100644 drivers/mtd/nand/tegra_nand.h
-- 1.7.7.3
-- nvpublic

Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Friday, September 07, 2012 2:33 PM To: Tom Warren Cc: U-Boot Mailing List; Stephen Warren; Scott Wood; Marek Vasut Subject: Re: [PATCH v4 0/6] tegra: Add NAND flash support
Hi Tom,
On Fri, Sep 7, 2012 at 2:31 PM, Tom Warren TWarren@nvidia.com wrote:
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and
apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
OK thanks.
With LCD I had a few comments, but the main question is with the bindings. Can we get a resolution there?
Sorry, missed this question in the flurry of Tegra30 patches I've been working on.
What exactly do you need? Can we start a discussion offline w/Stephen & whomever else you need to get this resolved and moving forward again? It's the only thing left hanging for Tegra20.
Note that you'll want to recast(e?) your patches after my recent re-org of the Tegra20 code into 'tegra-common' subdirs to get ready for Tegra30 patches.
Thanks,
Tom
Regards, Simon
<snip>

On 09/21/2012 03:44 PM, Tom Warren wrote:
Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Friday, September 07, 2012 2:33 PM To: Tom Warren Cc: U-Boot Mailing List; Stephen Warren; Scott Wood; Marek Vasut Subject: Re: [PATCH v4 0/6] tegra: Add NAND flash support
Hi Tom,
On Fri, Sep 7, 2012 at 2:31 PM, Tom Warren TWarren@nvidia.com wrote:
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and
apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
OK thanks.
With LCD I had a few comments, but the main question is with the bindings. Can we get a resolution there?
Sorry, missed this question in the flurry of Tegra30 patches I've been working on.
What exactly do you need? Can we start a discussion offline w/Stephen & whomever else you need to get this resolved and moving forward again? It's the only thing left hanging for Tegra20.
The issue is making sure that the kernel and U-Boot use the exact same DT binding.
The main people to work with here are:
Thierry Reding (Avionic Design) and Mark Zhang (NVIDIA) who're working on the tegradrm driver for the Linux kernel.
I believe Thierry is close to publishing an updated version of tegradrm which would presumably be a good base.
You probably also want to look at:
http://lists.freedesktop.org/archives/dri-devel/2012-July/024875.html
... although I think that's implicitly included in the tegradrm stuff.

Hi Stephen,
On Fri, Sep 21, 2012 at 2:57 PM, Stephen Warren swarren@wwwdotorg.org wrote:
On 09/21/2012 03:44 PM, Tom Warren wrote:
Simon,
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Friday, September 07, 2012 2:33 PM To: Tom Warren Cc: U-Boot Mailing List; Stephen Warren; Scott Wood; Marek Vasut Subject: Re: [PATCH v4 0/6] tegra: Add NAND flash support
Hi Tom,
On Fri, Sep 7, 2012 at 2:31 PM, Tom Warren TWarren@nvidia.com wrote:
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and
apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
OK thanks.
With LCD I had a few comments, but the main question is with the bindings. Can we get a resolution there?
Sorry, missed this question in the flurry of Tegra30 patches I've been working on.
What exactly do you need? Can we start a discussion offline w/Stephen & whomever else you need to get this resolved and moving forward again? It's the only thing left hanging for Tegra20.
The issue is making sure that the kernel and U-Boot use the exact same DT binding.
The main people to work with here are:
Thierry Reding (Avionic Design) and Mark Zhang (NVIDIA) who're working on the tegradrm driver for the Linux kernel.
I believe Thierry is close to publishing an updated version of tegradrm which would presumably be a good base.
You probably also want to look at:
http://lists.freedesktop.org/archives/dri-devel/2012-July/024875.html
Yes that's where I got the binding that I am currently using. I think Thierry pointed me to it a while ago.
... although I think that's implicitly included in the tegradrm stuff.
Regards, Simon

Dear Tom Warren,
Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@chromium.org] Sent: Sunday, July 29, 2012 11:53 PM To: U-Boot Mailing List Cc: Tom Warren; Stephen Warren; Scott Wood; Simon Glass Subject: [PATCH v4 0/6] tegra: Add NAND flash support
This series adds NAND flash support to Tegra and enables it on Seaboard.
Applied to u-boot-tegra/next, thanks. The fix for the m28evk and apx4devkit builds (moving common.h to the top in mxs_nand.c) can come from you or Marek, and I'll add it to /next later. But for now, all tegra20 boards build fine.
I'd say, the patchset that breaks something should also fix it.
Tom
Included here is a proposed device tree binding with most of the properties private to "nvidia,". The binding includes information about the NAND controller as well as the connected NAND device. The Seaboard has a Hynix HY27UF4G2B.
The driver supports ECC-based access and uses DMA and NAND acceleration features of the Tegra SOC to provide access at reasonable speed.
Changes in v2:
- Add new patch to align default buffers in nand_base
- Added comment about the behaviour of the 'resp' register
- Call set_bus_width_page_size() at init to report errors earlier
- Change set_bus_width_page_size() to return an error when needed
- Change timing structure member to u32 to match device tree
- Check for supported bus width in board_nand_init()
- Fix tegra nand header file to remove BIT defines
- Implement a dummy nand_select_chip() instead of nand_hwcontro()
- Make nand_command() display an error on an unknown command
- Minor code tidy-ups in driver for style
- Move cache logic into a separate dma_prepare() function
- Remove CMD_TRANS_SIZE_BYTESx enum
- Remove space after casts
- Remove use of 'register' variables
- Rename struct nand_info to struct nand_drv to avoid nand_info_t
confusion - Support 4096 byte page devices, drop 1024 and 2048
- Tidy up nand_waitfor_cmd_completion() logic
- Update NAND binding to add "nvidia," prefix
- Use s32 for device tree integer values
Changes in v3:
- Add reg property for unit address (should be used for chip select)
- Change note in fdt binding about the need for a hardware-specific
binding - Fix up typos in fdt binding, and rename the file
- Update fdt binding to make everything Nvidia-specific
Changes in v4:
- Align buffer length to cache line size in dma_prepare()
- Fix "Write Page 0x0 timeout with ECC" error on 4.4.1
- Fix the issue that read_byte can read at most 4 times
- Get some information from Read ID data instead of from device tree
- In nand_command, set NAND_CMD_RNDOUT as unsupported command
- Modify eccoob layout
- Move to using CONFIG_SYS_NAND_SELF_INIT
- Remove "DEFAULT" from comment because that function is not default
- Remove fdt bindings related to page structure
- Remove local read_buf and write_buf functions
- Remove some fields in fdt_nand structure
- Rename CONFIG_TEGRA2_NAND to CONFIG_TEGRA_NAND
- Rename variables my_* as our_*
- Use virt_to_phys() when filling address register
Jim Lin (1): tegra: nand: Add Tegra NAND driver
Simon Glass (5): nand: Try to align the default buffers tegra: Add NAND support to funcmux tegra: fdt: Add NAND controller binding and definitions tegra: fdt: Add NAND definitions to fdt tegra: Enable NAND on Seaboard
arch/arm/cpu/tegra20-common/funcmux.c | 7 + arch/arm/dts/tegra20.dtsi | 7 + arch/arm/include/asm/arch-tegra20/funcmux.h | 3 + arch/arm/include/asm/arch-tegra20/tegra20.h | 1 + board/nvidia/dts/tegra20-seaboard.dts | 10 + .../nand/nvidia,tegra20-nand.txt | 53 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/nand_base.c | 3 +- drivers/mtd/nand/tegra_nand.c | 1026
++++++++++++++++++++
drivers/mtd/nand/tegra_nand.h | 257 +++++ include/configs/seaboard.h | 9 + include/configs/tegra20-common.h | 2 + include/fdtdec.h | 1 + include/linux/mtd/nand.h | 7 +- lib/fdtdec.c | 1 + 15 files changed, 1384 insertions(+), 4 deletions(-) create mode 100644
doc/device-tree-bindings/nand/nvidia,tegra20-nand.txt
create mode 100644 drivers/mtd/nand/tegra_nand.c create mode 100644
drivers/mtd/nand/tegra_nand.h
-- 1.7.7.3
Best regards, Marek Vasut
participants (7)
-
Lucas Stach
-
Marek Vasut
-
Scott Wood
-
Simon Glass
-
Stephen Warren
-
Thierry Reding
-
Tom Warren