[U-Boot] [PATCH v2 00/20] Bring NAND support to Nintendo NES Classic

Hello,
This series first adds fixes and enhancements to sunxi NAND drivers (SPL and U-Boot). Once this is done, the SPL NAND driver is converted to use PIO instead of DMA with the goal to support all SoCs with this IP without the need for DMA-related code. Finally, NAND support is added to Nintendo NES Classic through Kconfig and DT additions.
Thanks, Miquèl
Changes since v1: =================
All: ---- - Enhance all commit messages. - Rebased on top of master branch (I should have done that earlier but I forgot I was on an old revision).
Fix binman_sym output check --------------------------- - SPL seems to be broken for a few weeks when using raw NAND, fix it by changing the error condition.
Fix strength ------------ - Add comment explaining the added line and moved the line for clarification on why it is needed. - Add forgotten Boris' Suggested-by tag.
Fix second case of modulo by zero error ---------------------------------------- - Added a reference to the first occurence of this issue.
Allow SPL to be compiled for sun8i platforms -------------------------------------------- - This commit is not about compiling the SPL, but the NAND support in the SPL, as corrected by Maxime.
Enhancements and cleaning ------------------------- - Patch split into several logical chunks, as requested. - Removed useless udelay(1), that was added for debugging purpose. - Introduced the nand_exec_cmd() helper to mutualize code one step further. - Add an udelay(1) after changing the column to respect the minimum tCCS delay (Change Column Setup time). - Canceled moving to global scope the ecc_strength array.
Use PIO instead of DMA ---------------------- - Change commit message/title. - Cancel removing NFC related definitions: they can be useful as the this IP is quite under-documented. - Merge nand_reset_column and nand_change_column (in another patch). - Moved the copy of the data after the check of the ECC status. - ECC chunks are read manually, return if the first chunk is empty only (needed for configuration research), otherwise it should not be treated as an error.
Add NAND node to sun8i ---------------------- - U-Boot master branch already has this node, remove the patch.
Enable NAND on NES classic -------------------------- - Change the DT cells size from 2 to 1.
Add NAND support for NES classic -------------------------------- - Split in several patches, moving SPL_NAND_SUPPORT and NAND_SUNXI out of the defconfig files (NES and CHIP pro) to be automatically selected depending on NAND_SUNXI and ARCH_SUNXI. - Moved the NAND parameters to Kconfig (only for SUNXI because the tool did not work as expected, maybe due to some definitions that are not "numbers" but multiplications and sometimes use other definitions (NAND page size, 2K_SZ, etc).
Miquel Raynal (20): spl: fix binman_sym output check mtd: nand: sunxi: fix ECC strength choice spl: nand: sunxi: fix second case of modulo by zero error spl: nand: sunxi: fix typo on register name spl: nand: sunxi: introduce the nand_wait_int() helper spl: nand: sunxi: introduce the nand_wait_cmd_fifo_empty() helper spl: nand: sunxi: add missing status clear spl: nand: sunxi: create an helper to handle command execution spl: nand: sunxi: ensure enough time has passed after changing the column spl: nand: sunxi: make the reset column helper more generic sunxi: spl: deassert the NAND controller reset line spl: nand: sunxi: declare the ecc_bytes array globally spl: nand: sunxi: use PIO instead of DMA sunxi: spl: remove DMA related settings of the NAND controller sunxi: allow NAND support in SPL to be compiled for sun8i platforms sunxi: dts: enable NAND on NES classic sunxi: automatically select SPL_NAND_SUPPORT in Kconfig sunxi: make NAND_SUNXI use ARCH_SUNXI as default in Kconfig sunxi: move the NAND parameters to Kconfig configs: add NAND support for NES Classic
arch/arm/dts/sun8i-a23-a33.dtsi | 18 ++ .../dts/sun8i-r16-nintendo-nes-classic-edition.dts | 14 ++ arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 6 + board/sunxi/board.c | 6 +- common/spl/spl.c | 10 +- configs/CHIP_pro_defconfig | 6 +- configs/Nintendo_NES_Classic_Edition_defconfig | 4 + drivers/mtd/nand/Kconfig | 26 ++- drivers/mtd/nand/sunxi_nand.c | 8 +- drivers/mtd/nand/sunxi_nand_spl.c | 242 ++++++++++----------- 10 files changed, 206 insertions(+), 134 deletions(-)

A previous commit introduced the use of binman in the SPL.
After the binman_sym call over the 'pos' symbol, the output value is checked against BINMAN_SYM_MISSING (-1UL). According to the documentation (tools/binman/README), when it comes to the 'pos' attribute:
pos: This sets the position of an entry within the image. The first byte of the image is normally at position 0. If 'pos' is not provided, binman sets it to the end of the previous region, or the start of the image's entry area (normally 0) if there is no previous region.
So instead of checking if the return value is BINMAN_SYM_MISSING, we should check if the value is not null.
The failure happens when using both files sunxi-spl(-with-ecc).bin and u-boot-dtb.bin instead of u-boot-sunxi-with-spl.bin. This is because u-boot-dtb.bin does not have the U-Boot header while it is present in u-boot-sunwi-with-spl.bin. Not having the header forces the SPL to discover where it should load U-Boot. The binman_sym call is supposed to do that but fails. Because of the wrong check, the destination address was set to 0 while it should have been somewhere in RAM. This, obviously, stalls the board.
Fixes: 8bee2d251afb ("binman: Add binman symbol support to SPL") Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- common/spl/spl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index b1ce56d0d0..cc0aa26452 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -127,8 +127,14 @@ void spl_set_header_raw_uboot(struct spl_image_info *spl_image) ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
spl_image->size = CONFIG_SYS_MONITOR_LEN; - if (u_boot_pos != BINMAN_SYM_MISSING) { - /* biman does not support separate entry addresses at present */ + + /* + * Binman error cases: address of the end of the previous region or the + * start of the image's entry area (usually 0) if there is no previous + * region. + */ + if (u_boot_pos) { + /* Binman does not support separate entry addresses */ spl_image->entry_point = u_boot_pos; spl_image->load_addr = u_boot_pos; } else {

Hi,
On Thu, Feb 22, 2018 at 02:33:31PM +0100, Miquel Raynal wrote:
A previous commit introduced the use of binman in the SPL.
After the binman_sym call over the 'pos' symbol, the output value is checked against BINMAN_SYM_MISSING (-1UL). According to the documentation (tools/binman/README), when it comes to the 'pos' attribute:
pos: This sets the position of an entry within the image. The first byte of the image is normally at position 0. If 'pos' is not provided, binman sets it to the end of the previous region, or the start of the image's entry area (normally 0) if there is no previous region.
So instead of checking if the return value is BINMAN_SYM_MISSING, we should check if the value is not null.
The failure happens when using both files sunxi-spl(-with-ecc).bin and u-boot-dtb.bin instead of u-boot-sunxi-with-spl.bin. This is because u-boot-dtb.bin does not have the U-Boot header while it is present in u-boot-sunwi-with-spl.bin. Not having the header forces the SPL to discover where it should load U-Boot. The binman_sym call is supposed to do that but fails. Because of the wrong check, the destination address was set to 0 while it should have been somewhere in RAM. This, obviously, stalls the board.
You should probably rewrite that part a bit. There's nothing specific about the Allwinner image, since issue will arise on the generic uboot image as well, and your fix is in the core SPL.
Maxime

When the requested ECC strength does not exactly match the strengths supported by the ECC engine, the driver is selecting the closest strength meeting the 'selected_strength > requested_strength' constraint. Fix the fact that, in this particular case, ecc->strength value was not updated to match the 'selected_strength'.
For instance, one can encounter this issue when no ECC requirement is filled in the device tree while the NAND chip minimum requirement is not a strength/step_size combo natively supported by the ECC engine.
Suggested-by: Boris Brezillon boris.brezillon@bootlin.com Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 532e03cd84..37160aaec2 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -1407,8 +1407,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
/* Add ECC info retrieval from DT */ for (i = 0; i < ARRAY_SIZE(strengths); i++) { - if (ecc->strength <= strengths[i]) + if (ecc->strength <= strengths[i]) { + /* + * Update ecc->strength value with the actual strength + * that will be used by the ECC engine. + */ + ecc->strength = strengths[i]; break; + } }
if (i >= ARRAY_SIZE(strengths)) {

In the nand_read_buffer() step, the seed is calculated by doing a modulo by conf->nseeds which is always zero when not using the randomizer (most of SLC NANDs).
This situation turns out to lead to a run time freeze with certain toolchains.
Derive this seed only when the randomizer is enabled (and conf->nseeds logically not zero), exactly like what has been done before with an identical situation, see commit ea3f750c73e3 ("nand: sunxi: Fix modulo by zero error").
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index eed4472bdc..06695fc15f 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -475,11 +475,12 @@ static int nand_detect_config(struct nfc_config *conf, u32 offs, void *dest) static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, unsigned int size, void *dest) { - int first_seed, page, ret; + int first_seed = 0, page, ret;
size = ALIGN(size, conf->page_size); page = offs / conf->page_size; - first_seed = page % conf->nseeds; + if (conf->randomize) + first_seed = page % conf->nseeds;
for (; size; size -= conf->page_size) { if (nand_load_page(conf, offs))

Change NFC_SEND_ADR to NFC_SEND_ADDR.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 06695fc15f..608cc997ca 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -55,7 +55,7 @@
#define NFC_ADDR_NUM_OFFSET 16 -#define NFC_SEND_ADR (1 << 19) +#define NFC_SEND_ADDR (1 << 19) #define NFC_ACCESS_DIR (1 << 20) #define NFC_DATA_TRANS (1 << 21) #define NFC_SEND_CMD1 (1 << 22) @@ -208,7 +208,7 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG | - ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR, + ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR, SUNXI_NFC_BASE + NFC_CMD);
if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, @@ -228,7 +228,7 @@ static int nand_reset_column(void) SUNXI_NFC_BASE + NFC_RCMD_SET); writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW); writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_CMD_RNDOUT, + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT, SUNXI_NFC_BASE + NFC_CMD);
if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,

The pattern of polling on a status register until a bit is set or a timeout occurs is repeated multiple times in the driver. Mutualize the code by introducing the nand_wait_int() helper that does wait for the bit to flip or returns an error in case of timeout.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 608cc997ca..afb5fef0a6 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -155,6 +155,17 @@ static inline int check_value_negated(int offset, int unexpected_bits, return check_value_inner(offset, unexpected_bits, timeout_us, 1); }
+static int nand_wait_int(void) +{ + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for interruption\n"); + return -ETIMEDOUT; + } + + return 0; +} + void nand_init(void) { uint32_t val; @@ -176,12 +187,7 @@ void nand_init(void) writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error timeout waiting for nand reset\n"); - return; - } - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + nand_wait_int(); }
static void nand_apply_config(const struct nfc_config *conf) @@ -211,13 +217,7 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -EIO; - } - - return 0; + return nand_wait_int(); }
static int nand_reset_column(void) @@ -231,13 +231,8 @@ static int nand_reset_column(void) (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -1; - } + return nand_wait_int();
- return 0; }
static int nand_read_page(const struct nfc_config *conf, u32 offs,

On Thu, 22 Feb 2018 14:33:35 +0100 Miquel Raynal miquel.raynal@bootlin.com wrote:
The pattern of polling on a status register until a bit is set or a timeout occurs is repeated multiple times in the driver. Mutualize the code by introducing the nand_wait_int() helper that does wait for the bit to flip or returns an error in case of timeout.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
drivers/mtd/nand/sunxi_nand_spl.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 608cc997ca..afb5fef0a6 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -155,6 +155,17 @@ static inline int check_value_negated(int offset, int unexpected_bits, return check_value_inner(offset, unexpected_bits, timeout_us, 1); }
+static int nand_wait_int(void) +{
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
DEFAULT_TIMEOUT_US)) {
printf("nand: timeout waiting for interruption\n");
return -ETIMEDOUT;
- }
- return 0;
+}
void nand_init(void) { uint32_t val; @@ -176,12 +187,7 @@ void nand_init(void) writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
DEFAULT_TIMEOUT_US)) {
printf("Error timeout waiting for nand reset\n");
return;
- }
- writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- nand_wait_int();
}
static void nand_apply_config(const struct nfc_config *conf) @@ -211,13 +217,7 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
DEFAULT_TIMEOUT_US)) {
printf("Error while initializing dma interrupt\n");
return -EIO;
- }
- return 0;
- return nand_wait_int();
}
static int nand_reset_column(void) @@ -231,13 +231,8 @@ static int nand_reset_column(void) (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT, SUNXI_NFC_BASE + NFC_CMD);
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG,
DEFAULT_TIMEOUT_US)) {
printf("Error while initializing dma interrupt\n");
return -1;
- }
- return nand_wait_int();
You can drop this empty line.
- return 0;
}
static int nand_read_page(const struct nfc_config *conf, u32 offs,

One bit in the control registers indicates if the NAND controller is ready to receive a new command. Otherwise, the command FIFO is full and we should wait for this bit to flip. It then states that the last command has been processed and the FIFO is now free to welcome another command.
Add this sanity check before starting any new command.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index afb5fef0a6..f100eff6ac 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -155,6 +155,17 @@ static inline int check_value_negated(int offset, int unexpected_bits, return check_value_inner(offset, unexpected_bits, timeout_us, 1); }
+static int nand_wait_cmd_fifo_empty(void) +{ + if (!check_value_negated(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_FIFO_STAT, + DEFAULT_TIMEOUT_US)) { + printf("nand: timeout waiting for empty cmd FIFO\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int nand_wait_int(void) { if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_CMD_INT_FLAG, @@ -183,6 +194,8 @@ void nand_init(void) }
/* reset NAND */ + nand_wait_cmd_fifo_empty(); + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, SUNXI_NFC_BASE + NFC_CMD); @@ -194,6 +207,8 @@ static void nand_apply_config(const struct nfc_config *conf) { u32 val;
+ nand_wait_cmd_fifo_empty(); + val = readl(SUNXI_NFC_BASE + NFC_CTL); val &= ~NFC_CTL_PAGE_SIZE_MASK; writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size), @@ -206,6 +221,8 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) { int page = offs / conf->page_size;
+ nand_wait_cmd_fifo_empty(); + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET), @@ -222,6 +239,8 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs)
static int nand_reset_column(void) { + nand_wait_cmd_fifo_empty(); + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET),

It is best practice to always clear the status register before executing a command to be sure that the status read afterwards is relevant.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index f100eff6ac..e21a102a09 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -245,6 +245,7 @@ static int nand_reset_column(void) (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW); writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT,

Executing a command is matter of always doing the following sequence: * Waiting for the FIFO to be empty so we can fill it with the new command. * Clearing the status register. * Writing the command in the FIFO. * Waiting for the command to finish.
Add a nand_exec_cmd() helper to handle this instead of repeating the logic through the various functions.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 43 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index e21a102a09..25a0941fd2 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -177,6 +177,20 @@ static int nand_wait_int(void) return 0; }
+static int nand_exec_cmd(u32 cmd) +{ + int ret; + + ret = nand_wait_cmd_fifo_empty(); + if (ret) + return ret; + + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(cmd, SUNXI_NFC_BASE + NFC_CMD); + + return nand_wait_int(); +} + void nand_init(void) { uint32_t val; @@ -194,13 +208,7 @@ void nand_init(void) }
/* reset NAND */ - nand_wait_cmd_fifo_empty(); - - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, - SUNXI_NFC_BASE + NFC_CMD); - - nand_wait_int(); + nand_exec_cmd(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET); }
static void nand_apply_config(const struct nfc_config *conf) @@ -221,38 +229,29 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) { int page = offs / conf->page_size;
- nand_wait_cmd_fifo_empty(); - writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_READSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); writel(((page & 0xFFFF) << 16), SUNXI_NFC_BASE + NFC_ADDR_LOW); writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | NFC_WAIT_FLAG | - ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR, - SUNXI_NFC_BASE + NFC_CMD);
- return nand_wait_int(); + return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + NFC_SEND_ADDR | NFC_WAIT_FLAG | + ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET)); }
static int nand_reset_column(void) { - nand_wait_cmd_fifo_empty(); - writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); - writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW); - writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT, - SUNXI_NFC_BASE + NFC_CMD); - - return nand_wait_int();
+ return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | + NFC_CMD_RNDOUT); }
static int nand_read_page(const struct nfc_config *conf, u32 offs,

When changing the column, the ONFI specification states that a minimum time of tCCS (Change Column Setup time) must elapse between the last address cycle is asserted on the bus and the first data cycle is clocked. An usual value for average NANDs is 500 nanoseconds. Round it up to 1 microsecond to be safe.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 25a0941fd2..2fa1f70d9d 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -243,15 +243,22 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs)
static int nand_reset_column(void) { + int ret; + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW);
- return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | - (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | - NFC_CMD_RNDOUT); + ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | + NFC_CMD_RNDOUT); + + /* Ensure tCCS has passed before reading data */ + udelay(1); + + return ret; }
static int nand_read_page(const struct nfc_config *conf, u32 offs,

On Thu, 22 Feb 2018 14:33:39 +0100 Miquel Raynal miquel.raynal@bootlin.com wrote:
When changing the column, the ONFI specification states that a minimum time of tCCS (Change Column Setup time) must elapse between the last address cycle is asserted on the bus and the first data cycle is clocked. An usual value for average NANDs is 500 nanoseconds. Round it up to 1 microsecond to be safe.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
drivers/mtd/nand/sunxi_nand_spl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 25a0941fd2..2fa1f70d9d 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -243,15 +243,22 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs)
static int nand_reset_column(void) {
- int ret;
- writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW);
- return nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
(1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR |
NFC_CMD_RNDOUT);
- ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD |
(1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR |
NFC_CMD_RNDOUT);
- /* Ensure tCCS has passed before reading data */
- udelay(1);
Just nitpicking, but if ret < 0 you don't have to wait tCCS :P.
- return ret;
}
static int nand_read_page(const struct nfc_config *conf, u32 offs,

Prepare the future use of an helper to move the data pointer (the column) of the NAND chip by renaming nand_reset_column() to nand_change_column(). Resetting the column is just a matter of giving 0 as argument.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 2fa1f70d9d..8c97834ec2 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -241,7 +241,7 @@ static int nand_load_page(const struct nfc_config *conf, u32 offs) ((conf->addr_cycles - 1) << NFC_ADDR_NUM_OFFSET)); }
-static int nand_reset_column(void) +static int nand_change_column(u16 column) { int ret;
@@ -249,7 +249,7 @@ static int nand_reset_column(void) (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + NFC_RCMD_SET); - writel(0, SUNXI_NFC_BASE + NFC_ADDR_LOW); + writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW);
ret = nand_exec_cmd(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | @@ -414,7 +414,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, conf->ecc_strength >= 0; conf->ecc_strength--) { conf->randomize = false; - if (nand_reset_column()) + if (nand_change_column(0)) return -EIO;
/* @@ -434,7 +434,7 @@ static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, conf->randomize = true; conf->nseeds = ARRAY_SIZE(random_seed); do { - if (nand_reset_column()) + if (nand_change_column(0)) return -EIO;
if (!nand_read_page(conf, offs, dest, @@ -526,7 +526,7 @@ static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, /* Try to adjust ->nseeds and read the page again... */ conf->nseeds = cur_seed;
- if (nand_reset_column()) + if (nand_change_column(0)) return -EIO;
/* ... it still fails => it's a real corruption. */

Ensure the NAND controller reset line is deasserted before use.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- board/sunxi/board.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 8891961dcc..54ac018b80 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -286,6 +286,7 @@ static void nand_clock_setup(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); + setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0)); #ifdef CONFIG_MACH_SUN9I setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); #else

