[U-Boot] [PATCH v3 0/4] sunxi: nand: Basic NAND driver for SPL

This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Changes in v3: - moved pinmux and clock to board level - code cleanup with significant size reduction - renamed the driver file - renamed constants to match Kconfig convention - moved defines from .h to .c, and renamed them to be consistent with each other - removed more magic values - changed ecc_errors from static to local variable - other minor changes - added new options in Kconfig to support different chips - changed descriptions to comply with patman rules
Changes in v2: - removed traces of non-SPL-specific code - moved the driver from boards/sunxi to drivers/mtd/nand - moved magic values to defines (whenever possible) - removed unnecesary late initialisation code - code style changes as suggested for the first patch set: - changed visibility of some symbols - renamed unclear variables - renamed header protector - changed types of pointer variables - other minor changes - removed traces of non-SPL specific code - renamed defines to be more relevant - moved Kconfig entry for the driver to drivers/mtd/nand - reworded Kconfig entry help
Karol Gugala (1): sunxi: nand: Add pinmux and clock settings for NAND support
Piotr Zierhoffer (3): sunxi: nand: Add basic sunxi NAND driver for SPL with DMA support sunxi: nand: Add board configuration options sunxi: nand: Add information to sunxi that it was run from NAND in SPL
arch/arm/cpu/armv7/sunxi/board.c | 4 + arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 2 + arch/arm/include/asm/arch-sunxi/gpio.h | 1 + board/sunxi/board.c | 27 ++ drivers/mtd/nand/Kconfig | 40 +++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand_spl.c | 353 ++++++++++++++++++++++++++ include/configs/sunxi-common.h | 10 + 8 files changed, 438 insertions(+) create mode 100644 drivers/mtd/nand/sunxi_nand_spl.c

