nand/denali: Adding Denali NAND driver support
Subsystems (2)
PATCH v6 1/1 nand/denali: Adding Denali NAND driver support
To add the Denali NAND driver support into U-Boot. It required information such as register base address from configuration header file within include/configs folder.
---
Changes for v6
- Remove chip_delay as its unused
- Remove ECC bit assignment in nand_para functions Changes for v5
- Rename denali_nand to denali only
- Rename the macro for ctrl and data address Changes for v4
- Added cache flush to handle dcache enabled
- Used standard return where 0 for pass
- Removed unnecessary casting
- Used standard readl and writel
Changes for v3
- Fixed coding style
Changes for v2
- Enable this driver support for SOCFPGA
--- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/denali.c | 1132 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/denali.h | 496 ++++++++++++++++++++ 3 files changed, 1629 insertions(+) create mode 100644 drivers/mtd/nand/denali.c create mode 100644 drivers/mtd/nand/denali.h
drivers/mtd/nand/Makefile +1 -0
@@ -39,6 +39,7 @@ obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o +obj-$(CONFIG_NAND_DENALI) += denali.o obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
drivers/mtd/nand/denali.c new file +1132 -0
1,132 lines not on this page · raw message
drivers/mtd/nand/denali.h new file +496 -0
496 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v6 1/1 nand/denali: Adding Denali NAND driver support
Hi Chin,
drivers/mtd/nand/denali.c line 6
Quoted 9 lines
drivers/mtd/nand/denali.c new file +6
-0@@ -0,0 +1,1132 @@ +/* +* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> +* Copyright (C) 2009-2010, Intel Corporation and its suppliers. +* +* SPDX-License-Identifier: GPL-2.0+ +*/
If you don't mind, is it OK to add the creadit of Panasonic? Going forward, Altera and Panasonic will share this driver and I am contributing on code improvement and run test. (I will post Panasonic boards support code after this driver is merged.)
drivers/mtd/nand/denali.c line 9
Quoted 3 lines
drivers/mtd/nand/denali.c new file +3
-0+/* setups the HW to perform the data DMA */ +static void denali_setup_dma (int op) +{
I sent a question to Cadence again and
finally received an answer I had wanted.
They said DMA command sequence depends on the bus width.
Panasonic bought 64bit bus version.
I guess Altera bought 32bit bus version.
So I'd like to suggest to use #ifdef CONFIG_NAND_DENALI_64BIT here.
Quoted 4 lines
drivers/mtd/nand/denali.c new file +4
-0+/* +* Although controller spec said SLC ECC is forceb to be 4bit, but denali +* controller in MRST only support 15bit and 8bit ECC correction +*/
drivers/mtd/nand/denali.c line 23
Quoted 10 lines
drivers/mtd/nand/denali.c new file +10
-0+#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST +#define ECC_15BITS 26 +static struct nand_ecclayout nand_15bit_oob = { + .eccbytes =ECC_15BITS , +}; +#else +#define ECC_8BITS 14 +static struct nand_ecclayout nand_8bit_oob = { + .eccbytes =ECC_8BITS , +};
I think supporting only 15bit, 8bit is odd. The number of ECC bits depends on the hardware. (You can choose ECC bits you like when you buy the IP from Cadence.)
I'd like to suggest to re-write this part in a generic way by using the formula given in Denali's document.
if (ecc.size == 512)
ecc.bytes = Ceiling_to_next_word(ecc.strength * 13)
if (ecc.size == 1024)
ecc.bytes = Ceiling_to_next_word(ecc.strength * 14)
Quoted 9 lines
drivers/mtd/nand/denali.c new file +9
-0+ nand->ecc.mode =NAND_ECC_HW ; + nand->ecc.size =CONFIG_NAND_DENALI_ECC_SIZE ; + nand->ecc.read_oob = denali_read_oob; + nand->ecc.write_oob = denali_write_oob; + nand->ecc.read_page = denali_read_page; + nand->ecc.read_page_raw = denali_read_page_raw; + nand->ecc.write_page = denali_write_page; + nand->ecc.write_page_raw = denali_write_page_raw; +#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST
drivers/mtd/nand/denali.c line 42
Quoted 10 lines
drivers/mtd/nand/denali.c new file +10
-0+/* 15bit ECC */ + nand->ecc.bytes =26 ; + nand->ecc.layout = &nand_15bit_oob; +#else /* 8bit ECC */ + nand->ecc.bytes =14 ; + nand->ecc.layout = &nand_8bit_oob; +#endif + nand->ecc.calculate = denali_ecc_calculate; + nand->ecc.correct = denali_ecc_correct; + nand->ecc.hwctl = denali_ecc_hwctl;
denali_ecc_calculate(),denali_ecc_correct(),denali_ecc_hwctl()
are never called. Nor do we need to set stub functions.
Besides, ecc.strength must be set.
I guess ECC_CORRECTION register is already set correctly. (In the case of SOCFPGA, it would be set to 8.)
So, ecc.strength should be set to the value of ECC_CORRECTION.
drivers/mtd/nand/denali.c line 47
Quoted 5 lines
drivers/mtd/nand/denali.c new file +5
-0+ +typedef int irqreturn_t ; + +#define IRQ_HANDLED 1 +#define IRQ_NONE 0
These typedef and macros are not used. denali.h in Linux Kernel does not have them either. Please delete.
drivers/mtd/nand/denali.c line 49
Quoted 2 lines
drivers/mtd/nand/denali.c new file +2
-0+#define SUPPORT_15BITECC 1 +#define SUPPORT_8BITECC 1
These are no longer necessary.
drivers/mtd/nand/denali.c line 50
Quoted 1 line
drivers/mtd/nand/denali.c new file +1
-0+#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
NAND_MAX_PAGESIZE and NAND_MAX_OOBSIZE are defined in include/linux/mtd/nand.h
So, denali.h must include it.
Code diff is as follows:
drivers/mtd/nand/denali.c +40 -50
@@ -1,5 +1,6 @@/* -* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> +* Copyright (C) 2014 Panasonic Corporation +* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> * Copyright (C) 2009-2010, Intel Corporation and its suppliers. * * SPDX-License-Identifier: GPL-2.0+
@@ -660,6 +661,21 @@ static void denali_setup_dma(int op)flush_dcache_range (addr, addr +sizeof (denali.buf.dma_buf)); +#ifdef CONFIG_NAND_DENALI_64BIT + mode =MODE_10 |BANK (denali.flash_bank) | denali.page; + +/* DMA is a three step process */ + +/* 1. setup transfer type, interrupt when complete, +burst len = 64 bytes, the number of pages */ +index_addr (mode,0x01002000 | (64 <<16 ) | op | page_count); + +/* 2. set memory low address bits 31:0 */ +index_addr (mode, addr); + +/* 3. set memory high address bits 64:32 */ +index_addr (mode,0 ); +#else mode =MODE_10 |BANK (denali.flash_bank);/* DMA is a four step process */
@@ -675,6 +691,7 @@ static void denali_setup_dma(int op)/* 4. interrupt when complete, burst len = 64 bytes*/ index_addr (mode |0x14000 ,0x2400 ); +#endif }/* Common DMA function */
@@ -1017,26 +1034,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,break ; } } - -/* stubs for ECC functions not used by the NAND core */ -static int denali_ecc_calculate (struct mtd_info *mtd,const uint8_t *data, -uint8_t *ecc_code) -{ -BUG (); -return -EIO ; -} - -static int denali_ecc_correct (struct mtd_info *mtd,uint8_t *data, -uint8_t *read_ecc,uint8_t *calc_ecc) -{ -BUG (); -return -EIO ; -} - -static void denali_ecc_hwctl (struct mtd_info *mtd,int mode) -{ -BUG (); -}/* end NAND core entry points */ /* Initialization code to bring the device up to a known good state */
@@ -1062,23 +1059,9 @@ static void denali_hw_init(void)denali_irq_init (); } -/* -* Although controller spec said SLC ECC is forceb to be 4bit, but denali -* controller in MRST only support 15bit and 8bit ECC correction -*/ -#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST -#define ECC_15BITS 26 -static struct nand_ecclayout nand_15bit_oob = { - .eccbytes =ECC_15BITS , -}; -#else -#define ECC_8BITS 14 -static struct nand_ecclayout nand_8bit_oob = { - .eccbytes =ECC_8BITS , -}; -#endif /* CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST */ +static struct nand_ecclayout nand_oob; -static void denali_nand_init (struct nand_chip *nand) +static int denali_nand_init (struct nand_chip *nand) { denali.flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE ; denali.flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE ;
@@ -1104,17 +1087,24 @@ static void denali_nand_init(struct nand_chip *nand) nand->ecc.read_page_raw = denali_read_page_raw; nand->ecc.write_page = denali_write_page; nand->ecc.write_page_raw = denali_write_page_raw; -#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST -/* 15bit ECC */ - nand->ecc.bytes =26 ; - nand->ecc.layout = &nand_15bit_oob; -#else /* 8bit ECC */ - nand->ecc.bytes =14 ; - nand->ecc.layout = &nand_8bit_oob; -#endif - nand->ecc.calculate = denali_ecc_calculate; - nand->ecc.correct = denali_ecc_correct; - nand->ecc.hwctl = denali_ecc_hwctl; +/* +* Tell driver the ecc strength. This register may be already set +* correctly. So we read this value out. +*/ + nand->ecc.strength =readl (denali.flash_reg +ECC_CORRECTION ); +switch (nand->ecc.size) { +case 512 : + nand->ecc.bytes = (nand->ecc.strength *13 +15 ) /16 *2 ; +break ; +case 1024 : + nand->ecc.bytes = (nand->ecc.strength *14 +15 ) /16 *2 ; +break ; +default : +pr_err ("Unsupported ECC size\n" ); +return -EINVAL ; + } + nand_oob.eccbytes = nand->ecc.bytes; + nand->ecc.layout = &nand_oob;/* Set address of hardware control function */ nand->cmdfunc = denali_cmdfunc;
@@ -1123,10 +1113,10 @@ static void denali_nand_init(struct nand_chip *nand) nand->select_chip = denali_select_chip; nand->waitfunc = denali_waitfunc;denali_hw_init (); +return 0 ; }int board_nand_init (struct nand_chip *chip) { -denali_nand_init (chip); -return 0 ; +return denali_nand_init (chip); }
drivers/mtd/nand/denali.h +1 -7
@@ -5,10 +5,7 @@* SPDX-License-Identifier: GPL-2.0+ */ -typedef int irqreturn_t ; - -#define IRQ_HANDLED 1 -#define IRQ_NONE 0 +#include <linux/mtd/nand.h> #define DEVICE_RESET 0x0#define DEVICE_RESET__BANK0 0x0001
@@ -382,9 +379,6 @@ typedef int irqreturn_t;#define GLOB_HWCTL_DEFAULT_BLKS 2048 -#define SUPPORT_15BITECC 1 -#define SUPPORT_8BITECC 1 -#define CUSTOM_CONF_PARAMS 0#define ONFI_BLOOM_TIME 1
Best Regards
Masahiro Yamada
PATCH v6 1/1 nand/denali: Adding Denali NAND driver support
Hi Mashiro,
Quoted 19 lines · Masahiro Yamada
Hi Chin,
drivers/mtd/nand/denali.c line 6
Quoted 9 lines
drivers/mtd/nand/denali.c new file +6
-0@@ -0,0 +1,1132 @@ +/* +* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> +* Copyright (C) 2009-2010, Intel Corporation and its suppliers. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ If you don't mind, is it OK to add the creadit of Panasonic? Going forward, Altera and Panasonic will share this driver and I am contributing on code improvement and run test. (I will post Panasonic boards support code after this driver is merged.)
Sure, no problem.
Its open source and code belongs to everyone :)
Quoted 9 lines
drivers/mtd/nand/denali.c line 9
Quoted 4 lines
drivers/mtd/nand/denali.c new file +3
-0+/* setups the HW to perform the data DMA */ +static void denali_setup_dma (int op) +{I sent a question to Cadence again and
finally received an answer I had wanted.
They said DMA command sequence depends on the bus width.
Quoted 6 lines
Panasonic bought 64bit bus version.
I guess Altera bought 32bit bus version.So I'd like to suggest to use #ifdef
CONFIG_NAND_DENALI_64BIThere.
Yup, finally we know why.
Added in next patch.
Quoted 23 lines
Quoted 7 lines
drivers/mtd/nand/denali.c new file +4
-0+/* +* Although controller spec said SLC ECC is forceb to be 4bit, but denali +* controller in MRST only support 15bit and 8bit ECC correction +*/ drivers/mtd/nand/denali.c line 23
Quoted 10 lines
drivers/mtd/nand/denali.c new file +10
-0+#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST +#define ECC_15BITS 26 +static struct nand_ecclayout nand_15bit_oob = { + .eccbytes =ECC_15BITS , +}; +#else +#define ECC_8BITS 14 +static struct nand_ecclayout nand_8bit_oob = { + .eccbytes =ECC_8BITS , +};I think supporting only 15bit, 8bit is odd. The number of ECC bits depends on the hardware. (You can choose ECC bits you like when you buy the IP from Cadence.)
Quoted 9 lines
I'd like to suggest to re-write this part in a generic way by using the formula given in Denali's document.
if (ecc.size == 512)
ecc.bytes =Ceiling_to_next_word(ecc.strength * 13)if (ecc.size == 1024)
ecc.bytes =Ceiling_to_next_word(ecc.strength * 14)
Sure, we can enhance this. The old code which mentioned MRST seems not applicable any more. At least, this is true for both of us.
Quoted 28 lines
Quoted 12 lines
drivers/mtd/nand/denali.c new file +9
-0+ nand->ecc.mode =NAND_ECC_HW ; + nand->ecc.size =CONFIG_NAND_DENALI_ECC_SIZE ; + nand->ecc.read_oob = denali_read_oob; + nand->ecc.write_oob = denali_write_oob; + nand->ecc.read_page = denali_read_page; + nand->ecc.read_page_raw = denali_read_page_raw; + nand->ecc.write_page = denali_write_page; + nand->ecc.write_page_raw = denali_write_page_raw; +#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST drivers/mtd/nand/denali.c line 42
Quoted 10 lines
drivers/mtd/nand/denali.c new file +10
-0+/* 15bit ECC */ + nand->ecc.bytes =26 ; + nand->ecc.layout = &nand_15bit_oob; +#else /* 8bit ECC */ + nand->ecc.bytes =14 ; + nand->ecc.layout = &nand_8bit_oob; +#endif + nand->ecc.calculate = denali_ecc_calculate; + nand->ecc.correct = denali_ecc_correct; + nand->ecc.hwctl = denali_ecc_hwctl;
denali_ecc_calculate(),denali_ecc_correct(),denali_ecc_hwctl()
are never called. Nor do we need to set stub functions.
Quoted 7 lines
Besides, ecc.strength must be set.
I guess
ECC_CORRECTIONregister is already set correctly. (In the case of SOCFPGA, it would be set to 8.)So, ecc.strength should be set to the value of
ECC_CORRECTION.
Yup, these can be removed.
It was added for SPL version but later I modified the SPL driver to use the HW ECC correction.
Quoted 14 lines
drivers/mtd/nand/denali.c line 47
Quoted 8 lines
drivers/mtd/nand/denali.c new file +5
-0+ +typedef int irqreturn_t ; + +#define IRQ_HANDLED 1 +#define IRQ_NONE 0These typedef and macros are not used.
denali.hin Linux Kernel does not have them either. Please delete.
Quoted 6 lines
drivers/mtd/nand/denali.c line 49
Quoted 2 lines
drivers/mtd/nand/denali.c new file +2
-0+#define SUPPORT_15BITECC 1 +#define SUPPORT_8BITECC 1These are no longer necessary.
Noted. They are removed.
Quoted 9 lines
drivers/mtd/nand/denali.c line 50
Quoted 2 lines
drivers/mtd/nand/denali.c new file +1
-0+#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
NAND_MAX_PAGESIZEandNAND_MAX_OOBSIZEare defined ininclude/linux/mtd/nand.hSo,
denali.hmust include it.
Added in next patch.
Quoted 170 lines
Code diff is as follows:
drivers/mtd/nand/denali.c +40
-50@@ -1,5 +1,6 @@/* -* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> +* Copyright (C) 2014 Panasonic Corporation +* Copyright (C) 2013-2014 Altera Corporation <www.altera.com> * Copyright (C) 2009-2010, Intel Corporation and its suppliers. * * SPDX-License-Identifier: GPL-2.0+ @@ -660,6 +661,21 @@ static void denali_setup_dma(int op)flush_dcache_range (addr, addr +sizeof (denali.buf.dma_buf)); +#ifdef CONFIG_NAND_DENALI_64BIT + mode =MODE_10 |BANK (denali.flash_bank) | denali.page; + +/* DMA is a three step process */ + +/* 1. setup transfer type, interrupt when complete, +burst len = 64 bytes, the number of pages */ +index_addr (mode,0x01002000 | (64 <<16 ) | op | page_count); + +/* 2. set memory low address bits 31:0 */ +index_addr (mode, addr); + +/* 3. set memory high address bits 64:32 */ +index_addr (mode,0 ); +#else mode =MODE_10 |BANK (denali.flash_bank);/* DMA is a four step process */ @@ -675,6 +691,7 @@ static void denali_setup_dma(int op)/* 4. interrupt when complete, burst len = 64 bytes*/ index_addr (mode |0x14000 ,0x2400 ); +#endif }/* Common DMA function */ @@ -1017,26 +1034,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,break ; } } - -/* stubs for ECC functions not used by the NAND core */ -static int denali_ecc_calculate (struct mtd_info *mtd,const uint8_t *data, -uint8_t *ecc_code) -{ -BUG (); -return -EIO ; -} - -static int denali_ecc_correct (struct mtd_info *mtd,uint8_t *data, -uint8_t *read_ecc,uint8_t *calc_ecc) -{ -BUG (); -return -EIO ; -} - -static void denali_ecc_hwctl (struct mtd_info *mtd,int mode) -{ -BUG (); -}/* end NAND core entry points */ /* Initialization code to bring the device up to a known good state */ @@ -1062,23 +1059,9 @@ static void denali_hw_init(void)denali_irq_init (); } -/* -* Although controller spec said SLC ECC is forceb to be 4bit, but denali -* controller in MRST only support 15bit and 8bit ECC correction -*/ -#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST -#define ECC_15BITS 26 -static struct nand_ecclayout nand_15bit_oob = { - .eccbytes =ECC_15BITS , -}; -#else -#define ECC_8BITS 14 -static struct nand_ecclayout nand_8bit_oob = { - .eccbytes =ECC_8BITS , -}; -#endif /* CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST */ +static struct nand_ecclayout nand_oob; -static void denali_nand_init (struct nand_chip *nand) +static int denali_nand_init (struct nand_chip *nand) { denali.flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE ; denali.flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE ;@@ -1104,17 +1087,24 @@ static void denali_nand_init(struct nand_chip *nand) nand->ecc.read_page_raw = denali_read_page_raw; nand->ecc.write_page = denali_write_page; nand->ecc.write_page_raw = denali_write_page_raw; -#ifdef CONFIG_SYS_NAND_15BIT_HW_ECC_OOBFIRST -/* 15bit ECC */ - nand->ecc.bytes =26 ; - nand->ecc.layout = &nand_15bit_oob; -#else /* 8bit ECC */ - nand->ecc.bytes =14 ; - nand->ecc.layout = &nand_8bit_oob; -#endif - nand->ecc.calculate = denali_ecc_calculate; - nand->ecc.correct = denali_ecc_correct; - nand->ecc.hwctl = denali_ecc_hwctl; +/* +* Tell driver the ecc strength. This register may be already set +* correctly. So we read this value out. +*/ + nand->ecc.strength =readl (denali.flash_reg +ECC_CORRECTION ); +switch (nand->ecc.size) { +case 512 : + nand->ecc.bytes = (nand->ecc.strength *13 +15 ) /16 *2 ; +break ; +case 1024 : + nand->ecc.bytes = (nand->ecc.strength *14 +15 ) /16 *2 ; +break ; +default : +pr_err ("Unsupported ECC size\n" ); +return -EINVAL ; + } + nand_oob.eccbytes = nand->ecc.bytes; + nand->ecc.layout = &nand_oob;/* Set address of hardware control function */ nand->cmdfunc = denali_cmdfunc;@@ -1123,10 +1113,10 @@ static void denali_nand_init(struct nand_chip *nand) nand->select_chip = denali_select_chip; nand->waitfunc = denali_waitfunc;denali_hw_init (); +return 0 ; }int board_nand_init (struct nand_chip *chip) { -denali_nand_init (chip); -return 0 ; +return denali_nand_init (chip); }drivers/mtd/nand/denali.h +1
-4@@ -5,10 +5,7 @@* SPDX-License-Identifier: GPL-2.0+ */ -typedef int irqreturn_t ; - -#define IRQ_HANDLED 1 -#define IRQ_NONE 0 +#include <linux/mtd/nand.h> #define DEVICE_RESET 0x0#define DEVICE_RESET__BANK0 0x0001
drivers/mtd/nand/denali.h typedef int irqreturn_t; · line 384
Quoted 9 lines
drivers/mtd/nand/denali.h +0
-3@@ -382,9 +379,6 @@ typedef int irqreturn_t;#define GLOB_HWCTL_DEFAULT_BLKS 2048 -#define SUPPORT_15BITECC 1 -#define SUPPORT_8BITECC 1 -#define CUSTOM_CONF_PARAMS 0#define ONFI_BLOOM_TIME 1
Applied at v7 patch.
Thanks
Chin Liang
Quoted 6 lines
Best Regards
Masahiro Yamada