On Thu, Feb 22, 2018 at 02:33:41PM +0100, Miquel Raynal wrote:
Ensure the NAND controller reset line is deasserted before use.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
board/sunxi/board.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 8891961dcc..54ac018b80 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -286,6 +286,7 @@ static void nand_clock_setup(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
- setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0));
This is only relevant for the SoCs after the A31 (sun6i, sun8i, and probably the A80 (sun9i) and the armv8 (sun50i) families), so you should put an ifdef there.
Maxime

Hi Maxime,
On Thu, 22 Feb 2018 14:53:35 +0100, Maxime Ripard maxime.ripard@bootlin.com wrote:
On Thu, Feb 22, 2018 at 02:33:41PM +0100, Miquel Raynal wrote:
Ensure the NAND controller reset line is deasserted before use.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
board/sunxi/board.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 8891961dcc..54ac018b80 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -286,6 +286,7 @@ static void nand_clock_setup(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
- setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0));
This is only relevant for the SoCs after the A31 (sun6i, sun8i, and probably the A80 (sun9i) and the armv8 (sun50i) families), so you should put an ifdef there.
Can you tell me if something like this would fit?
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); +#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \ + defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0)); +#endif setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
Thanks, Miquèl

On Sat, Feb 24, 2018 at 05:35:06PM +0100, Miquel Raynal wrote:
Hi Maxime,
On Thu, 22 Feb 2018 14:53:35 +0100, Maxime Ripard maxime.ripard@bootlin.com wrote:
On Thu, Feb 22, 2018 at 02:33:41PM +0100, Miquel Raynal wrote:
Ensure the NAND controller reset line is deasserted before use.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
board/sunxi/board.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 8891961dcc..54ac018b80 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -286,6 +286,7 @@ static void nand_clock_setup(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
- setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0));
This is only relevant for the SoCs after the A31 (sun6i, sun8i, and probably the A80 (sun9i) and the armv8 (sun50i) families), so you should put an ifdef there.
Can you tell me if something like this would fit?
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \
- defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I
Yep, that would be better.
Thanks! Maxime