From: Karol Gugala kgugala@antmicro.com
To enable NAND flash in sunxi SPL, pins 0-6, 8-22 and 24 on port C are configured.
Signed-off-by: Karol Gugala kgugala@antmicro.com Signed-off-by: Piotr Zierhoffer pzierhoffer@antmicro.com ---
Changes in v3: - moved pinmux and clock to board level - code cleanup with significant size reduction
Changes in v2: None
arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 2 ++ arch/arm/include/asm/arch-sunxi/gpio.h | 1 + board/sunxi/board.c | 27 +++++++++++++++++++++++++++ 3 files changed, 30 insertions(+)
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h index 58aff16..01d3e28 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h @@ -267,6 +267,8 @@ struct sunxi_ccm_reg { #define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2 #define CCM_MBUS_CTRL_GATE (0x1 << 31)
+#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/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 8e67b3b..8382101 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -158,6 +158,7 @@ enum sunxi_gpio_number { #define SUN8I_GPB_UART2 2 #define SUN8I_A33_GPB_UART0 3
+#define SUNXI_GPC_NAND 2 #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index ed60e74..096b5c3 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -108,6 +108,28 @@ int dram_init(void) return 0; }
+#if defined(CONFIG_SPL_NAND_SUNXI) && defined(CONFIG_SPL_BUILD) +static void nand_pinmux_setup(void) +{ + unsigned int pin; + for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(6); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND); + + for (pin = SUNXI_GPC(8); pin <= SUNXI_GPC(22); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND); + + sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_NAND); +} + +static void nand_clock_setup(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); + setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); +} +#endif + #ifdef CONFIG_GENERIC_MMC static void mmc_pinmux_setup(int sdc) { @@ -434,6 +456,11 @@ void sunxi_board_init(void) power_failed |= axp221_set_eldo(3, CONFIG_AXP221_ELDO3_VOLT); #endif
+#ifdef CONFIG_SPL_NAND_SUNXI + nand_pinmux_setup(); + nand_clock_setup(); +#endif + printf("DRAM:"); ramsize = sunxi_dram_init(); printf(" %lu MiB\n", ramsize >> 20);

This driver adds NAND support to SPL. It was tested on Allwinner A20.
Signed-off-by: Peter Gielda pgielda@antmicro.com Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com Signed-off-by: Mateusz Holenko mholenko@antmicro.com Signed-off-by: Piotr Zierhoffer pzierhoffer@antmicro.com Signed-off-by: Karol Gugala kgugala@antmicro.com ---
Changes in v3: - renamed the driver file - renamed constants to match Kconfig convention - moved defines from .h to .c, and renamed them to be consistent with each other - removed more magic values - changed ecc_errors from static to local variable - other minor changes
Changes in v2: - removed traces of non-SPL-specific code - moved the driver from boards/sunxi to drivers/mtd/nand - moved magic values to defines (whenever possible) - removed unnecesary late initialisation code - code style changes as suggested for the first patch set: - changed visibility of some symbols - renamed unclear variables - renamed header protector - changed types of pointer variables - other minor changes
drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand_spl.c | 353 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 drivers/mtd/nand/sunxi_nand_spl.c
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 347ea62..b40dda8 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -12,6 +12,7 @@ NORMAL_DRIVERS=y endif
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o +obj-$(CONFIG_SPL_NAND_SUNXI) += sunxi_nand_spl.o obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c new file mode 100644 index 0000000..ac5f56d --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com> + * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <nand.h> + +/* registers */ +#define NFC_CTL 0x00000000 +#define NFC_ST 0x00000004 +#define NFC_INT 0x00000008 +#define NFC_TIMING_CTL 0x0000000C +#define NFC_TIMING_CFG 0x00000010 +#define NFC_ADDR_LOW 0x00000014 +#define NFC_ADDR_HIGH 0x00000018 +#define NFC_SECTOR_NUM 0x0000001C +#define NFC_CNT 0x00000020 +#define NFC_CMD 0x00000024 +#define NFC_RCMD_SET 0x00000028 +#define NFC_WCMD_SET 0x0000002C +#define NFC_IO_DATA 0x00000030 +#define NFC_ECC_CTL 0x00000034 +#define NFC_ECC_ST 0x00000038 +#define NFC_DEBUG 0x0000003C +#define NFC_ECC_CNT0 0x00000040 +#define NFC_ECC_CNT1 0x00000044 +#define NFC_ECC_CNT2 0x00000048 +#define NFC_ECC_CNT3 0x0000004C +#define NFC_USER_DATA_BASE 0x00000050 +#define NFC_EFNAND_STATUS 0x00000090 +#define NFC_SPARE_AREA 0x000000A0 +#define NFC_PATTERN_ID 0x000000A4 +#define NFC_RAM0_BASE 0x00000400 +#define NFC_RAM1_BASE 0x00000800 + +#define NFC_CTL_EN (1 << 0) +#define NFC_CTL_RESET (1 << 1) +#define NFC_CTL_RAM_METHOD (1 << 14) + + +#define NFC_ECC_EN (1 << 0) +#define NFC_ECC_PIPELINE (1 << 3) +#define NFC_ECC_EXCEPTION (1 << 4) +#define NFC_ECC_BLOCK_SIZE (1 << 5) +#define NFC_ECC_RANDOM_EN (1 << 9) +#define NFC_ECC_RANDOM_DIRECTION (1 << 10) + + +#define NFC_ADDR_NUM_OFFSET 16 +#define NFC_SEND_ADR (1 << 19) +#define NFC_ACCESS_DIR (1 << 20) +#define NFC_DATA_TRANS (1 << 21) +#define NFC_SEND_CMD1 (1 << 22) +#define NFC_WAIT_FLAG (1 << 23) +#define NFC_SEND_CMD2 (1 << 24) +#define NFC_SEQ (1 << 25) +#define NFC_DATA_SWAP_METHOD (1 << 26) +#define NFC_ROW_AUTO_INC (1 << 27) +#define NFC_SEND_CMD3 (1 << 28) +#define NFC_SEND_CMD4 (1 << 29) + +#define NFC_CMD_INT_FLAG (1 << 1) + +#define NFC_READ_CMD_OFFSET 0 +#define NFC_RANDOM_READ_CMD0_OFFSET 8 +#define NFC_RANDOM_READ_CMD1_OFFSET 16 + +#define NFC_CMD_RNDOUTSTART 0xE0 +#define NFC_CMD_RNDOUT 0x05 +#define NFC_CMD_READSTART 0x30 + + +#define NFC_PAGE_CMD (2 << 30) + +#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_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) + +/* minimal "boot0" style NAND support for Allwinner A20 */ + +/* temporary buffer in internal ram */ +unsigned char temp_buf[CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE] + __aligned(0x10) __section(".text#"); + +/* random seed used by linux */ +const uint16_t random_seed[128] = { + 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, + 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, + 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, + 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, + 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, + 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, + 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, + 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, + 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, + 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, + 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, + 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, + 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, + 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, + 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, + 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, +}; + +/* random seed used for syndrome calls */ +const uint16_t random_seed_syndrome = 0x4a80; + +#define MAX_RETRIES 10 + +static int check_value_inner(int offset, int expected_bits, + int max_number_of_retries, int negation) +{ + int retries = 0; + do { + int val = readl(offset) & expected_bits; + if (negation ? !val : val) + return 1; + mdelay(1); + retries++; + } while (retries < max_number_of_retries); + + return 0; +} + +static inline int check_value(int offset, int expected_bits, + int max_number_of_retries) +{ + return check_value_inner(offset, expected_bits, + max_number_of_retries, 0); +} + +static inline int check_value_negated(int offset, int unexpected_bits, + int max_number_of_retries) +{ + return check_value_inner(offset, unexpected_bits, + max_number_of_retries, 1); +} + +void nand_init(void) +{ + uint32_t val; + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + /* enable and reset CTL */ + writel(val | NFC_CTL_EN | NFC_CTL_RESET, + SUNXI_NFC_BASE + NFC_CTL); + + if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL, + NFC_CTL_RESET, MAX_RETRIES)) { + printf("Couldn't initialize nand\n"); + } +} + +static void nand_read_page(unsigned int real_addr, int syndrome, + uint32_t *ecc_errors) +{ + uint32_t val; + int ecc_off = 0; + uint16_t ecc_mode = 0; + uint16_t rand_seed; + uint32_t page; + uint16_t column; + uint32_t oob_offset; + + switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) { + case 16: + ecc_mode = 0; + ecc_off = 0x20; + break; + case 24: + ecc_mode = 1; + ecc_off = 0x2e; + break; + case 28: + ecc_mode = 2; + ecc_off = 0x32; + break; + case 32: + ecc_mode = 3; + ecc_off = 0x3c; + break; + case 40: + ecc_mode = 4; + ecc_off = 0x4a; + break; + case 48: + ecc_mode = 4; + ecc_off = 0x52; + break; + case 56: + ecc_mode = 4; + ecc_off = 0x60; + break; + case 60: + ecc_mode = 4; + ecc_off = 0x0; + break; + case 64: + ecc_mode = 4; + ecc_off = 0x0; + break; + default: + ecc_mode = 0; + ecc_off = 0; + } + + if (ecc_off == 0) { + printf("Unsupported ECC strength (%d)!\n", + CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH); + return; + } + + /* clear temp_buf */ + memset(temp_buf, 0, CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE); + + /* set CMD */ + writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, + SUNXI_NFC_BASE + NFC_CMD); + + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG, + MAX_RETRIES)) { + printf("Error while initilizing command interrupt\n"); + return; + } + + page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; + column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; + + if (syndrome) + column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + * ecc_off; + + /* clear ecc status */ + writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); + + /* Choose correct seed */ + if (syndrome) + rand_seed = random_seed_syndrome; + else + rand_seed = random_seed[page % 128]; + + writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN + | NFC_ECC_PIPELINE | (ecc_mode << 12), + SUNXI_NFC_BASE + NFC_ECC_CTL); + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL); + + if (syndrome) { + writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + SUNXI_NFC_BASE + NFC_SPARE_AREA); + } else { + oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE + + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + * ecc_off; + writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA); + } + + /* 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((uint32_t)temp_buf, + 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(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */ + writel(SUNXI_DMA_DDMA_CFG_REG_LOADING + | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 + | 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((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(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM); + writel(((page & 0xFFFF) << 16) | column, + SUNXI_NFC_BASE + NFC_ADDR_LOW); + writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); + writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS | + NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) | + NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0), + SUNXI_NFC_BASE + NFC_CMD); + + if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2), + MAX_RETRIES)) { + printf("Error while initializing dma interrupt\n"); + return; + } + + if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0, + SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) { + printf("Error while waiting for dma transfer to finish\n"); + return; + } + + if (readl(SUNXI_NFC_BASE + NFC_ECC_ST)) + (*ecc_errors)++; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + void *current_dest; + uint32_t count; + uint32_t current_count; + uint32_t ecc_errors = 0; + + memset(dest, 0x0, size); /* clean destination memory */ + for (current_dest = dest; + current_dest < (dest + size); + current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) { + nand_read_page(offs, offs + < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END, + &ecc_errors); + count = current_dest - dest; + + if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE; + else + current_count = size - count; + + memcpy(current_dest, + temp_buf, + current_count); + offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE; + } + return ecc_errors ? -1 : 0; +} + +void nand_deselect(void) {}

On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
-Scott

Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
What we should do (in a follow up patch) is run some sanity checks (checksum of the image, etc.) and retry at a different offset if that fails. This is also what the bootrom does for loading the SPL itself, it simply tries to read it at a number of fixed addresses at the beginningen of the nand, so we should do the same looking for u-boot.bin at those same addresses (taking into account that u-boot.bin will be written after the SPL).
Regards,
Hans
-Scott

Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
What we should do (in a follow up patch) is run some sanity checks (checksum of the image, etc.) and retry at a different offset if that fails. This is also what the bootrom does for loading the SPL itself, it simply tries to read it at a number of fixed addresses at the beginningen of the nand, so we should do the same looking for u-boot.bin at those same addresses (taking into account that u-boot.bin will be written after the SPL).
Yes that's a solution: putting the u-boot binary in 2 (or more) distinct blocks (and maybe we should also repeat it over a given block to be more robust against bitflips) should address the case where the main u-boot block becomes bad.
Best Regards,
Boris

On 31 July 2015 at 11:24, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
Not on Allwinner hardware. Allwinner tools write data to the nand which looks like bad block markers so skipping blocks which appear marked as bad will inevitably skip valid blocks on many (most ?) Allwinner devices.
Only in the case you soldered a new nand chip yourself and never used Allwinner tools with it will the bad block markers remain valid. This is overall very unlikely so it should not be something SPL handles.
If you build custom devices and write devicetree for them then adding an option there might be worthwhile.
Thanks
Michal

Hi,
On 31-07-15 16:25, Michal Suchanek wrote:
On 31 July 2015 at 11:24, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
Not on Allwinner hardware. Allwinner tools write data to the nand which looks like bad block markers so skipping blocks which appear marked as bad will inevitably skip valid blocks on many (most ?) Allwinner devices.
Right this has been my observation as well.
Only in the case you soldered a new nand chip yourself and never used Allwinner tools with it will the bad block markers remain valid. This is overall very unlikely so it should not be something SPL handles.
Or if you've some device where the nand was not initialized from the factory, I think some Olinuxino devices with nand fall into this category.
I agree that is best to simply ignore bad block markers on sunxi though, as they tend to lead to many false positives (think 60% of the entire nand consisting of bad blocks in my experience)
Regards,
Hans

Hi Michal,
On Fri, 31 Jul 2015 16:25:00 +0200 Michal Suchanek hramrach@gmail.com wrote:
On 31 July 2015 at 11:24, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
Not on Allwinner hardware. Allwinner tools write data to the nand which looks like bad block markers so skipping blocks which appear marked as bad will inevitably skip valid blocks on many (most ?) Allwinner devices.
First of all, that's not exactly true. The allwinner NAND layer (and probably the tools allowing you to flash a new image) is actually writing the appropriate good block pattern (0xff), but this pattern is then randomized by the hardware randomizer, which makes it look like a bad block (!= 0xff).
The other aspect is, do we really have to support images flashed with this tool? I mean, I'm flashing my images using fel and a standard u-boot, and they generate perfectly valid images with valid bad block markers.
Only in the case you soldered a new nand chip yourself and never used Allwinner tools with it will the bad block markers remain valid. This is overall very unlikely so it should not be something SPL handles.
Here you're talking about the bad block markers 'corrupted' by the libnand layer (or the flashing tool). To restore valid bad block markers you just have to launch nand scrub in u-boot. I'm also thinking about a way to retrieve the real bad blocks even when the NAND has been used with an allwinner kernel (the idea is to first check without the randomizer disabled, and if it does not return 0xff, try to enable the randomizer, then if it still does not return 0xff, it's a real bad block).
But unless we want to support both mainline and non-mainline systems using the same SPL, that aspect is just something that should be handled when your moving from an allwinner image to a mainline one.
Best Regards,
Boris

On 31 July 2015 at 16:41, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Michal,
On Fri, 31 Jul 2015 16:25:00 +0200 Michal Suchanek hramrach@gmail.com wrote:
On 31 July 2015 at 11:24, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
< CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
Not on Allwinner hardware. Allwinner tools write data to the nand which looks like bad block markers so skipping blocks which appear marked as bad will inevitably skip valid blocks on many (most ?) Allwinner devices.
First of all, that's not exactly true. The allwinner NAND layer (and probably the tools allowing you to flash a new image) is actually writing the appropriate good block pattern (0xff), but this pattern is then randomized by the hardware randomizer, which makes it look like a bad block (!= 0xff).
The other aspect is, do we really have to support images flashed with this tool? I mean, I'm flashing my images using fel and a standard u-boot, and they generate perfectly valid images with valid bad block markers.
If u-boot takes into account the broken bad block markers generated by Allwinner tools it will make perfectly unusable image with invalid bad block markers.
I tried flashing my image by booting Linux from SD card and formatting the nand and it certainly did not go well with some past version of the driver.
Only in the case you soldered a new nand chip yourself and never used Allwinner tools with it will the bad block markers remain valid. This is overall very unlikely so it should not be something SPL handles.
Here you're talking about the bad block markers 'corrupted' by the libnand layer (or the flashing tool). To restore valid bad block markers you just have to launch nand scrub in u-boot. I'm also thinking about a way to retrieve the real bad blocks even when the NAND has been used with an allwinner kernel (the idea is to first check without the randomizer disabled, and if it does not return 0xff, try to enable the randomizer, then if it still does not return 0xff, it's a real bad block).
That would be good if it just detected bad blocks whatever format the flash was in previously.
But unless we want to support both mainline and non-mainline systems using the same SPL, that aspect is just something that should be handled when your moving from an allwinner image to a mainline one.
We probably want to support no-nonsense reimaging regardless of the previous nand content. You cannot expect users to track what they used last to flash their device.
Thanks
Michal

On Fri, 2015-07-31 at 16:41 +0200, Boris Brezillon wrote:
Hi Michal,
On Fri, 31 Jul 2015 16:25:00 +0200 Michal Suchanek hramrach@gmail.com wrote:
On 31 July 2015 at 11:24, Boris Brezillon boris.brezillon@free-electrons.com wrote:
Hi Hans,
On Fri, 31 Jul 2015 10:36:43 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 31-07-15 02:47, Scott Wood wrote:
On Thu, 2015-07-23 at 14:33 +0200, Piotr Zierhoffer wrote:
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
void *current_dest;
uint32_t count;
uint32_t current_count;
uint32_t ecc_errors = 0;
memset(dest, 0x0, size); /* clean destination memory */
for (current_dest = dest;
current_dest < (dest + size);
current_dest +=
CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) {
nand_read_page(offs, offs
<
CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END,
&ecc_errors);
count = current_dest - dest;
if (size - count >
CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE)
current_count =
CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
else
current_count = size - count;
memcpy(current_dest,
temp_buf,
current_count);
offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE;
}
return ecc_errors ? -1 : 0;
+}
No bad block marker handling?
The bootrom does not use bad block marker handling (and allwinner's own FTL does neither for the non boot area, the actually mess up things by writing metadata which looks like classic bad block markers).
Hm, checking for bad block markers (and skipping bad blocks) is always a good thing, even if it does not by itself guarantee that the data stored in there are not corrupted.
Not on Allwinner hardware. Allwinner tools write data to the nand which looks like bad block markers so skipping blocks which appear marked as bad will inevitably skip valid blocks on many (most ?) Allwinner devices.
So, how do you prevent the bad block check from happening in non-SPL NAND code?
First of all, that's not exactly true. The allwinner NAND layer (and probably the tools allowing you to flash a new image) is actually writing the appropriate good block pattern (0xff), but this pattern is then randomized by the hardware randomizer, which makes it look like a bad block (!= 0xff).
The other aspect is, do we really have to support images flashed with this tool? I mean, I'm flashing my images using fel and a standard u-boot, and they generate perfectly valid images with valid bad block markers.
Only in the case you soldered a new nand chip yourself and never used Allwinner tools with it will the bad block markers remain valid. This is overall very unlikely so it should not be something SPL handles.
Here you're talking about the bad block markers 'corrupted' by the libnand layer (or the flashing tool). To restore valid bad block markers you just have to launch nand scrub in u-boot.
Are you talking about using scrub only on blocks that read as valid when unrandomized? Does the tool that writes these randomized images skip blocks that are marked bad?
-Scott

When SPL_NAND_SUNXI option is selected in config, set some configuration options for sunxi NAND.
This commit also introduces the configurable options in Kconfig.
Signed-off-by: Peter Gielda pgielda@antmicro.com Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com Signed-off-by: Mateusz Holenko mholenko@antmicro.com Signed-off-by: Piotr Zierhoffer pzierhoffer@antmicro.com Signed-off-by: Karol Gugala kgugala@antmicro.com ---
Changes in v3: - added new options in Kconfig to support different chips - changed descriptions to comply with patman rules
Changes in v2: - removed traces of non-SPL specific code - renamed defines to be more relevant - moved Kconfig entry for the driver to drivers/mtd/nand - reworded Kconfig entry help
drivers/mtd/nand/Kconfig | 40 ++++++++++++++++++++++++++++++++++++++++ include/configs/sunxi-common.h | 10 ++++++++++ 2 files changed, 50 insertions(+)
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 3024357..41ebfea 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -85,6 +85,46 @@ config SPL_NAND_DENALI This is a small implementation of the Denali NAND controller for use on SPL.
+config SPL_NAND_SUNXI + bool "Support for NAND on Allwinner A20 in SPL" + depends on MACH_SUN7I + ---help--- + Enable support for NAND. This option allows SPL to read from + sunxi NAND using DMA transfers. + Depending on the NAND chip, values like ECC strength and page sizes + have to be configured. + +config NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END + hex "Size of syndrome partitions in sunxi NAND" + default 0x400000 + depends on SPL_NAND_SUNXI + ---help--- + End address for boot partitions on NAND. Those partitions have a + different random seed that has to match the sunxi BROM setting. + +config NAND_SUNXI_SPL_ECC_STRENGTH + int "ECC Strength for sunxi NAND" + default 40 + depends on SPL_NAND_SUNXI + ---help--- + ECC strength used by the sunxi NAND SPL driver. This is specific to the + chosen NAND chip and has to match the value used by the sunxi BROM. + +config NAND_SUNXI_SPL_ECC_PAGE_SIZE + hex "ECC page size for sunxi NAND" + default 0x400 + depends on SPL_NAND_SUNXI + ---help--- + ECC page size used by the sunxi NAND SPL driver for syndrome partitions. + This setting has to match the value used by the sunxi BROM. + +config NAND_SUNXI_SPL_PAGE_SIZE + hex "Page size for sunxi NAND" + default 0x2000 + depends on SPL_NAND_SUNXI + ---help--- + Page size of the NAND flash used by the sunxi NAND SPL driver. This is + specific to the chosen NAND chip. endif
endmenu diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9576bc1..1855ade 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -139,6 +139,16 @@ #define CONFIG_INITRD_TAG #define CONFIG_SERIAL_TAG
+#if defined(CONFIG_SPL_NAND_SUNXI) +#define CONFIG_SPL_NAND_DRIVERS +#define CONFIG_SPL_NAND_SUPPORT + +#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x280000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x008000 + +#endif + + /* mmc config */ #if !defined(CONFIG_UART0_PORT_F) #define CONFIG_MMC

As SPL does not know which source to choose when booting U-Boot, choose NAND if it is capable of doing so.
Signed-off-by: Peter Gielda pgielda@antmicro.com Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com Signed-off-by: Mateusz Holenko mholenko@antmicro.com Signed-off-by: Piotr Zierhoffer pzierhoffer@antmicro.com Signed-off-by: Karol Gugala kgugala@antmicro.com
---
Changes in v3: - none
Changes in v2: - none
arch/arm/cpu/armv7/sunxi/board.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 5f39aa0..e4b7d63 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -128,6 +128,9 @@ void s_init(void) */ u32 spl_boot_device(void) { +#ifdef CONFIG_SPL_NAND_SUPPORT + return BOOT_DEVICE_NAND; +#else /* * When booting from the SD card, the "eGON.BT0" signature is expected * to be found in memory at the address 0x0004 (see the "mksunxiboot" @@ -148,6 +151,7 @@ u32 spl_boot_device(void) return BOOT_DEVICE_MMC1; else return BOOT_DEVICE_BOARD; +#endif }
/* No confirmation data available in SPL yet. Hardcode bootmode */

Hi Marek
As BROM requires SPL binary size to be limited, we wanted to keep it very minimal.
This driver has no integration with full U-Boot driver structure. What's more, it does not support writing.
It was tested as SPL driver, so that's why I am submitting it as such.
Best regards
Piotr Zierhoffer, Antmicro Ltd | www.antmicro.com *Piotr Zierhoffer* mobile: +48 696 419 606 Antmicro Ltd | www.antmicro.com Zwierzyniecka 3, 60-813 Poznan, Poland
2015-07-23 16:04 GMT+02:00 Marek Vasut marex@denx.de:
On Thursday, July 23, 2015 at 02:33:00 PM, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
Can you please elaborate how exactly is this specific only to SPL? Why?
Best regards, Marek Vasut

On Thursday, July 23, 2015 at 04:59:37 PM, Piotr Zierhoffer wrote:
Hi Marek
Hi,
As BROM requires SPL binary size to be limited, we wanted to keep it very minimal.
This driver has no integration with full U-Boot driver structure. What's more, it does not support writing.
It was tested as SPL driver, so that's why I am submitting it as such.
Ah OK. Btw please fix your mailer to stop top-posting :)
Best regards
Piotr Zierhoffer, Antmicro Ltd | www.antmicro.com *Piotr Zierhoffer* mobile: +48 696 419 606 Antmicro Ltd | www.antmicro.com Zwierzyniecka 3, 60-813 Poznan, Poland
2015-07-23 16:04 GMT+02:00 Marek Vasut marex@denx.de:
On Thursday, July 23, 2015 at 02:33:00 PM, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
Can you please elaborate how exactly is this specific only to SPL? Why?
Best regards, Marek Vasut
Best regards, Marek Vasut

Hi,
On 23-07-15 14:33, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Thanks for your work on this.
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
We do need to do some more work on this, to support more different sunxi SoCs, and to add some retry logic in case the default boot pages of the nand are bad, but that can both be done in follow-up commits.
Regards,
Hans
Changes in v3:
- moved pinmux and clock to board level
- code cleanup with significant size reduction
- renamed the driver file
- renamed constants to match Kconfig convention
- moved defines from .h to .c, and renamed them to be consistent with each other
- removed more magic values
- changed ecc_errors from static to local variable
- other minor changes
- added new options in Kconfig to support different chips
- changed descriptions to comply with patman rules
Changes in v2:
- removed traces of non-SPL-specific code
- moved the driver from boards/sunxi to drivers/mtd/nand
- moved magic values to defines (whenever possible)
- removed unnecesary late initialisation code
- code style changes as suggested for the first patch set:
- changed visibility of some symbols
- renamed unclear variables
- renamed header protector
- changed types of pointer variables
- other minor changes
- removed traces of non-SPL specific code
- renamed defines to be more relevant
- moved Kconfig entry for the driver to drivers/mtd/nand
- reworded Kconfig entry help
Karol Gugala (1): sunxi: nand: Add pinmux and clock settings for NAND support
Piotr Zierhoffer (3): sunxi: nand: Add basic sunxi NAND driver for SPL with DMA support sunxi: nand: Add board configuration options sunxi: nand: Add information to sunxi that it was run from NAND in SPL
arch/arm/cpu/armv7/sunxi/board.c | 4 + arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 2 + arch/arm/include/asm/arch-sunxi/gpio.h | 1 + board/sunxi/board.c | 27 ++ drivers/mtd/nand/Kconfig | 40 +++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand_spl.c | 353 ++++++++++++++++++++++++++ include/configs/sunxi-common.h | 10 + 8 files changed, 438 insertions(+) create mode 100644 drivers/mtd/nand/sunxi_nand_spl.c

Hi Hans,
On Sat, 1 Aug 2015 14:15:53 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 23-07-15 14:33, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Thanks for your work on this.
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Best Regards,
Boris

On Sat, 2015-08-01 at 14:30 +0200, Boris Brezillon wrote:
Hi Hans,
On Sat, 1 Aug 2015 14:15:53 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 23-07-15 14:33, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Thanks for your work on this.
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Or Scott's. :-)
ACK, though I'd encourage quickly implementing multiple spl payload locations to work around the breakage of the bad block marker mechanism, as was discussed.
-Scott

Hi,
On 01-08-15 21:22, Scott Wood wrote:
On Sat, 2015-08-01 at 14:30 +0200, Boris Brezillon wrote:
Hi Hans,
On Sat, 1 Aug 2015 14:15:53 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 23-07-15 14:33, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Thanks for your work on this.
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Or Scott's. :-)
ACK
Thanks.
though I'd encourage quickly implementing multiple spl payload locations to work around the breakage of the bad block marker mechanism, as was discussed.
I agree 100%, I've added note to my sunxi todo list for this. Note I only have this on my todo list as a reminder, since a few other people are actively working on sunxi nand support I hope that someone else will tackle this.
Regards,
Hans

Hello
2015-08-02 14:56 GMT+02:00 Hans de Goede hdegoede@redhat.com:
Hi,
On 01-08-15 21:22, Scott Wood wrote:
On Sat, 2015-08-01 at 14:30 +0200, Boris Brezillon wrote:
Hi Hans,
On Sat, 1 Aug 2015 14:15:53 +0200 Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 23-07-15 14:33, Piotr Zierhoffer wrote:
This is a basic driver for the sunxi NAND controller for Allwinner A20. It supports only SPL.
The driver uses DMA for data transfers. It does not support writing.
Thanks for your work on this.
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Or Scott's. :-)
ACK
Thanks.
though I'd encourage quickly implementing multiple spl payload locations to work around the breakage of the bad block marker mechanism, as was discussed.
I agree 100%, I've added note to my sunxi todo list for this. Note I only have this on my todo list as a reminder, since a few other people are actively working on sunxi nand support I hope that someone else will tackle this.
Thank you for your ACKs on this.
Unfortunately, we do not have manpower to implement features you have mentioned at the moment.
Of course we will be willing to help with testing and fixing if anything comes up.
Best regards, thank you for your support
Piotr Zierhoffer Antmicro Ltd | antmicro.com

Hi,
I've not done sunxi development for a while. So I need to ask you guys about some details. I hope you don't mind. Please see questions below.
On 06.08.2015 09:55, Piotr Zierhoffer wrote:
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Or Scott's. :-)
ACK
Thanks.
Okay, this driver SPL NAND is now integrated in mainline. Great.
But how about NAND support for the main U-Boot (load Linux from NAND etc.)? It seems to be missing. Is somebody working on this? Whats the current status here?
Thanks, Stefan

Hi,
On 08/20/2015 02:37 PM, Stefan Roese wrote:
Hi,
I've not done sunxi development for a while. So I need to ask you guys about some details. I hope you don't mind. Please see questions below.
On 06.08.2015 09:55, Piotr Zierhoffer wrote:
I've merged patches 1 - 3 in my sunxi-wip branch, and I'll include them in the next u-boot-sunxi pull-req.
Shouldn't we at least wait for Scoot's approval?
Or Scott's. :-)
ACK
Thanks.
Okay, this driver SPL NAND is now integrated in mainline. Great.
But how about NAND support for the main U-Boot (load Linux from NAND etc.)? It seems to be missing. Is somebody working on this?
Yes, see:
https://github.com/NextThingCo/CHIP-u-boot https://github.com/jwrdegoede/u-boot-sunxi/commits/sunxi-nand-wip
Whats the current status here?
We want to use the Linux kernel code for the main U-Boot, which is not fully upstream yet (and will likely not be for a while) as it needs per partition config (ecc / scrambler) settings, as well as merging of scrambler support into the upstream kernel first.
We will likely have a u-boot branch with this working soon-ish, but getting this merged is a different story.
Regards,
Hans

Hi Hans,
On 20.08.2015 15:42, Hans de Goede wrote:
Okay, this driver SPL NAND is now integrated in mainline. Great.
But how about NAND support for the main U-Boot (load Linux from NAND etc.)? It seems to be missing. Is somebody working on this?
Yes, see:
https://github.com/NextThingCo/CHIP-u-boot https://github.com/jwrdegoede/u-boot-sunxi/commits/sunxi-nand-wip
Thanks.
Whats the current status here?
We want to use the Linux kernel code for the main U-Boot, which is not fully upstream yet (and will likely not be for a while) as it needs per partition config (ecc / scrambler) settings, as well as merging of scrambler support into the upstream kernel first.
Ah, right. I remember seeing some mails on this.
We will likely have a u-boot branch with this working soon-ish,
That sounds interesting. I will probably start with NAND on an A20 board in the next 1-2 weeks. And will get back to you by then.
but getting this merged is a different story.
Right. Perhaps when we combine our "forces" this might be easier...
Thanks, Stefan

Hi Hans,
On 20.08.2015 16:49, Stefan Roese wrote:
Yes, see:
https://github.com/NextThingCo/CHIP-u-boot https://github.com/jwrdegoede/u-boot-sunxi/commits/sunxi-nand-wip
Thanks.
I've started on your "sunxi-nand-wip" branch. And noticed that its currently stuck / hangs in nand_onfi_set_features() called via sunxi_nand_chip_init_timings(). I've attached 2 patches now:
One with some whitespace / coding-style fixes and more important a 2nd one that actually fixes some buggy pointer initialization.
I just wanted to share this improvement, even if the driver still does not work correctly. But at least its not crashing that early with this fix.
Comments welcome.
BTW: What is the current status of this code? From my debugging (see 2nd patch) it seems that this should not be good enough to run on any board yet.
Thanks, Stefan

On 27.08.2015 12:06, Stefan Roese wrote:
https://github.com/NextThingCo/CHIP-u-boot https://github.com/jwrdegoede/u-boot-sunxi/commits/sunxi-nand-wip
Thanks.
I've started on your "sunxi-nand-wip" branch. And noticed that its currently stuck / hangs in nand_onfi_set_features() called via sunxi_nand_chip_init_timings(). I've attached 2 patches now:
One with some whitespace / coding-style fixes and more important a 2nd one that actually fixes some buggy pointer initialization.
I just wanted to share this improvement, even if the driver still does not work correctly. But at least its not crashing that early with this fix.
I forgot to mention that NAND detection takes very long with this patch (like 10 seconds). And all NAND block are marked as bad.
Thanks, Stefan
participants (7)
-
Boris Brezillon
-
Hans de Goede
-
Marek Vasut
-
Michal Suchanek
-
Piotr Zierhoffer
-
Scott Wood
-
Stefan Roese