Dear Maxime,
In message 20180226084006.5armemyuslxgqjtw@flea.lan you wrote:
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \
- defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I
Yep, that would be better.
Actually such (ever growing) lists of board selectors are pretty much deprecated.
Instead, you should define a feature macro which describes the specific property, which you can then enable in all boards which have this property.
The big advantage is that (1) you don't have to touch this common code when you just add support for a new board and (2) the code becomes much easier to read and to understand.
Thanks!
Best regards,
Wolfgang Denk

Hi Wolfgang,
On Mon, Feb 26, 2018 at 09:52:21AM +0100, Wolfgang Denk wrote:
Dear Maxime,
In message 20180226084006.5armemyuslxgqjtw@flea.lan you wrote:
+#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \
- defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I
Yep, that would be better.
Actually such (ever growing) lists of board selectors are pretty much deprecated.
Instead, you should define a feature macro which describes the specific property, which you can then enable in all boards which have this property.
This is not really about boards but SoCs families, so the grain is much much larger (especially since the families are now based on the CPU these SoCs use, and we have pretty much only Cortex-A7 or A53).
The big advantage is that (1) you don't have to touch this common code when you just add support for a new board and (2) the code becomes much easier to read and to understand.
I'm not quite sure what you mean, do you have an example of such a construct?
Thanks! Maxime

Move the ecc_bytes array out of nand_max_ecc_strength() for future use by nand_read_page().
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 8c97834ec2..3be7ffa241 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -261,6 +261,8 @@ static int nand_change_column(u16 column) return ret; }
+static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; + static int nand_read_page(const struct nfc_config *conf, u32 offs, void *dest, int len) { @@ -348,7 +350,6 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs,
static int nand_max_ecc_strength(struct nfc_config *conf) { - static const int ecc_bytes[] = { 32, 46, 54, 60, 74, 88, 102, 110, 116 }; int max_oobsize, max_ecc_bytes; int nsectors = conf->page_size / conf->ecc_size; int i;

SPL support was first written to support only the earlier generations of Allwinner SoCs, and was only really enabled on the A13 / GR8. However, those old SoCs had a DMA engine that has been replaced since the A31 by another DMA controller that is no longer compatible.
Since the code directly uses that DMA controller, it cannot operate properly on the later SoCs, while the NAND controller has not changed.
There's two paths forward, the first one would have been to add support for that DMA controller too, the second to just remove the DMA usage entirely and rely on PIO.
The later has been chosen because CPU overload at this stage is not an issue and it makes the driver more generic, and easier to understand.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- drivers/mtd/nand/sunxi_nand_spl.c | 141 ++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 83 deletions(-)
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 3be7ffa241..5650c59905 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -10,6 +10,7 @@ #include <common.h> #include <config.h> #include <nand.h> +#include <linux/ctype.h>
/* registers */ #define NFC_CTL 0x00000000 @@ -67,10 +68,12 @@ #define NFC_SEND_CMD3 (1 << 28) #define NFC_SEND_CMD4 (1 << 29) #define NFC_RAW_CMD (0 << 30) +#define NFC_ECC_CMD (1 << 30) #define NFC_PAGE_CMD (2 << 30)
#define NFC_ST_CMD_INT_FLAG (1 << 1) #define NFC_ST_DMA_INT_FLAG (1 << 2) +#define NFC_ST_CMD_FIFO_STAT (1 << 3)
#define NFC_READ_CMD_OFFSET 0 #define NFC_RANDOM_READ_CMD0_OFFSET 8 @@ -80,22 +83,6 @@ #define NFC_CMD_RNDOUT 0x05 #define NFC_CMD_READSTART 0x30
-#define SUNXI_DMA_CFG_REG0 0x300 -#define SUNXI_DMA_SRC_START_ADDR_REG0 0x304 -#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308 -#define SUNXI_DMA_DDMA_BC_REG0 0x30C -#define SUNXI_DMA_DDMA_PARA_REG0 0x318 - -#define SUNXI_DMA_DDMA_CFG_REG_LOADING (1 << 31) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25) -#define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9) -#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5) -#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0) - -#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0) -#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8) - struct nfc_config { int page_size; int ecc_strength; @@ -266,86 +253,74 @@ static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; static int nand_read_page(const struct nfc_config *conf, u32 offs, void *dest, int len) { - dma_addr_t dst = (dma_addr_t)dest; int nsectors = len / conf->ecc_size; u16 rand_seed = 0; - u32 val; - int page; - - page = offs / conf->page_size; + int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; + int page = offs / conf->page_size; + u32 ecc_st; + int i;
if (offs % conf->page_size || len % conf->ecc_size || len > conf->page_size || len < 0) return -EINVAL;
- /* clear ecc status */ - writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); - /* Choose correct seed if randomized */ if (conf->randomize) rand_seed = random_seed[page % conf->nseeds];
- writel((rand_seed << 16) | (conf->ecc_strength << 12) | - (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | - (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | - NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION, - SUNXI_NFC_BASE + NFC_ECC_CTL); - - flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN)); - - /* SUNXI_DMA */ - writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */ - /* read from REG_IO_DATA */ - writel(SUNXI_NFC_BASE + NFC_IO_DATA, - SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0); - /* read to RAM */ - writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0); - writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC | - SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE, - SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0); - writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); - writel(SUNXI_DMA_DDMA_CFG_REG_LOADING | - SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 | - SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM | - SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 | - SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO | - SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC, - SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); - - writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM); - writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); - writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD, - SUNXI_NFC_BASE + NFC_CMD); - - if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG, - DEFAULT_TIMEOUT_US)) { - printf("Error while initializing dma interrupt\n"); - return -EIO; + /* Retrieve data from SRAM (PIO) */ + for (i = 0; i < nsectors; i++) { + int data_off = i * conf->ecc_size; + int oob_off = conf->page_size + (i * oob_chunk_sz); + u8 *data = dest + data_off; + + /* Clear ECC status and restart ECC engine */ + writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); + writel((rand_seed << 16) | (conf->ecc_strength << 12) | + (conf->randomize ? NFC_ECC_RANDOM_EN : 0) | + (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) | + NFC_ECC_EN | NFC_ECC_EXCEPTION, + SUNXI_NFC_BASE + NFC_ECC_CTL); + + /* Move the data in SRAM */ + nand_change_column(data_off); + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); + nand_exec_cmd(NFC_DATA_TRANS); + + /* + * Let the ECC engine consume the ECC bytes and possibly correct + * the data. + */ + nand_change_column(oob_off); + nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD); + + /* Get the ECC status */ + ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST); + + /* ECC error detected. */ + if (ecc_st & 0xffff) + return -EIO; + + /* + * Return 1 if the first chunk is empty (needed for + * configuration detection). + */ + if (!i && (ecc_st & 0x10000)) + return 1; + + /* Retrieve the data from SRAM */ + memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE, + conf->ecc_size); + + /* Stop the ECC engine */ + writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN, + SUNXI_NFC_BASE + NFC_ECC_CTL); + + if (data_off + conf->ecc_size >= len) + break; } - writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0, - SUNXI_DMA_DDMA_CFG_REG_LOADING, - DEFAULT_TIMEOUT_US)) { - printf("Error while waiting for dma transfer to finish\n"); - return -EIO; - } - - invalidate_dcache_range(dst, - ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN)); - - val = readl(SUNXI_NFC_BASE + NFC_ECC_ST); - - /* ECC error detected. */ - if (val & 0xffff) - return -EIO; - - /* - * Return 1 if the page is empty. - * We consider the page as empty if the first ECC block is marked - * empty. - */ - return (val & 0x10000) ? 1 : 0; + return 0; }
static int nand_max_ecc_strength(struct nfc_config *conf)

Code has been changed to do not use DMA anymore with the NAND controller, instead PIO is used. Then, DMA-specific initialization may be dropped.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- board/sunxi/board.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 54ac018b80..59cfddc8e0 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -287,11 +287,6 @@ static void nand_clock_setup(void)
setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0)); -#ifdef CONFIG_MACH_SUN9I - setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); -#else - setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); -#endif setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); }

Add some clocks/PLL definitions and the dependency on MACH_SUN8I in Kconfig so the NAND support in the SPL could be compiled for boards using A33 SoCs.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 6 ++++++ drivers/mtd/nand/Kconfig | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index d328df9597..d35aa479f7 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -192,6 +192,7 @@ struct sunxi_ccm_reg { #define ATB_DIV_1 0 #define ATB_DIV_2 1 #define ATB_DIV_4 2 +#define AHB_DIV_1 0 #define CPU_CLK_SRC_OSC24M 1 #define CPU_CLK_SRC_PLL1 2
@@ -317,6 +318,11 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_LCD0 3 #endif
+#define CCM_NAND_CTRL_M(x) ((x) - 1) +#define CCM_NAND_CTRL_N(x) ((x) << 16) +#define CCM_NAND_CTRL_PLL6 (0x1 << 24) +#define CCM_NAND_CTRL_ENABLE (0x1 << 31) + #define CCM_MMC_CTRL_M(x) ((x) - 1) #define CCM_MMC_CTRL_OCLK_DLY(x) ((x) << 8) #define CCM_MMC_CTRL_N(x) ((x) << 16) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a820af61ce..dcb8ff66ae 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -95,7 +95,7 @@ config NAND_PXA3XX
config NAND_SUNXI bool "Support for NAND on Allwinner SoCs" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I select SYS_NAND_SELF_INIT select SYS_NAND_U_BOOT_LOCATIONS imply CMD_NAND

Hi,
On Thu, Feb 22, 2018 at 02:33:45PM +0100, Miquel Raynal wrote:
Add some clocks/PLL definitions and the dependency on MACH_SUN8I in Kconfig so the NAND support in the SPL could be compiled for boards using A33 SoCs.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
The patch is fine but the title is misleading, this has nothing to do with the SPL, you just allow the driver to be compiled on the sun8i platforms, for both the SPL and U-boot.
Maxime

Let the Nintendo NES Classic use the Macronix NAND chip on it.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- arch/arm/dts/sun8i-a23-a33.dtsi | 18 ++++++++++++++++++ .../arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts | 14 ++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm/dts/sun8i-a23-a33.dtsi b/arch/arm/dts/sun8i-a23-a33.dtsi index ea50dda75a..c0053ad649 100644 --- a/arch/arm/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/dts/sun8i-a23-a33.dtsi @@ -289,6 +289,24 @@ function = "uart1"; };
+ nand_pins_a: nand-base0@0 { + allwinner,pins = "PC0", "PC1", "PC2", + "PC5", "PC8", "PC9", "PC10", + "PC11", "PC12", "PC13", "PC14", + "PC15"; + allwinner,function = "nand0"; + }; + + nand_cs0_pins_a: nand-cs@0 { + allwinner,pins = "PC4"; + allwinner,function = "nand0"; + }; + + nand_rb0_pins_a: nand-rb@0 { + allwinner,pins = "PC6"; + allwinner,function = "nand0"; + }; + mmc0_pins_a: mmc0@0 { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; diff --git a/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts b/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts index dce688ec8e..72a8505d94 100644 --- a/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts +++ b/arch/arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts @@ -61,3 +61,17 @@ pinctrl-0 = <&uart0_pins_a>; status = "okay"; }; + +&nfc { + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; + status = "okay"; + + nand@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + allwinner,rb = <0>; + nand-ecc-mode = "hw"; + }; +};

Hi,
On Thu, Feb 22, 2018 at 02:33:46PM +0100, Miquel Raynal wrote:
Let the Nintendo NES Classic use the Macronix NAND chip on it.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
arch/arm/dts/sun8i-a23-a33.dtsi | 18 ++++++++++++++++++ .../arm/dts/sun8i-r16-nintendo-nes-classic-edition.dts | 14 ++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/arm/dts/sun8i-a23-a33.dtsi b/arch/arm/dts/sun8i-a23-a33.dtsi index ea50dda75a..c0053ad649 100644 --- a/arch/arm/dts/sun8i-a23-a33.dtsi +++ b/arch/arm/dts/sun8i-a23-a33.dtsi @@ -289,6 +289,24 @@ function = "uart1"; };
nand_pins_a: nand-base0@0 {
allwinner,pins = "PC0", "PC1", "PC2",
"PC5", "PC8", "PC9", "PC10",
"PC11", "PC12", "PC13", "PC14",
"PC15";
allwinner,function = "nand0";
};
nand_cs0_pins_a: nand-cs@0 {
allwinner,pins = "PC4";
allwinner,function = "nand0";
};
nand_rb0_pins_a: nand-rb@0 {
allwinner,pins = "PC6";
allwinner,function = "nand0";
};
This is the old-style binding that is now deprecated, you should favour the new one (with function and pins instead of allwinner,function and allwinner,pins).
The indentation of the nand pins in your first group is weird too.
Maxime

Make SUNXI_NAND select SPL_NAND_SUPPORT in Kconfig, this limit the number of entries to add in defconfig files when adding NAND support.
For now, the only board using it is the CHIP pro.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- configs/CHIP_pro_defconfig | 1 - drivers/mtd/nand/Kconfig | 1 + 2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig index a98bb40c03..5e5fae9a36 100644 --- a/configs/CHIP_pro_defconfig +++ b/configs/CHIP_pro_defconfig @@ -1,7 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_SUNXI=y CONFIG_SYS_TEXT_BASE=0x4a000000 -CONFIG_SPL_NAND_SUPPORT=y CONFIG_MACH_SUN5I=y CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y CONFIG_USB0_VBUS_PIN="PB10" diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dcb8ff66ae..75eefc8a2b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -98,6 +98,7 @@ config NAND_SUNXI depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I select SYS_NAND_SELF_INIT select SYS_NAND_U_BOOT_LOCATIONS + select SPL_NAND_SUPPORT imply CMD_NAND ---help--- Enable support for NAND. This option enables the standard and

On Thu, Feb 22, 2018 at 02:33:47PM +0100, Miquel Raynal wrote:
Make SUNXI_NAND select SPL_NAND_SUPPORT in Kconfig, this limit the number of entries to add in defconfig files when adding NAND support.
For now, the only board using it is the CHIP pro.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Maxime

Remove NAND_SUNXI from the CHIP pro defconfig to be automatically selected depending on the state of ARCH_SUNXI.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- configs/CHIP_pro_defconfig | 1 - drivers/mtd/nand/Kconfig | 1 + 2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig index 5e5fae9a36..75951bf03b 100644 --- a/configs/CHIP_pro_defconfig +++ b/configs/CHIP_pro_defconfig @@ -16,7 +16,6 @@ CONFIG_ENV_UBI_PART="UBI" CONFIG_ENV_UBI_VOLUME="uboot-env" # CONFIG_MMC is not set CONFIG_NAND=y -CONFIG_NAND_SUNXI=y CONFIG_AXP_ALDO3_VOLT=3300 CONFIG_AXP_ALDO4_VOLT=3300 CONFIG_USB_EHCI_HCD=y diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 75eefc8a2b..cf323c5348 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -95,6 +95,7 @@ config NAND_PXA3XX
config NAND_SUNXI bool "Support for NAND on Allwinner SoCs" + default ARCH_SUNXI depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I select SYS_NAND_SELF_INIT select SYS_NAND_U_BOOT_LOCATIONS

On Thu, Feb 22, 2018 at 02:33:48PM +0100, Miquel Raynal wrote:
Remove NAND_SUNXI from the CHIP pro defconfig to be automatically selected depending on the state of ARCH_SUNXI.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Thanks! Maxime

Move the NAND parameters from defconfig files to Kconfig for SUNXI architecture only. Fort now only the CHIP pro is migrated.
It would have been better to convert this defconfig entry to Kconfig for all supported machines/architectures but it has been abandoned due to a fairly high amount of errors reported by the moveconfig.py tool. This is probably due to defines quite often being multiplications of values/other defines not correctly handled.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- configs/CHIP_pro_defconfig | 4 +++- drivers/mtd/nand/Kconfig | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig index 75951bf03b..9f682239bf 100644 --- a/configs/CHIP_pro_defconfig +++ b/configs/CHIP_pro_defconfig @@ -5,7 +5,9 @@ CONFIG_MACH_SUN5I=y CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y CONFIG_USB0_VBUS_PIN="PB10" CONFIG_DEFAULT_DEVICE_TREE="sun5i-gr8-chip-pro" -CONFIG_SYS_EXTRA_OPTIONS="SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256" +CONFIG_SYS_NAND_BLOCK_SIZE=0x40000 +CONFIG_SYS_NAND_OOBSIZE=0x1000 +CONFIG_SYS_NAND_OOBSIZE=0x100 CONFIG_SPL=y CONFIG_SPL_I2C_SUPPORT=y # CONFIG_CMD_FLASH is not set diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index cf323c5348..fc930a804c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -168,6 +168,28 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
comment "Generic NAND options"
+config SYS_NAND_BLOCK_SIZE + hex "NAND chip eraseblock size" + depends on ARCH_SUNXI + help + Number of data bytes in one eraseblock for the NAND chip on the + board. This is the multiple of NAND_PAGE_SIZE and the number of + pages. + +config SYS_NAND_PAGE_SIZE + hex "NAND chip page size" + depends on ARCH_SUNXI + help + Number of data bytes in one page for the NAND chip on the + board, not including the OOB area. + +config SYS_NAND_OOBSIZE + hex "NAND chip OOB size" + depends on ARCH_SUNXI + help + Number of bytes in the Out-Of-Band area for the NAND chip on + the board. + # Enhance depends when converting drivers to Kconfig which use this config # option (mxc_nand, ndfc, omap_gpmc). config SYS_NAND_BUSWIDTH_16BIT

On Thu, Feb 22, 2018 at 02:33:49PM +0100, Miquel Raynal wrote:
Move the NAND parameters from defconfig files to Kconfig for SUNXI architecture only. Fort now only the CHIP pro is migrated.
It would have been better to convert this defconfig entry to Kconfig for all supported machines/architectures but it has been abandoned due to a fairly high amount of errors reported by the moveconfig.py tool. This is probably due to defines quite often being multiplications of values/other defines not correctly handled.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
configs/CHIP_pro_defconfig | 4 +++- drivers/mtd/nand/Kconfig | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig index 75951bf03b..9f682239bf 100644 --- a/configs/CHIP_pro_defconfig +++ b/configs/CHIP_pro_defconfig @@ -5,7 +5,9 @@ CONFIG_MACH_SUN5I=y CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y CONFIG_USB0_VBUS_PIN="PB10" CONFIG_DEFAULT_DEVICE_TREE="sun5i-gr8-chip-pro" -CONFIG_SYS_EXTRA_OPTIONS="SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256" +CONFIG_SYS_NAND_BLOCK_SIZE=0x40000 +CONFIG_SYS_NAND_OOBSIZE=0x1000 +CONFIG_SYS_NAND_OOBSIZE=0x100 CONFIG_SPL=y CONFIG_SPL_I2C_SUPPORT=y # CONFIG_CMD_FLASH is not set diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index cf323c5348..fc930a804c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -168,6 +168,28 @@ config NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
comment "Generic NAND options"
+config SYS_NAND_BLOCK_SIZE
hex "NAND chip eraseblock size"
depends on ARCH_SUNXI
help
Number of data bytes in one eraseblock for the NAND chip on the
board. This is the multiple of NAND_PAGE_SIZE and the number of
pages.
The indentation here ...
+config SYS_NAND_PAGE_SIZE
hex "NAND chip page size"
depends on ARCH_SUNXI
help
Number of data bytes in one page for the NAND chip on the
board, not including the OOB area.
... and here ...
+config SYS_NAND_OOBSIZE
hex "NAND chip OOB size"
depends on ARCH_SUNXI
help
Number of bytes in the Out-Of-Band area for the NAND chip on
the board.
... but you somehow got it right here :)
Otherwise, Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Thanks! Maxime

Add NAND parameters to the Nintendo NES Classic configuration file which features a Macronix NAND flash chip with 128kiB blocks of 2kiB pages plus 64 OOB bytes.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com --- configs/Nintendo_NES_Classic_Edition_defconfig | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/configs/Nintendo_NES_Classic_Edition_defconfig b/configs/Nintendo_NES_Classic_Edition_defconfig index 2be724425c..0af53f2dd9 100644 --- a/configs/Nintendo_NES_Classic_Edition_defconfig +++ b/configs/Nintendo_NES_Classic_Edition_defconfig @@ -10,6 +10,10 @@ CONFIG_AXP_GPIO=y CONFIG_DEFAULT_DEVICE_TREE="sun8i-r16-nintendo-nes-classic-edition" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL=y +CONFIG_NAND=y +CONFIG_SYS_NAND_BLOCK_SIZE=0x20000 +CONFIG_SYS_NAND_PAGE_SIZE=0x800 +CONFIG_SYS_NAND_OOBSIZE=0x40 # CONFIG_CMD_FLASH is not set # CONFIG_SPL_DOS_PARTITION is not set # CONFIG_SPL_ISO_PARTITION is not set

On Thu, Feb 22, 2018 at 02:33:50PM +0100, Miquel Raynal wrote:
Add NAND parameters to the Nintendo NES Classic configuration file which features a Macronix NAND flash chip with 128kiB blocks of 2kiB pages plus 64 OOB bytes.
Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com
Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Thanks! Maxime

On Thu, 22 Feb 2018 14:33:30 +0100 Miquel Raynal miquel.raynal@bootlin.com wrote:
Hello,
This series first adds fixes and enhancements to sunxi NAND drivers (SPL and U-Boot). Once this is done, the SPL NAND driver is converted to use PIO instead of DMA with the goal to support all SoCs with this IP without the need for DMA-related code. Finally, NAND support is added to Nintendo NES Classic through Kconfig and DT additions.
Thanks, Miquèl
Changes since v1:
All:
- Enhance all commit messages.
- Rebased on top of master branch (I should have done that earlier but I forgot I was on an old revision).
Fix binman_sym output check
- SPL seems to be broken for a few weeks when using raw NAND, fix it by changing the error condition.
Fix strength
- Add comment explaining the added line and moved the line for clarification on why it is needed.
- Add forgotten Boris' Suggested-by tag.
Fix second case of modulo by zero error
- Added a reference to the first occurence of this issue.
Allow SPL to be compiled for sun8i platforms
- This commit is not about compiling the SPL, but the NAND support in the SPL, as corrected by Maxime.
Enhancements and cleaning
- Patch split into several logical chunks, as requested.
- Removed useless udelay(1), that was added for debugging purpose.
- Introduced the nand_exec_cmd() helper to mutualize code one step further.
- Add an udelay(1) after changing the column to respect the minimum tCCS delay (Change Column Setup time).
- Canceled moving to global scope the ecc_strength array.
Use PIO instead of DMA
- Change commit message/title.
- Cancel removing NFC related definitions: they can be useful as the this IP is quite under-documented.
- Merge nand_reset_column and nand_change_column (in another patch).
- Moved the copy of the data after the check of the ECC status.
- ECC chunks are read manually, return if the first chunk is empty only (needed for configuration research), otherwise it should not be treated as an error.
Add NAND node to sun8i
- U-Boot master branch already has this node, remove the patch.
Enable NAND on NES classic
- Change the DT cells size from 2 to 1.
Add NAND support for NES classic
- Split in several patches, moving SPL_NAND_SUPPORT and NAND_SUNXI out of the defconfig files (NES and CHIP pro) to be automatically selected depending on NAND_SUNXI and ARCH_SUNXI.
- Moved the NAND parameters to Kconfig (only for SUNXI because the tool did not work as expected, maybe due to some definitions that are not "numbers" but multiplications and sometimes use other definitions (NAND page size, 2K_SZ, etc).
Miquel Raynal (20): spl: fix binman_sym output check mtd: nand: sunxi: fix ECC strength choice spl: nand: sunxi: fix second case of modulo by zero error spl: nand: sunxi: fix typo on register name spl: nand: sunxi: introduce the nand_wait_int() helper spl: nand: sunxi: introduce the nand_wait_cmd_fifo_empty() helper spl: nand: sunxi: add missing status clear spl: nand: sunxi: create an helper to handle command execution spl: nand: sunxi: ensure enough time has passed after changing the column spl: nand: sunxi: make the reset column helper more generic sunxi: spl: deassert the NAND controller reset line spl: nand: sunxi: declare the ecc_bytes array globally spl: nand: sunxi: use PIO instead of DMA sunxi: spl: remove DMA related settings of the NAND controller sunxi: allow NAND support in SPL to be compiled for sun8i platforms sunxi: dts: enable NAND on NES classic sunxi: automatically select SPL_NAND_SUPPORT in Kconfig sunxi: make NAND_SUNXI use ARCH_SUNXI as default in Kconfig sunxi: move the NAND parameters to Kconfig configs: add NAND support for NES Classic
Acked-by: Boris Brezillon boris.brezillon@bootlin.com
on all NAND related patches.
arch/arm/dts/sun8i-a23-a33.dtsi | 18 ++ .../dts/sun8i-r16-nintendo-nes-classic-edition.dts | 14 ++ arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 6 + board/sunxi/board.c | 6 +- common/spl/spl.c | 10 +- configs/CHIP_pro_defconfig | 6 +- configs/Nintendo_NES_Classic_Edition_defconfig | 4 + drivers/mtd/nand/Kconfig | 26 ++- drivers/mtd/nand/sunxi_nand.c | 8 +- drivers/mtd/nand/sunxi_nand_spl.c | 242 ++++++++++----------- 10 files changed, 206 insertions(+), 134 deletions(-)

On Thu, 22 Feb 2018 15:06:19 +0100 Boris Brezillon boris.brezillon@bootlin.com wrote:
On Thu, 22 Feb 2018 14:33:30 +0100 Miquel Raynal miquel.raynal@bootlin.com wrote:
Hello,
This series first adds fixes and enhancements to sunxi NAND drivers (SPL and U-Boot). Once this is done, the SPL NAND driver is converted to use PIO instead of DMA with the goal to support all SoCs with this IP without the need for DMA-related code. Finally, NAND support is added to Nintendo NES Classic through Kconfig and DT additions.
Thanks, Miquèl
Changes since v1:
All:
- Enhance all commit messages.
- Rebased on top of master branch (I should have done that earlier but I forgot I was on an old revision).
Fix binman_sym output check
- SPL seems to be broken for a few weeks when using raw NAND, fix it by changing the error condition.
Fix strength
- Add comment explaining the added line and moved the line for clarification on why it is needed.
- Add forgotten Boris' Suggested-by tag.
Fix second case of modulo by zero error
- Added a reference to the first occurence of this issue.
Allow SPL to be compiled for sun8i platforms
- This commit is not about compiling the SPL, but the NAND support in the SPL, as corrected by Maxime.
Enhancements and cleaning
- Patch split into several logical chunks, as requested.
- Removed useless udelay(1), that was added for debugging purpose.
- Introduced the nand_exec_cmd() helper to mutualize code one step further.
- Add an udelay(1) after changing the column to respect the minimum tCCS delay (Change Column Setup time).
- Canceled moving to global scope the ecc_strength array.
Use PIO instead of DMA
- Change commit message/title.
- Cancel removing NFC related definitions: they can be useful as the this IP is quite under-documented.
- Merge nand_reset_column and nand_change_column (in another patch).
- Moved the copy of the data after the check of the ECC status.
- ECC chunks are read manually, return if the first chunk is empty only (needed for configuration research), otherwise it should not be treated as an error.
Add NAND node to sun8i
- U-Boot master branch already has this node, remove the patch.
Enable NAND on NES classic
- Change the DT cells size from 2 to 1.
Add NAND support for NES classic
- Split in several patches, moving SPL_NAND_SUPPORT and NAND_SUNXI out of the defconfig files (NES and CHIP pro) to be automatically selected depending on NAND_SUNXI and ARCH_SUNXI.
- Moved the NAND parameters to Kconfig (only for SUNXI because the tool did not work as expected, maybe due to some definitions that are not "numbers" but multiplications and sometimes use other definitions (NAND page size, 2K_SZ, etc).
Miquel Raynal (20): spl: fix binman_sym output check mtd: nand: sunxi: fix ECC strength choice spl: nand: sunxi: fix second case of modulo by zero error spl: nand: sunxi: fix typo on register name spl: nand: sunxi: introduce the nand_wait_int() helper spl: nand: sunxi: introduce the nand_wait_cmd_fifo_empty() helper spl: nand: sunxi: add missing status clear spl: nand: sunxi: create an helper to handle command execution spl: nand: sunxi: ensure enough time has passed after changing the column spl: nand: sunxi: make the reset column helper more generic sunxi: spl: deassert the NAND controller reset line spl: nand: sunxi: declare the ecc_bytes array globally spl: nand: sunxi: use PIO instead of DMA sunxi: spl: remove DMA related settings of the NAND controller sunxi: allow NAND support in SPL to be compiled for sun8i platforms sunxi: dts: enable NAND on NES classic sunxi: automatically select SPL_NAND_SUPPORT in Kconfig sunxi: make NAND_SUNXI use ARCH_SUNXI as default in Kconfig sunxi: move the NAND parameters to Kconfig configs: add NAND support for NES Classic
Acked-by: Boris Brezillon boris.brezillon@bootlin.com
on all NAND related patches.
I've been told that my statement was a bit ambiguous since all patches in this series are related to supporting NAND on sun8i, so I'll clarify a bit. My ack applies to all patches containing 'nand' in their subject :P.
arch/arm/dts/sun8i-a23-a33.dtsi | 18 ++ .../dts/sun8i-r16-nintendo-nes-classic-edition.dts | 14 ++ arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 6 + board/sunxi/board.c | 6 +- common/spl/spl.c | 10 +- configs/CHIP_pro_defconfig | 6 +- configs/Nintendo_NES_Classic_Edition_defconfig | 4 + drivers/mtd/nand/Kconfig | 26 ++- drivers/mtd/nand/sunxi_nand.c | 8 +- drivers/mtd/nand/sunxi_nand_spl.c | 242 ++++++++++----------- 10 files changed, 206 insertions(+), 134 deletions(-)
participants (4)
-
Boris Brezillon
-
Maxime Ripard
-
Miquel Raynal
-
Wolfgang Denk