[U-Boot] Proposal to add NAND-boot support for Sunxi SPL

The following patches take the work by Daniel Kochmánski, and make some heavy modifications for readability and functionality, based on Boris Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. Patches are sent as RFC. Open questions: - Config options added are partially NAND-chip specific. Some options can be autodetected based on the NAND ID, others require either brute-forcing or config options like these. Do they belong in sunxi-common? Should we make a Kconfig option for this? If bikeshedding is desired, are defines in sunxi-common.h good enough for now? - Style is mostly kernel-like. Satisfied? - Daniel: do you think we can work from here?
Please comment away!
Roy

From: Daniel Kochmański dkochmanski@turtle-solutions.eu
This change is necessary to calculate correct checksum for NAND boot. Works both for MMC and NAND. Without it BROM rejects boot image as invalid (bad checksum). (Changes block size from 0x200 to 0x2000).
V2: Document decision in source too
Signed-off-by: Daniel Kochmański dkochmanski@turtle-solutions.eu Cc: Ian Campbell ijc@hellion.org.uk Cc: Hans De Goede hdegoede@redhat.com Signed-off-by: Roy Spliet r.spliet@ultimaker.com --- tools/mksunxiboot.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c index 0035f6e..3361251 100644 --- a/tools/mksunxiboot.c +++ b/tools/mksunxiboot.c @@ -65,7 +65,13 @@ int gen_check_sum(struct boot_file_head *head_p)
#define SUN4I_SRAM_SIZE 0x7600 /* 0x7748+ is used by BROM */ #define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head)) -#define BLOCK_SIZE 512 + +/* + * BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned + * to a multiple of 8K, and rejects the image otherwise. MMC-images are fine + * with 512B blocks. To cater for both, align to the largest of the two. + */ +#define BLOCK_SIZE 0x2000
struct boot_img { struct boot_file_head header;

Hi,
On 21-05-15 15:59, Roy Spliet wrote:
From: Daniel Kochmański dkochmanski@turtle-solutions.eu
This change is necessary to calculate correct checksum for NAND boot. Works both for MMC and NAND. Without it BROM rejects boot image as invalid (bad checksum). (Changes block size from 0x200 to 0x2000).
V2: Document decision in source too
Signed-off-by: Daniel Kochmański dkochmanski@turtle-solutions.eu Cc: Ian Campbell ijc@hellion.org.uk Cc: Hans De Goede hdegoede@redhat.com Signed-off-by: Roy Spliet r.spliet@ultimaker.com
Looks good: Reviewed-by: Hans de Goede hdegoede@redhat.com
Regards,
Hans
tools/mksunxiboot.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/mksunxiboot.c b/tools/mksunxiboot.c index 0035f6e..3361251 100644 --- a/tools/mksunxiboot.c +++ b/tools/mksunxiboot.c @@ -65,7 +65,13 @@ int gen_check_sum(struct boot_file_head *head_p)
#define SUN4I_SRAM_SIZE 0x7600 /* 0x7748+ is used by BROM */ #define SRAM_LOAD_MAX_SIZE (SUN4I_SRAM_SIZE - sizeof(struct boot_file_head)) -#define BLOCK_SIZE 512
+/*
- BROM (at least on A10 and A20) requires NAND-images to be explicitly aligned
- to a multiple of 8K, and rejects the image otherwise. MMC-images are fine
- with 512B blocks. To cater for both, align to the largest of the two.
- */
+#define BLOCK_SIZE 0x2000
struct boot_img { struct boot_file_head header;

From: Daniel Kochmański dkochmanski@turtle-solutions.eu
V2: - Rename config option - Move to separate driver - fix DMA directly into RAM - Many readability upgrades - Drop R32 and W32 macros in favour of readl/writel respectively - Use standard port controller methods for pinctl - Make many NAND options semi-configurable
Signed-off-by: Roy Spliet r.spliet@ultimaker.com --- arch/arm/cpu/armv7/sunxi/board.c | 12 +- arch/arm/include/asm/arch-sunxi/gpio.h | 2 + board/sunxi/Kconfig | 12 ++ board/sunxi/board.c | 27 +++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand_spl.c | 290 +++++++++++++++++++++++++++++++++ include/configs/sun4i.h | 1 + include/configs/sun5i.h | 3 + include/configs/sun7i.h | 2 + include/configs/sun8i.h | 6 + include/configs/sunxi-common.h | 20 +++ 11 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/nand/sunxi_nand_spl.c
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 6718ae2..70f413f 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -111,8 +111,10 @@ void s_init(void) #ifdef CONFIG_SPL_BUILD /* The sunxi internal brom will try to loader external bootloader * from mmc0, nand flash, mmc2. - * Unfortunately we can't check how SPL was loaded so assume - * it's always the first SD/MMC controller + * + * Unfortunately we can't check how SPL was loaded so assume it's + * always the first SD/MMC controller, unless it was explicitly + * stated that SPL is on nand flash. */ u32 spl_boot_device(void) { @@ -122,6 +124,12 @@ u32 spl_boot_device(void) * enabled build. It has many restrictions and can only boot over USB. */ return BOOT_DEVICE_BOARD; +#elif defined(CONFIG_SPL_NAND_SUPPORT) + /* + * This is compile time configuration informing SPL, that it + * was loaded from nand flash. + */ + return BOOT_DEVICE_NAND; #else /* * When booting from the SD card, the "eGON.BT0" signature is expected diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 59d8210..2b49616 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -156,6 +156,8 @@ enum sunxi_gpio_number { #define SUN4I_GPB_UART0 2 #define SUN5I_GPB_UART0 2
+#define SUNXI_GPC_NAND 2 + #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index a60d028..cf58d73 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -269,6 +269,18 @@ config MMC_SUNXI_SLOT_EXTRA slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable support for this.
+config SPL_NAND_SUPPORT + bool "SPL/NAND mode support" + depends on SPL + default n + ---help--- + This enables support for booting from NAND internal + memory. U-Boot SPL doesn't detect where is it load from, + therefore this option is needed to properly load image from + flash. Option also disables MMC functionality on U-Boot due to + initialization errors encountered, when both controllers are + enabled. + config USB0_VBUS_PIN string "Vbus enable pin for usb0 (otg)" default "" diff --git a/board/sunxi/board.c b/board/sunxi/board.c index d9f7691..121e655 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -22,6 +22,9 @@ #ifdef CONFIG_AXP221_POWER #include <axp221.h> #endif +#ifdef CONFIG_NAND_SUNXI +#include <nand.h> +#endif #include <asm/arch/clock.h> #include <asm/arch/cpu.h> #include <asm/arch/display.h> @@ -34,6 +37,8 @@ #include <linux/usb/musb.h> #include <net.h>
+#define CCMU_BASE 0x01c20000 + #if defined CONFIG_VIDEO_LCD_PANEL_I2C && !(defined CONFIG_SPL_BUILD) /* So that we can use pin names in Kconfig and sunxi_name_to_gpio() */ int soft_i2c_gpio_sda; @@ -315,6 +320,28 @@ int board_mmc_init(bd_t *bis) } #endif
+void board_nand_init(void) +{ + uint32_t val; + unsigned int pin; + static u8 ports[] = CONFIG_NAND_SUNXI_GPC_PORTS; + + /* Configure AHB muxes to connect output pins with NAND controller */ + for (pin = 0; pin < 16; pin++) + sunxi_gpio_set_cfgpin(SUNXI_GPC(pin), SUNXI_GPC_NAND); + + for (pin = 0; pin < ARRAY_SIZE(ports); pin++) + sunxi_gpio_set_cfgpin(SUNXI_GPC(ports[pin]), SUNXI_GPC_NAND); + + /* "un-gate" NAND clock and clock source + * This assumes that the clock was already correctly configured by + * BootROM */ + val = readl(CCMU_BASE + 0x60); + writel((val | 0x00002000), CCMU_BASE + 0x60); + val = readl(CCMU_BASE + 0x80); + writel((val | 0x80000000), CCMU_BASE + 0x80); +} + void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 347ea62..a0cf4d5 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -73,5 +73,6 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o +obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
endif # drivers diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c new file mode 100644 index 0000000..b8d7a7a --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2014, Antmicro Ltd <www.antmicro.com> + * Copyright (c) 2015, Turtle Solutions <www.turtle-solutions.eu> + * Copyright (c) 2015, Roy Spliet rspliet@ultimaker.com + * + * SPDX-License-Identifier: GPL-2.0+ + * + * \todo Detect chip parameters (page size, ECC mode, randomisation...) + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <nand.h> + +/* DMAC */ +#define DMAC_BASE 0x01c02000 +#define DMAC_REG(a) (DMAC_BASE + a) + +#define DMAC_INT DMAC_REG(0x000) +#define DMAC_DDMA_CFG DMAC_REG(0x300) +#define DMAC_DDMA_SRC DMAC_REG(0x304) +#define DMAC_DDMA_DST DMAC_REG(0x308) +#define DMAC_DDMA_BYTE_COUNT DMAC_REG(0x30C) +#define DMAC_DDMA_PARAM DMAC_REG(0x318) + +/* NAND controller */ +#define NANDFLASHC_BASE 0x01c03000 +#define NREG(a) (0x01c03000 + a) + +#define NANDFLASHC_CTL NREG(0x00) +#define NANDFLASHC_CTL_EN 0x00000001 +#define NANDFLASHC_CTL_RST 0x00000002 +#define NANDFLASHC_CTL_RAM_METHOD 0x00004000 + +#define NANDFLASHC_ST NREG(0x004) +#define NANDFLASHC_INT NREG(0x008) +#define NANDFLASHC_TIMING_CTL NREG(0x00C) +#define NANDFLASHC_TIMING_CFG NREG(0x010) +#define NANDFLASHC_ADDR_LOW NREG(0x014) +#define NANDFLASHC_ADDR_HIGH NREG(0x018) +#define NANDFLASHC_SECTOR_NUM NREG(0x01C) +#define NANDFLASHC_CNT NREG(0x020) + +#define NANDFLASHC_CMD NREG(0x024) +#define NANDFLASHC_SEND_CMD1 (1 << 22) +#define NANDFLASHC_WAIT_FLAG (1 << 23) + +#define NANDFLASHC_RCMD_SET NREG(0x028) +#define NANDFLASHC_WCMD_SET NREG(0x02C) +#define NANDFLASHC_IO_DATA NREG(0x030) +#define NANDFLASHC_ECC_CTL NREG(0x034) +#define NANDFLASHC_ECC_ST NREG(0x038) +#define NANDFLASHC_DEBUG NREG(0x03c) +#define NANDFLASHC_ECC_CNT0 NREG(0x040) +#define NANDFLASHC_ECC_CNT1 NREG(0x044) +#define NANDFLASHC_ECC_CNT2 NREG(0x048) +#define NANDFLASHC_ECC_CNT3 NREG(0x04c) +#define NANDFLASHC_USER_DATA_BASE NREG(0x050) +#define NANDFLASHC_EFNAND_STATUS NREG(0x090) +#define NANDFLASHC_SPARE_AREA NREG(0x0A0) +#define NANDFLASHC_PATTERN_ID NREG(0x0A4) +#define NANDFLASHC_RAM0_BASE NREG(0x400) +#define NANDFLASHC_RAM1_BASE NREG(0x800) + +void +nand_init(void) +{ + uint32_t val; + + board_nand_init(); + val = readl(NANDFLASHC_CTL); + val |= NANDFLASHC_CTL_RST; + writel(val, NANDFLASHC_CTL); + + /* Wait until reset pin is deasserted */ + do { + val = readl(NANDFLASHC_CTL); + if (!(val & NANDFLASHC_CTL_RST)) + break; + } while (1); + + /** \todo Chip select, currently kind of static */ + val = readl(NANDFLASHC_CTL); + val &= 0xf0fff0f2; + val |= NANDFLASHC_CTL_EN; + val |= (3 << 8); + writel(val, NANDFLASHC_CTL); + + writel(0x100, NANDFLASHC_TIMING_CTL); + writel(0x7ff, NANDFLASHC_TIMING_CFG); + + /* reset CMD */ + val = NANDFLASHC_SEND_CMD1 | NANDFLASHC_WAIT_FLAG | NAND_CMD_RESET; + writel(val, NANDFLASHC_CMD); + do { + val = readl(NANDFLASHC_ST); + if (val & (1<<1)) + break; + udelay(1000); + } while (1); + + printf("Nand initialised\n"); +} + +/* random seed */ +static 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, +}; + +uint32_t ecc_errors = 0; + +int nand_waid_cmd_fifo_free(void) +{ + do { + if (!(readl(NANDFLASHC_ST) & 0x8)) + return 0; + } while (1); + return -1; +} + +static void +nand_config_ecc(uint32_t page, int syndrome) +{ + static u8 strength[] = {16, 24, 28, 32, 40, 48, 56, 60, 64}; + int i; + uint32_t ecc_mode; + u32 ecc; + + for (i = 0; i < ARRAY_SIZE(strength); i++) { + if (CONFIG_NAND_SUNXI_ECC_STRENGTH == strength[i]) { + ecc_mode = i; + break; + } + } + + if (i == ARRAY_SIZE(strength)) { + printf("ECC strength unsupported\n"); + return; + } + + ecc = 1 | (1<<3) | (1 << 9) | (ecc_mode << 12); + + if (CONFIG_NAND_SUNXI_ECC_STEP == 512) + ecc |= 1 << 5; + + if (syndrome) + ecc |= (0x4A80 << 16); + else + ecc |= (random_seed[page % ARRAY_SIZE(random_seed)] << 16); + + writel(ecc, NANDFLASHC_ECC_CTL); +} + +/* read CONFIG_NAND_SUNXI_ECC_STEP bytes from real_addr to temp_buf */ +void +nand_read_block(phys_addr_t src, dma_addr_t dst, int syndrome) +{ + uint32_t shift; + uint32_t page; + uint32_t addr; + uint32_t oob_offset; + uint32_t ecc_bytes; + u32 val; + u32 cmd; + + page = src / CONFIG_NAND_SUNXI_PAGE_SIZE; + if (page > 0xFFFF) { + /* TODO: currently this is not supported */ + printf("Reading from address >= %08X is not allowed.\n", + 0xFFFF * CONFIG_NAND_SUNXI_PAGE_SIZE); + return; + } + + shift = src % CONFIG_NAND_SUNXI_PAGE_SIZE; + writel(0, NANDFLASHC_ECC_ST); + + /* ECC_CTL, randomization */ + ecc_bytes = CONFIG_NAND_SUNXI_ECC_STRENGTH * + fls(CONFIG_NAND_SUNXI_ECC_STEP * 8); + ecc_bytes = DIV_ROUND_UP(ecc_bytes, 8); + ecc_bytes += (ecc_bytes & 1); /* Align to 2-bytes */ + ecc_bytes += 4; + + nand_config_ecc(page, syndrome); + if (syndrome) { + /* shift every 1kB in syndrome */ + shift += (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes; + oob_offset = CONFIG_NAND_SUNXI_ECC_STEP + shift; + } else { + oob_offset = CONFIG_NAND_SUNXI_PAGE_SIZE + + (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes; + } + + addr = (page << 16) | shift; + + /* DMA */ + val = readl(NANDFLASHC_CTL); + writel(val | NANDFLASHC_CTL_RAM_METHOD, NANDFLASHC_CTL); + + writel(oob_offset, NANDFLASHC_SPARE_AREA); + + /* DMAC + * \todo Separate this into a tidy driver */ + writel(0x0, DMAC_INT); /* clear dma interrupts */ + writel(NANDFLASHC_IO_DATA, DMAC_DDMA_SRC); + writel(dst , DMAC_DDMA_DST); + writel(0x00007F0F , DMAC_DDMA_PARAM); + writel(CONFIG_NAND_SUNXI_ECC_STEP, DMAC_DDMA_BYTE_COUNT); + /* + * [ 0: 4] Source - NAND + * [ 5: 6] Mode - IO + * [ 9:10] Dada width - 32-bits + * [16:20] Dest - SDRAM + * [25:26] Data width - 32-bits + * [ 31] Enable + */ + writel(0x84010423, DMAC_DDMA_CFG); + + writel(0x00E00530, NANDFLASHC_RCMD_SET); + nand_waid_cmd_fifo_free(); + writel(1, NANDFLASHC_SECTOR_NUM); + writel(addr, NANDFLASHC_ADDR_LOW); + writel(0, NANDFLASHC_ADDR_HIGH); + + /* CMD (PAGE READ) */ + cmd = 0x85E80000; + cmd |= ((CONFIG_NAND_SUNXI_ADDR_CYCLES - 1) << 16); + cmd |= (syndrome ? 0x02000000 : 0x0); + writel(cmd, NANDFLASHC_CMD); + + do { /* wait for dma irq */ + val = readl(NANDFLASHC_ST); + if (val & (1<<2)) + break; + udelay(1000); + } while (1); + + do {/* make sure cmd is finished */ + val = readl(DMAC_BASE + 0x300); + if (!(val & 0x80000000)) + break; + udelay(1000); + } while (1); + + if (readl(NANDFLASHC_ECC_ST)) + ecc_errors++; +} + +int +nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + dma_addr_t dst_block; + dma_addr_t dst_end; + phys_addr_t addr = offs; + + dst_end = ((dma_addr_t) dest) + size; + + memset((void *)dest, 0x0, size); + ecc_errors = 0; + for (dst_block = (dma_addr_t) dest; dst_block < dst_end; + dst_block += CONFIG_NAND_SUNXI_ECC_STEP, + addr += CONFIG_NAND_SUNXI_ECC_STEP) { + /* syndrome read first 4MiB to match Allwinner BootROM */ + nand_read_block(addr, dst_block, addr < 0x400000); + } + + if (ecc_errors) + printf("Error: %d ECC failures detected\n", ecc_errors); + return ecc_errors == 0; +} + +void +nand_deselect(void) +{} diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h index ea079eb..a3c9408 100644 --- a/include/configs/sun4i.h +++ b/include/configs/sun4i.h @@ -18,6 +18,7 @@ #endif
#define CONFIG_SUNXI_USB_PHYS 3 +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24}
/* * Include common sunxi configuration where most the settings are diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h index d257659..8e13df5 100644 --- a/include/configs/sun5i.h +++ b/include/configs/sun5i.h @@ -19,6 +19,9 @@
#define CONFIG_SUNXI_USB_PHYS 2
+/* \todo A13 only defines port 19, whereas A10s requires each of these */ +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19} + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h index 56101a9..3d26ce8 100644 --- a/include/configs/sun7i.h +++ b/include/configs/sun7i.h @@ -24,6 +24,8 @@ #define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE #define CONFIG_TIMER_CLK_FREQ 24000000
+#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24} + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h index 7111c63..cd33758 100644 --- a/include/configs/sun8i.h +++ b/include/configs/sun8i.h @@ -20,6 +20,12 @@
#define CONFIG_SUNXI_USB_PHYS 2
+#if defined(CONFIG_MACH_SUN8I_A23) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18} +#elif defined(CONFIG_MACH_SUN8I_A33) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16} +#endif + /* * Include common sunxi configuration where most the settings are */ diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index c8ebb54..cce0441 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -106,8 +106,10 @@ #define CONFIG_CMD_MMC #define CONFIG_MMC_SUNXI #define CONFIG_MMC_SUNXI_SLOT 0 +#if !defined(CONFIG_SPL_NAND_SUPPORT) #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */ +#endif /* CONFIG_SPL_NAND_SUPPORT */ #endif
/* 4MB of malloc() pool */ @@ -324,6 +326,24 @@ extern int soft_i2c_gpio_scl; #define CONFIG_ENV_IS_NOWHERE #endif
+#ifdef CONFIG_SPL_NAND_SUPPORT +#define CONFIG_NAND +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_NAND_SUNXI +#define CONFIG_CMD_SPL_WRITE_SIZE 0x000400 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x008000 + +/* \todo Make these parameterisable in kernel config ? */ +#define CONFIG_NAND_SUNXI_PAGE_SIZE 8192 +#define CONFIG_NAND_SUNXI_ECC_STEP 1024 +#define CONFIG_NAND_SUNXI_ECC_STRENGTH 40 +#define CONFIG_NAND_SUNXI_ADDR_CYCLES 5 + +#ifndef CONFIG_NAND_SUNXI_GPC_PORTS +#error "No NAND GPC ports defined, NAND unsupported" +#endif +#endif /* CONFIG_SPL_NAND_SUPPORT */ + #define CONFIG_MISC_INIT_R #define CONFIG_SYS_CONSOLE_IS_IN_ENV

Hi,
On 21-05-15 15:59, Roy Spliet wrote:
From: Daniel Kochmański dkochmanski@turtle-solutions.eu
V2:
- Rename config option
- Move to separate driver
- fix DMA directly into RAM
- Many readability upgrades
- Drop R32 and W32 macros in favour of readl/writel respectively
- Use standard port controller methods for pinctl
- Make many NAND options semi-configurable
Signed-off-by: Roy Spliet r.spliet@ultimaker.com
arch/arm/cpu/armv7/sunxi/board.c | 12 +- arch/arm/include/asm/arch-sunxi/gpio.h | 2 + board/sunxi/Kconfig | 12 ++ board/sunxi/board.c | 27 +++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand_spl.c | 290 +++++++++++++++++++++++++++++++++ include/configs/sun4i.h | 1 + include/configs/sun5i.h | 3 + include/configs/sun7i.h | 2 + include/configs/sun8i.h | 6 + include/configs/sunxi-common.h | 20 +++ 11 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/nand/sunxi_nand_spl.c
diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index 6718ae2..70f413f 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -111,8 +111,10 @@ void s_init(void) #ifdef CONFIG_SPL_BUILD /* The sunxi internal brom will try to loader external bootloader
- from mmc0, nand flash, mmc2.
- Unfortunately we can't check how SPL was loaded so assume
- it's always the first SD/MMC controller
- Unfortunately we can't check how SPL was loaded so assume it's
- always the first SD/MMC controller, unless it was explicitly
*/ u32 spl_boot_device(void) {
- stated that SPL is on nand flash.
@@ -122,6 +124,12 @@ u32 spl_boot_device(void) * enabled build. It has many restrictions and can only boot over USB. */ return BOOT_DEVICE_BOARD; +#elif defined(CONFIG_SPL_NAND_SUPPORT)
- /*
* This is compile time configuration informing SPL, that it
* was loaded from nand flash.
*/
- return BOOT_DEVICE_NAND; #else /*
- When booting from the SD card, the "eGON.BT0" signature is expected
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 59d8210..2b49616 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -156,6 +156,8 @@ enum sunxi_gpio_number { #define SUN4I_GPB_UART0 2 #define SUN5I_GPB_UART0 2
+#define SUNXI_GPC_NAND 2
- #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index a60d028..cf58d73 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -269,6 +269,18 @@ config MMC_SUNXI_SLOT_EXTRA slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable support for this.
+config SPL_NAND_SUPPORT
- bool "SPL/NAND mode support"
- depends on SPL
- default n
- ---help---
This enables support for booting from NAND internal
memory. U-Boot SPL doesn't detect where is it load from,
therefore this option is needed to properly load image from
flash. Option also disables MMC functionality on U-Boot due to
initialization errors encountered, when both controllers are
enabled.
- config USB0_VBUS_PIN string "Vbus enable pin for usb0 (otg)" default ""
There is a way to figure out if you're booting from sdcard or nand actually, simply check if an sdcard is there and if it has the boot0 signature, if that is true, then we should be booting from sd, as those are the checks the brom does itself to determine what to boot (*).
Since we support booting from internal emmc on boars which have it. and those are connected to mmc2 rather then mmc0 we already have code to check for this, see board/sunxi/board.c: board_mmc_init(), adapting this for use to determine whether to look u-boot.bin from nand or mmc on systems which have nand rather an emmc should be trivial.
So we should be able to build uniform SPL (and u-boot) binaries which work for both nand and sdcard. Note that this is jyst FYI, I'm fine with merging the patch as is and fixing this in a follow up patch.
*) Note this is not true on the A31 which prefers nand over sdcard unless the fel pin is pulled down (or was it up), but is true on all other SoCs
diff --git a/board/sunxi/board.c b/board/sunxi/board.c index d9f7691..121e655 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -22,6 +22,9 @@ #ifdef CONFIG_AXP221_POWER #include <axp221.h> #endif +#ifdef CONFIG_NAND_SUNXI +#include <nand.h> +#endif #include <asm/arch/clock.h> #include <asm/arch/cpu.h> #include <asm/arch/display.h> @@ -34,6 +37,8 @@ #include <linux/usb/musb.h> #include <net.h>
+#define CCMU_BASE 0x01c20000
Ugh no please, see below.
#if defined CONFIG_VIDEO_LCD_PANEL_I2C && !(defined CONFIG_SPL_BUILD) /* So that we can use pin names in Kconfig and sunxi_name_to_gpio() */ int soft_i2c_gpio_sda; @@ -315,6 +320,28 @@ int board_mmc_init(bd_t *bis) } #endif
+void board_nand_init(void) +{
- uint32_t val;
- unsigned int pin;
- static u8 ports[] = CONFIG_NAND_SUNXI_GPC_PORTS;
- /* Configure AHB muxes to connect output pins with NAND controller */
- for (pin = 0; pin < 16; pin++)
sunxi_gpio_set_cfgpin(SUNXI_GPC(pin), SUNXI_GPC_NAND);
- for (pin = 0; pin < ARRAY_SIZE(ports); pin++)
sunxi_gpio_set_cfgpin(SUNXI_GPC(ports[pin]), SUNXI_GPC_NAND);
- /* "un-gate" NAND clock and clock source
* This assumes that the clock was already correctly configured by
* BootROM */
- val = readl(CCMU_BASE + 0x60);
- writel((val | 0x00002000), CCMU_BASE + 0x60);
- val = readl(CCMU_BASE + 0x80);
- writel((val | 0x80000000), CCMU_BASE + 0x80);
+}
2 remarks here:
1) The ccmu poking needs to be done in the same way it is done everywhere else, see e.g. drivers/mmc/sunxi_mmc.c which does:
struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
/* config ahb clock */ setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); #ifdef CONFIG_SUNXI_GEN_SUN6I /* unassert reset */ setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); #endif
Also why are you doing this in the board init code? All other sunxi code only does pinmux setup in the board_init code and does the clk gating stuff in the actual driver code.
Last: "This assumes that the clock was already correctly configured by BROM" that will need to be fixed (eventually, can be in a follow up patch), as in u-boot.bin we will want to support reading nand while booted from sdcard (for the unified binaries)
void i2c_init_board(void) { #ifdef CONFIG_I2C0_ENABLE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 347ea62..a0cf4d5 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -73,5 +73,6 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o +obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o
endif # drivers diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c new file mode 100644 index 0000000..b8d7a7a --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -0,0 +1,290 @@ +/*
- Copyright (c) 2014, Antmicro Ltd <www.antmicro.com>
- Copyright (c) 2015, Turtle Solutions <www.turtle-solutions.eu>
- Copyright (c) 2015, Roy Spliet rspliet@ultimaker.com
- SPDX-License-Identifier: GPL-2.0+
- \todo Detect chip parameters (page size, ECC mode, randomisation...)
- */
+#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <nand.h>
+/* DMAC */ +#define DMAC_BASE 0x01c02000
Please use the base address define from arch/arm/include/asm/arch-sunxi/cpu_sun4i.h or add one there if necessary.
+#define DMAC_REG(a) (DMAC_BASE + a)
+#define DMAC_INT DMAC_REG(0x000) +#define DMAC_DDMA_CFG DMAC_REG(0x300) +#define DMAC_DDMA_SRC DMAC_REG(0x304) +#define DMAC_DDMA_DST DMAC_REG(0x308) +#define DMAC_DDMA_BYTE_COUNT DMAC_REG(0x30C) +#define DMAC_DDMA_PARAM DMAC_REG(0x318)
+/* NAND controller */ +#define NANDFLASHC_BASE 0x01c03000 +#define NREG(a) (0x01c03000 + a)
+#define NANDFLASHC_CTL NREG(0x00) +#define NANDFLASHC_CTL_EN 0x00000001 +#define NANDFLASHC_CTL_RST 0x00000002 +#define NANDFLASHC_CTL_RAM_METHOD 0x00004000
+#define NANDFLASHC_ST NREG(0x004) +#define NANDFLASHC_INT NREG(0x008) +#define NANDFLASHC_TIMING_CTL NREG(0x00C) +#define NANDFLASHC_TIMING_CFG NREG(0x010) +#define NANDFLASHC_ADDR_LOW NREG(0x014) +#define NANDFLASHC_ADDR_HIGH NREG(0x018) +#define NANDFLASHC_SECTOR_NUM NREG(0x01C) +#define NANDFLASHC_CNT NREG(0x020)
+#define NANDFLASHC_CMD NREG(0x024) +#define NANDFLASHC_SEND_CMD1 (1 << 22) +#define NANDFLASHC_WAIT_FLAG (1 << 23)
+#define NANDFLASHC_RCMD_SET NREG(0x028) +#define NANDFLASHC_WCMD_SET NREG(0x02C) +#define NANDFLASHC_IO_DATA NREG(0x030) +#define NANDFLASHC_ECC_CTL NREG(0x034) +#define NANDFLASHC_ECC_ST NREG(0x038) +#define NANDFLASHC_DEBUG NREG(0x03c) +#define NANDFLASHC_ECC_CNT0 NREG(0x040) +#define NANDFLASHC_ECC_CNT1 NREG(0x044) +#define NANDFLASHC_ECC_CNT2 NREG(0x048) +#define NANDFLASHC_ECC_CNT3 NREG(0x04c) +#define NANDFLASHC_USER_DATA_BASE NREG(0x050) +#define NANDFLASHC_EFNAND_STATUS NREG(0x090) +#define NANDFLASHC_SPARE_AREA NREG(0x0A0) +#define NANDFLASHC_PATTERN_ID NREG(0x0A4) +#define NANDFLASHC_RAM0_BASE NREG(0x400) +#define NANDFLASHC_RAM1_BASE NREG(0x800)
Please create a struct reflecting the register layout and then initialize a ptr to this struct from the base-address and get register addresses this way, this is how we deal with this in pretty much all other sunxi code, see e.g.:
arch/arm/include/asm/arch-sunxi/mmc.h
+void +nand_init(void) +{
- uint32_t val;
- board_nand_init();
- val = readl(NANDFLASHC_CTL);
- val |= NANDFLASHC_CTL_RST;
- writel(val, NANDFLASHC_CTL);
- /* Wait until reset pin is deasserted */
- do {
val = readl(NANDFLASHC_CTL);
if (!(val & NANDFLASHC_CTL_RST))
break;
- } while (1);
Please put a timeout on all waits, see mctl_await_completion() from arch/arm/cpu/armv7/sunxi/dram_helpers.c, or just use that outright. It is intended for use during dram init, but it should work fine for things like this too.
- /** \todo Chip select, currently kind of static */
- val = readl(NANDFLASHC_CTL);
- val &= 0xf0fff0f2;
- val |= NANDFLASHC_CTL_EN;
- val |= (3 << 8);
- writel(val, NANDFLASHC_CTL);
- writel(0x100, NANDFLASHC_TIMING_CTL);
- writel(0x7ff, NANDFLASHC_TIMING_CFG);
- /* reset CMD */
- val = NANDFLASHC_SEND_CMD1 | NANDFLASHC_WAIT_FLAG | NAND_CMD_RESET;
- writel(val, NANDFLASHC_CMD);
- do {
val = readl(NANDFLASHC_ST);
if (val & (1<<1))
break;
udelay(1000);
- } while (1);
Idem. Also the udelay buys you nothing.
- printf("Nand initialised\n");
+}
+/* random seed */ +static 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,
+};
+uint32_t ecc_errors = 0;
+int nand_waid_cmd_fifo_free(void) +{
- do {
if (!(readl(NANDFLASHC_ST) & 0x8))
return 0;
- } while (1);
Idem.
- return -1;
+}
+static void +nand_config_ecc(uint32_t page, int syndrome) +{
- static u8 strength[] = {16, 24, 28, 32, 40, 48, 56, 60, 64};
- int i;
- uint32_t ecc_mode;
- u32 ecc;
- for (i = 0; i < ARRAY_SIZE(strength); i++) {
if (CONFIG_NAND_SUNXI_ECC_STRENGTH == strength[i]) {
ecc_mode = i;
break;
}
- }
- if (i == ARRAY_SIZE(strength)) {
printf("ECC strength unsupported\n");
return;
- }
- ecc = 1 | (1<<3) | (1 << 9) | (ecc_mode << 12);
- if (CONFIG_NAND_SUNXI_ECC_STEP == 512)
ecc |= 1 << 5;
- if (syndrome)
ecc |= (0x4A80 << 16);
- else
ecc |= (random_seed[page % ARRAY_SIZE(random_seed)] << 16);
- writel(ecc, NANDFLASHC_ECC_CTL);
+}
+/* read CONFIG_NAND_SUNXI_ECC_STEP bytes from real_addr to temp_buf */ +void +nand_read_block(phys_addr_t src, dma_addr_t dst, int syndrome) +{
- uint32_t shift;
- uint32_t page;
- uint32_t addr;
- uint32_t oob_offset;
- uint32_t ecc_bytes;
- u32 val;
- u32 cmd;
- page = src / CONFIG_NAND_SUNXI_PAGE_SIZE;
- if (page > 0xFFFF) {
/* TODO: currently this is not supported */
printf("Reading from address >= %08X is not allowed.\n",
0xFFFF * CONFIG_NAND_SUNXI_PAGE_SIZE);
return;
- }
- shift = src % CONFIG_NAND_SUNXI_PAGE_SIZE;
- writel(0, NANDFLASHC_ECC_ST);
- /* ECC_CTL, randomization */
- ecc_bytes = CONFIG_NAND_SUNXI_ECC_STRENGTH *
fls(CONFIG_NAND_SUNXI_ECC_STEP * 8);
- ecc_bytes = DIV_ROUND_UP(ecc_bytes, 8);
- ecc_bytes += (ecc_bytes & 1); /* Align to 2-bytes */
- ecc_bytes += 4;
- nand_config_ecc(page, syndrome);
- if (syndrome) {
/* shift every 1kB in syndrome */
shift += (shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
oob_offset = CONFIG_NAND_SUNXI_ECC_STEP + shift;
- } else {
oob_offset = CONFIG_NAND_SUNXI_PAGE_SIZE +
(shift / CONFIG_NAND_SUNXI_ECC_STEP) * ecc_bytes;
- }
- addr = (page << 16) | shift;
- /* DMA */
- val = readl(NANDFLASHC_CTL);
- writel(val | NANDFLASHC_CTL_RAM_METHOD, NANDFLASHC_CTL);
- writel(oob_offset, NANDFLASHC_SPARE_AREA);
- /* DMAC
* \todo Separate this into a tidy driver */
- writel(0x0, DMAC_INT); /* clear dma interrupts */
- writel(NANDFLASHC_IO_DATA, DMAC_DDMA_SRC);
- writel(dst , DMAC_DDMA_DST);
- writel(0x00007F0F , DMAC_DDMA_PARAM);
- writel(CONFIG_NAND_SUNXI_ECC_STEP, DMAC_DDMA_BYTE_COUNT);
- /*
* [ 0: 4] Source - NAND
* [ 5: 6] Mode - IO
* [ 9:10] Dada width - 32-bits
* [16:20] Dest - SDRAM
* [25:26] Data width - 32-bits
* [ 31] Enable
*/
- writel(0x84010423, DMAC_DDMA_CFG);
- writel(0x00E00530, NANDFLASHC_RCMD_SET);
- nand_waid_cmd_fifo_free();
- writel(1, NANDFLASHC_SECTOR_NUM);
- writel(addr, NANDFLASHC_ADDR_LOW);
- writel(0, NANDFLASHC_ADDR_HIGH);
- /* CMD (PAGE READ) */
- cmd = 0x85E80000;
- cmd |= ((CONFIG_NAND_SUNXI_ADDR_CYCLES - 1) << 16);
- cmd |= (syndrome ? 0x02000000 : 0x0);
- writel(cmd, NANDFLASHC_CMD);
- do { /* wait for dma irq */
val = readl(NANDFLASHC_ST);
if (val & (1<<2))
break;
udelay(1000);
- } while (1);
- do {/* make sure cmd is finished */
val = readl(DMAC_BASE + 0x300);
if (!(val & 0x80000000))
break;
udelay(1000);
- } while (1);
- if (readl(NANDFLASHC_ECC_ST))
ecc_errors++;
+}
+int +nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
- dma_addr_t dst_block;
- dma_addr_t dst_end;
- phys_addr_t addr = offs;
- dst_end = ((dma_addr_t) dest) + size;
- memset((void *)dest, 0x0, size);
- ecc_errors = 0;
- for (dst_block = (dma_addr_t) dest; dst_block < dst_end;
dst_block += CONFIG_NAND_SUNXI_ECC_STEP,
addr += CONFIG_NAND_SUNXI_ECC_STEP) {
/* syndrome read first 4MiB to match Allwinner BootROM */
nand_read_block(addr, dst_block, addr < 0x400000);
- }
- if (ecc_errors)
printf("Error: %d ECC failures detected\n", ecc_errors);
- return ecc_errors == 0;
+}
+void +nand_deselect(void) +{} diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h index ea079eb..a3c9408 100644 --- a/include/configs/sun4i.h +++ b/include/configs/sun4i.h @@ -18,6 +18,7 @@ #endif
#define CONFIG_SUNXI_USB_PHYS 3 +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24}
/*
- Include common sunxi configuration where most the settings are
diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h index d257659..8e13df5 100644 --- a/include/configs/sun5i.h +++ b/include/configs/sun5i.h @@ -19,6 +19,9 @@
#define CONFIG_SUNXI_USB_PHYS 2
+/* \todo A13 only defines port 19, whereas A10s requires each of these */ +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19}
- /*
*/
- Include common sunxi configuration where most the settings are
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h index 56101a9..3d26ce8 100644 --- a/include/configs/sun7i.h +++ b/include/configs/sun7i.h @@ -24,6 +24,8 @@ #define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE #define CONFIG_TIMER_CLK_FREQ 24000000
+#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18, 19, 20, 21, 22, 24}
- /*
*/
- Include common sunxi configuration where most the settings are
diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h index 7111c63..cd33758 100644 --- a/include/configs/sun8i.h +++ b/include/configs/sun8i.h @@ -20,6 +20,12 @@
#define CONFIG_SUNXI_USB_PHYS 2
+#if defined(CONFIG_MACH_SUN8I_A23) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16, 17, 18} +#elif defined(CONFIG_MACH_SUN8I_A33) +#define CONFIG_NAND_SUNXI_GPC_PORTS {16} +#endif
- /*
*/
- Include common sunxi configuration where most the settings are
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index c8ebb54..cce0441 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -106,8 +106,10 @@ #define CONFIG_CMD_MMC #define CONFIG_MMC_SUNXI #define CONFIG_MMC_SUNXI_SLOT 0 +#if !defined(CONFIG_SPL_NAND_SUPPORT) #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */ +#endif /* CONFIG_SPL_NAND_SUPPORT */ #endif
/* 4MB of malloc() pool */ @@ -324,6 +326,24 @@ extern int soft_i2c_gpio_scl; #define CONFIG_ENV_IS_NOWHERE #endif
+#ifdef CONFIG_SPL_NAND_SUPPORT +#define CONFIG_NAND +#define CONFIG_SYS_NAND_SELF_INIT +#define CONFIG_NAND_SUNXI +#define CONFIG_CMD_SPL_WRITE_SIZE 0x000400 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x008000
+/* \todo Make these parameterisable in kernel config ? */ +#define CONFIG_NAND_SUNXI_PAGE_SIZE 8192 +#define CONFIG_NAND_SUNXI_ECC_STEP 1024 +#define CONFIG_NAND_SUNXI_ECC_STRENGTH 40 +#define CONFIG_NAND_SUNXI_ADDR_CYCLES 5
+#ifndef CONFIG_NAND_SUNXI_GPC_PORTS +#error "No NAND GPC ports defined, NAND unsupported" +#endif +#endif /* CONFIG_SPL_NAND_SUPPORT */
- #define CONFIG_MISC_INIT_R #define CONFIG_SYS_CONSOLE_IS_IN_ENV
Otherwise this looks like a good start, with the coding style issues fixed I would not be opposed against merging this as a first step to growing proper nand support.
Ian, is that ok with you ?
Regards,
Hans

On Thu, 2015-05-21 at 20:39 +0200, Hans de Goede wrote: [...]
Please create a struct reflecting the register layout and then initialize a ptr to this struct from the base-address and get register addresses this way, this is how we deal with this in pretty much all other sunxi code, see e.g.:
This isn't just sunxi, I believe it is u-boot's preferred way to do things generally. [...]
Otherwise this looks like a good start, with the coding style issues fixed I would not be opposed against merging this as a first step to growing proper nand support.
Ian, is that ok with you ?
You mean with the coding style fixed but not (necessarily) all the other issues you pointed out (timeouts on loops, structs for register accesses)?
I think at least the structs for register access stuff should be fixed first, especially given it was already raised in the previous round of review.
Ian

Hi,
On 21-05-15 21:02, Ian Campbell wrote:
On Thu, 2015-05-21 at 20:39 +0200, Hans de Goede wrote: [...]
Please create a struct reflecting the register layout and then initialize a ptr to this struct from the base-address and get register addresses this way, this is how we deal with this in pretty much all other sunxi code, see e.g.:
This isn't just sunxi, I believe it is u-boot's preferred way to do things generally. [...]
Otherwise this looks like a good start, with the coding style issues fixed I would not be opposed against merging this as a first step to growing proper nand support.
Ian, is that ok with you ?
You mean with the coding style fixed but not (necessarily) all the other issues you pointed out (timeouts on loops, structs for register accesses)?
Sorry, what I meant is are you ok with starting with merging just the SPL support without having support for actually reading the kernel, etc. as a first step. The SPL support would have to have all the issues (*) I pointed out fixed before merging.
Regards,
Hans
*) Except for those where I explicitly said they can be fixed up with a follow up commit.

On Fri, 2015-05-22 at 09:30 +0200, Hans de Goede wrote:
Hi,
On 21-05-15 21:02, Ian Campbell wrote:
On Thu, 2015-05-21 at 20:39 +0200, Hans de Goede wrote: [...]
Please create a struct reflecting the register layout and then initialize a ptr to this struct from the base-address and get register addresses this way, this is how we deal with this in pretty much all other sunxi code, see e.g.:
This isn't just sunxi, I believe it is u-boot's preferred way to do things generally. [...]
Otherwise this looks like a good start, with the coding style issues fixed I would not be opposed against merging this as a first step to growing proper nand support.
Ian, is that ok with you ?
You mean with the coding style fixed but not (necessarily) all the other issues you pointed out (timeouts on loops, structs for register accesses)?
Sorry, what I meant is are you ok with starting with merging just the SPL support without having support for actually reading the kernel, etc. as a first step.
Oh yes, that seems completely reasonable.
The SPL support would have to have all the issues (*) I pointed out fixed before merging.
Agreed.
Ian.

On Thu, 2015-05-21 at 15:59 +0200, Roy Spliet wrote:
+#ifdef CONFIG_NAND_SUNXI +#include <nand.h> +#endif
Why do you need the ifdef?
+#include <common.h>
+#include <config.h> +#include <asm/io.h> +#include <nand.h>
+/* DMAC */ +#define DMAC_BASE 0x01c02000 +#define DMAC_REG(a) (DMAC_BASE + a)
+#define DMAC_INT DMAC_REG(0x000) +#define DMAC_DDMA_CFG DMAC_REG(0x300) +#define DMAC_DDMA_SRC DMAC_REG(0x304) +#define DMAC_DDMA_DST DMAC_REG(0x308) +#define DMAC_DDMA_BYTE_COUNT DMAC_REG(0x30C) +#define DMAC_DDMA_PARAM DMAC_REG(0x318)
+/* NAND controller */ +#define NANDFLASHC_BASE 0x01c03000 +#define NREG(a) (0x01c03000 + a)
+#define NANDFLASHC_CTL NREG(0x00) +#define NANDFLASHC_CTL_EN 0x00000001 +#define NANDFLASHC_CTL_RST 0x00000002 +#define NANDFLASHC_CTL_RAM_METHOD 0x00004000
+#define NANDFLASHC_ST NREG(0x004) +#define NANDFLASHC_INT NREG(0x008) +#define NANDFLASHC_TIMING_CTL NREG(0x00C) +#define NANDFLASHC_TIMING_CFG NREG(0x010) +#define NANDFLASHC_ADDR_LOW NREG(0x014) +#define NANDFLASHC_ADDR_HIGH NREG(0x018) +#define NANDFLASHC_SECTOR_NUM NREG(0x01C) +#define NANDFLASHC_CNT NREG(0x020)
+#define NANDFLASHC_CMD NREG(0x024) +#define NANDFLASHC_SEND_CMD1 (1 << 22) +#define NANDFLASHC_WAIT_FLAG (1 << 23)
+#define NANDFLASHC_RCMD_SET NREG(0x028) +#define NANDFLASHC_WCMD_SET NREG(0x02C) +#define NANDFLASHC_IO_DATA NREG(0x030) +#define NANDFLASHC_ECC_CTL NREG(0x034) +#define NANDFLASHC_ECC_ST NREG(0x038) +#define NANDFLASHC_DEBUG NREG(0x03c) +#define NANDFLASHC_ECC_CNT0 NREG(0x040) +#define NANDFLASHC_ECC_CNT1 NREG(0x044) +#define NANDFLASHC_ECC_CNT2 NREG(0x048) +#define NANDFLASHC_ECC_CNT3 NREG(0x04c) +#define NANDFLASHC_USER_DATA_BASE NREG(0x050) +#define NANDFLASHC_EFNAND_STATUS NREG(0x090) +#define NANDFLASHC_SPARE_AREA NREG(0x0A0) +#define NANDFLASHC_PATTERN_ID NREG(0x0A4) +#define NANDFLASHC_RAM0_BASE NREG(0x400) +#define NANDFLASHC_RAM1_BASE NREG(0x800)
Shouldn't these be in a header file so they can be shared with a non- SPL driver?
+void +nand_init(void) +{
Don't put a newline after the return type.
uint32_t val;
board_nand_init();
val = readl(NANDFLASHC_CTL);
val |= NANDFLASHC_CTL_RST;
writel(val, NANDFLASHC_CTL);
/* Wait until reset pin is deasserted */
do {
val = readl(NANDFLASHC_CTL);
if (!(val & NANDFLASHC_CTL_RST))
break;
} while (1);
Add a timeout to delay loops.
/** \todo Chip select, currently kind of static */
val = readl(NANDFLASHC_CTL);
val &= 0xf0fff0f2;
Don't put magic numbers in the code -- use symbolic constants taht describe what the fields mean.
+/* random seed */
+static 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,
+};
Why is randomness needed?
+uint32_t ecc_errors = 0;
Why is this global?
+int +nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
dma_addr_t dst_block;
dma_addr_t dst_end;
phys_addr_t addr = offs;
dst_end = ((dma_addr_t) dest) + size;
memset((void *)dest, 0x0, size);
Unnecessary cast.
-Scott

Dear Scott,
Thank you for taking your time to feedback. However, it seems to be about a week and two versions of the patchset too late. Most of your issues have been addressed in the meanwhile, as you can see in Hans de Goede's sunxi branch. Yours,
Roy
Op 02-06-15 om 00:14 schreef Scott Wood:
On Thu, 2015-05-21 at 15:59 +0200, Roy Spliet wrote:
+#ifdef CONFIG_NAND_SUNXI +#include <nand.h> +#endif
Why do you need the ifdef?
+#include <common.h>
+#include <config.h> +#include <asm/io.h> +#include <nand.h>
+/* DMAC */ +#define DMAC_BASE 0x01c02000 +#define DMAC_REG(a) (DMAC_BASE + a)
+#define DMAC_INT DMAC_REG(0x000) +#define DMAC_DDMA_CFG DMAC_REG(0x300) +#define DMAC_DDMA_SRC DMAC_REG(0x304) +#define DMAC_DDMA_DST DMAC_REG(0x308) +#define DMAC_DDMA_BYTE_COUNT DMAC_REG(0x30C) +#define DMAC_DDMA_PARAM DMAC_REG(0x318)
+/* NAND controller */ +#define NANDFLASHC_BASE 0x01c03000 +#define NREG(a) (0x01c03000 + a)
+#define NANDFLASHC_CTL NREG(0x00) +#define NANDFLASHC_CTL_EN 0x00000001 +#define NANDFLASHC_CTL_RST 0x00000002 +#define NANDFLASHC_CTL_RAM_METHOD 0x00004000
+#define NANDFLASHC_ST NREG(0x004) +#define NANDFLASHC_INT NREG(0x008) +#define NANDFLASHC_TIMING_CTL NREG(0x00C) +#define NANDFLASHC_TIMING_CFG NREG(0x010) +#define NANDFLASHC_ADDR_LOW NREG(0x014) +#define NANDFLASHC_ADDR_HIGH NREG(0x018) +#define NANDFLASHC_SECTOR_NUM NREG(0x01C) +#define NANDFLASHC_CNT NREG(0x020)
+#define NANDFLASHC_CMD NREG(0x024) +#define NANDFLASHC_SEND_CMD1 (1 << 22) +#define NANDFLASHC_WAIT_FLAG (1 << 23)
+#define NANDFLASHC_RCMD_SET NREG(0x028) +#define NANDFLASHC_WCMD_SET NREG(0x02C) +#define NANDFLASHC_IO_DATA NREG(0x030) +#define NANDFLASHC_ECC_CTL NREG(0x034) +#define NANDFLASHC_ECC_ST NREG(0x038) +#define NANDFLASHC_DEBUG NREG(0x03c) +#define NANDFLASHC_ECC_CNT0 NREG(0x040) +#define NANDFLASHC_ECC_CNT1 NREG(0x044) +#define NANDFLASHC_ECC_CNT2 NREG(0x048) +#define NANDFLASHC_ECC_CNT3 NREG(0x04c) +#define NANDFLASHC_USER_DATA_BASE NREG(0x050) +#define NANDFLASHC_EFNAND_STATUS NREG(0x090) +#define NANDFLASHC_SPARE_AREA NREG(0x0A0) +#define NANDFLASHC_PATTERN_ID NREG(0x0A4) +#define NANDFLASHC_RAM0_BASE NREG(0x400) +#define NANDFLASHC_RAM1_BASE NREG(0x800)
Shouldn't these be in a header file so they can be shared with a non- SPL driver?
+void +nand_init(void) +{
Don't put a newline after the return type.
uint32_t val;
board_nand_init();
val = readl(NANDFLASHC_CTL);
val |= NANDFLASHC_CTL_RST;
writel(val, NANDFLASHC_CTL);
/* Wait until reset pin is deasserted */
do {
val = readl(NANDFLASHC_CTL);
if (!(val & NANDFLASHC_CTL_RST))
break;
} while (1);
Add a timeout to delay loops.
/** \todo Chip select, currently kind of static */
val = readl(NANDFLASHC_CTL);
val &= 0xf0fff0f2;
Don't put magic numbers in the code -- use symbolic constants taht describe what the fields mean.
+/* random seed */
+static 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,
+};
Why is randomness needed?
+uint32_t ecc_errors = 0;
Why is this global?
+int +nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{
dma_addr_t dst_block;
dma_addr_t dst_end;
phys_addr_t addr = offs;
dst_end = ((dma_addr_t) dest) + size;
memset((void *)dest, 0x0, size);
Unnecessary cast.
-Scott

Hi Roy,
On 21-05-15 15:59, Roy Spliet wrote:
The following patches take the work by Daniel Kochmánski, and make some heavy modifications for readability and functionality, based on Boris Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. Patches are sent as RFC. Open questions:
- Config options added are partially NAND-chip specific. Some options can
be autodetected based on the NAND ID, others require either brute-forcing or config options like these. Do they belong in sunxi-common? Should we make a Kconfig option for this? If bikeshedding is desired, are defines in sunxi-common.h good enough for now?
- Style is mostly kernel-like. Satisfied?
- Daniel: do you think we can work from here?
Please comment away!
Cool stuff. Overall this looks good I'll reply with more detailed feedback to your individual patches, 2 questions:
1) Can you provide a quick howto (at developer level) on how to actually get the spl and u-boot into the nand, what I'm looking for is unstructions like this:
a) Take this git repo + branch, build a kernel from it b) Look at this dts file for a nand settings example, adjust it for your board c) Once booted into the kernel using an updated dts you should have these block devices, dd spl to this one, and u-boot to this one.
No more to go more detailed then that :)
2) What is the plan to add support for loading files from nand in u-boot proper, so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ?
Regards,
Hans

Hi Roy,
I could definitely use such a howto. I have applied the patches to the current mainline u-boot head and try to boot my A13-OlinXino Wifi board in FEL mode. I can compile and boot into u-boot via FEL. However, I get these errors when I have CONFIG_SPL_NAND_SUPPORT defined:
U-Boot SPL 2015.07-rc1-00276-g77792f9-dirty (May 21 2015 - 19:15:54) DRAM: 512 MiB Failed to set core voltage! Can't set CPU frequency sunxi board_nand_init() Nand initialised Error: 1 ECC failures detected Error: 512 ECC failures detected
This is my configs/A13-OLinuXino_defconfig looks like this: CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,AXP209_POWER,USB_EHCI,SYS_MAX_NAND_DEVICE=1,SYS_NAND_BASE=0x00" CONFIG_NAND=y
CONFIG_SUNXI_NAND=y
CONFIG_SUNXI_DMA=y
CONFIG_CMD_NAND=y
CONFIG_SPL_NAND_SUPPORT=y
CONFIG_SPL=y
CONFIG_FDTFILE="sun5i-a13-olinuxino.dtb"
CONFIG_USB1_VBUS_PIN="PG11"
CONFIG_VIDEO_HDMI=n
CONFIG_VIDEO_VGA_VIA_LCD=y
CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH=y
# For use with the Olimex 7" LCD module, adjust timings for other displays # Set video-mode=sunxi:800x600-24@60,monitor=lcd in the env. to enable CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:16,ri:209,up:22,lo:22,hs:30,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_POWER="AXP0-0"
CONFIG_VIDEO_LCD_BL_PWM="PB2"
CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_MACH_SUN5I=y
CONFIG_DRAM_CLK=408
CONFIG_DRAM_ZQ=123
CONFIG_DRAM_EMR1=0
CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
I just found out in the sun5i-a13-olinuxino.dts file are no nand settings. I guess I can find the information in the linux-sunxi 3.4 kernels fex file for the olinuxio and need to convert to dts, correct?
I am happy about any hints / comments.
Thanks Alex
On Thursday, May 21, 2015 at 11:08:24 AM UTC-7, Hans de Goede wrote:
Hi Roy,
On 21-05-15 15:59, Roy Spliet wrote:
The following patches take the work by Daniel Kochmánski, and make some heavy modifications for readability and functionality, based on Boris Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. Patches are sent as RFC. Open questions:
- Config options added are partially NAND-chip specific. Some options
can
be autodetected based on the NAND ID, others require either
brute-forcing
or config options like these. Do they belong in sunxi-common? Should we make a Kconfig option for this? If bikeshedding is desired, are
defines
in sunxi-common.h good enough for now?
- Style is mostly kernel-like. Satisfied?
- Daniel: do you think we can work from here?
Please comment away!
Cool stuff. Overall this looks good I'll reply with more detailed feedback to your individual patches, 2 questions:
- Can you provide a quick howto (at developer level) on how to actually
get the spl and u-boot into the nand, what I'm looking for is unstructions like this:
a) Take this git repo + branch, build a kernel from it b) Look at this dts file for a nand settings example, adjust it for your board c) Once booted into the kernel using an updated dts you should have these block devices, dd spl to this one, and u-boot to this one.
No more to go more detailed then that :)
- What is the plan to add support for loading files from nand in u-boot
proper, so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ?
Regards,
Hans

Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is: 1) in include/configs/sunxi-common.h, adjust the parameters <CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration. 2) Build 3) Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND: # flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Cheers,
Roy
[1] https://github.com/bbrezillon/linux-sunxi/commits/sunxi-nand [2] https://linux-sunxi.org/NAND#More_information_on_BROM_NAND
Op 22-05-15 om 04:23 schreef kaplan2539@gmail.com:
Hi Roy,
I could definitely use such a howto. I have applied the patches to the current mainline u-boot head and try to boot my A13-OlinXino Wifi board in FEL mode. I can compile and boot into u-boot via FEL. However, I get these errors when I have CONFIG_SPL_NAND_SUPPORT defined:
U-Boot SPL 2015.07-rc1-00276-g77792f9-dirty (May 21 2015 - 19:15:54) DRAM: 512 MiB Failed to set core voltage! Can't set CPU frequency sunxi board_nand_init() Nand initialised Error: 1 ECC failures detected Error: 512 ECC failures detected
This is my configs/A13-OLinuXino_defconfig looks like this: CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,AXP209_POWER,USB_EHCI,SYS_MAX_NAND_DEVICE=1,SYS_NAND_BASE=0x00" CONFIG_NAND=y CONFIG_SUNXI_NAND=y CONFIG_SUNXI_DMA=y CONFIG_CMD_NAND=y CONFIG_SPL_NAND_SUPPORT=y CONFIG_SPL=y CONFIG_FDTFILE="sun5i-a13-olinuxino.dtb" CONFIG_USB1_VBUS_PIN="PG11" CONFIG_VIDEO_HDMI=n CONFIG_VIDEO_VGA_VIA_LCD=y CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH=y # For use with the Olimex 7" LCD module, adjust timings for other displays # Set video-mode=sunxi:800x600-24@60,monitor=lcd in the env. to enable CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:16,ri:209,up:22,lo:22,hs:30,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_POWER="AXP0-0" CONFIG_VIDEO_LCD_BL_PWM="PB2" CONFIG_ARM=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN5I=y CONFIG_DRAM_CLK=408 CONFIG_DRAM_ZQ=123 CONFIG_DRAM_EMR1=0 CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
I just found out in the sun5i-a13-olinuxino.dts file are no nand settings. I guess I can find the information in the linux-sunxi 3.4 kernels fex file for the olinuxio and need to convert to dts, correct?
I am happy about any hints / comments.
Thanks Alex
On Thursday, May 21, 2015 at 11:08:24 AM UTC-7, Hans de Goede wrote:
Hi Roy, On 21-05-15 15:59, Roy Spliet wrote: > The following patches take the work by Daniel Kochmánski, and make some > heavy modifications for readability and functionality, based on Boris > Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. > Patches are sent as RFC. Open questions: > - Config options added are partially NAND-chip specific. Some options can > be autodetected based on the NAND ID, others require either brute-forcing > or config options like these. Do they belong in sunxi-common? Should > we make a Kconfig option for this? If bikeshedding is desired, are defines > in sunxi-common.h good enough for now? > - Style is mostly kernel-like. Satisfied? > - Daniel: do you think we can work from here? > > Please comment away! Cool stuff. Overall this looks good I'll reply with more detailed feedback to your individual patches, 2 questions: 1) Can you provide a quick howto (at developer level) on how to actually get the spl and u-boot into the nand, what I'm looking for is unstructions like this: a) Take this git repo + branch, build a kernel from it b) Look at this dts file for a nand settings example, adjust it for your board c) Once booted into the kernel using an updated dts you should have these block devices, dd spl to this one, and u-boot to this one. No more to go more detailed then that :) 2) What is the plan to add support for loading files from nand in u-boot proper, so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ? Regards, Hans

Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters <CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration.
- Build
- Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND:
# flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Regards,
Hans
Cheers,
Roy
[1] https://github.com/bbrezillon/linux-sunxi/commits/sunxi-nand [2] https://linux-sunxi.org/NAND#More_information_on_BROM_NAND
Op 22-05-15 om 04:23 schreef kaplan2539@gmail.com:
Hi Roy,
I could definitely use such a howto. I have applied the patches to the current mainline u-boot head and try to boot my A13-OlinXino Wifi board in FEL mode. I can compile and boot into u-boot via FEL. However, I get these errors when I have CONFIG_SPL_NAND_SUPPORT defined:
U-Boot SPL 2015.07-rc1-00276-g77792f9-dirty (May 21 2015 - 19:15:54) DRAM: 512 MiB Failed to set core voltage! Can't set CPU frequency sunxi board_nand_init() Nand initialised Error: 1 ECC failures detected Error: 512 ECC failures detected
This is my configs/A13-OLinuXino_defconfig looks like this: CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,AXP209_POWER,USB_EHCI,SYS_MAX_NAND_DEVICE=1,SYS_NAND_BASE=0x00" CONFIG_NAND=y CONFIG_SUNXI_NAND=y CONFIG_SUNXI_DMA=y CONFIG_CMD_NAND=y CONFIG_SPL_NAND_SUPPORT=y CONFIG_SPL=y CONFIG_FDTFILE="sun5i-a13-olinuxino.dtb" CONFIG_USB1_VBUS_PIN="PG11" CONFIG_VIDEO_HDMI=n CONFIG_VIDEO_VGA_VIA_LCD=y CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH=y # For use with the Olimex 7" LCD module, adjust timings for other displays # Set video-mode=sunxi:800x600-24@60,monitor=lcd in the env. to enable CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:18,pclk_khz:33000,le:16,ri:209,up:22,lo:22,hs:30,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_POWER="AXP0-0" CONFIG_VIDEO_LCD_BL_PWM="PB2" CONFIG_ARM=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN5I=y CONFIG_DRAM_CLK=408 CONFIG_DRAM_ZQ=123 CONFIG_DRAM_EMR1=0 CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
I just found out in the sun5i-a13-olinuxino.dts file are no nand settings. I guess I can find the information in the linux-sunxi 3.4 kernels fex file for the olinuxio and need to convert to dts, correct?
I am happy about any hints / comments.
Thanks Alex
On Thursday, May 21, 2015 at 11:08:24 AM UTC-7, Hans de Goede wrote:
Hi Roy, On 21-05-15 15:59, Roy Spliet wrote: > The following patches take the work by Daniel Kochmánski, and make some > heavy modifications for readability and functionality, based on Boris > Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. > Patches are sent as RFC. Open questions: > - Config options added are partially NAND-chip specific. Some options can > be autodetected based on the NAND ID, others require either brute-forcing > or config options like these. Do they belong in sunxi-common? Should > we make a Kconfig option for this? If bikeshedding is desired, are defines > in sunxi-common.h good enough for now? > - Style is mostly kernel-like. Satisfied? > - Daniel: do you think we can work from here? > > Please comment away! Cool stuff. Overall this looks good I'll reply with more detailed feedback to your individual patches, 2 questions: 1) Can you provide a quick howto (at developer level) on how to actually get the spl and u-boot into the nand, what I'm looking for is unstructions like this: a) Take this git repo + branch, build a kernel from it b) Look at this dts file for a nand settings example, adjust it for your board c) Once booted into the kernel using an updated dts you should have these block devices, dd spl to this one, and u-boot to this one. No more to go more detailed then that :) 2) What is the plan to add support for loading files from nand in u-boot proper, so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ? Regards, Hans

Hi,
On 25-05-15 20:35, Hans de Goede wrote:
Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters <CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration.
- Build
- Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND:
# flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Ok, so quick update the breakage was caused by this commit:
https://github.com/bbrezillon/linux-sunxi/commit/7f7324bc6170a45742352070fb4...
When it was rebased someone (Boris I guess) forgot to remove the "chip->read_buf(mtd, NULL, ecc->size);" line at line 1075 (after the patch) and likewise the "chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);" line at line 1161. With these 2 lines removed the sunxi-nand-next branch from Boris, rebased on 4.1-rc1 can write the nand boot parts and the brom / spl can load the spl / resp. u-boot.bin from there (on a cubieboard2).
I've also tried to get this code running on a cubieboard (non 2 so A10 rather then A20), the SPL loads fine there (indicating that the kernel bits work), but then I get:
U-Boot SPL 2015.07-rc1-00287-g050de86-dirty (May 25 2015 - 22:28:19) DRAM: 1024 MiB CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2 Nand initialised NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data ...
Which seems to indicate a problem with the SPL nand code on the A10. I'll investigate this further tomorrow evening.
A cleaned up version of my kernel work on this is available in my sunxi-wip branch.
Regards,
Hans

Hello Hans,
Re-sent to everybody instead of just you. Reply inline.
Op 25-05-15 om 22:39 schreef Hans de Goede:
Hi,
On 25-05-15 20:35, Hans de Goede wrote:
Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters
<CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration. 2) Build 3) Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND: # flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Ok, so quick update the breakage was caused by this commit:
https://github.com/bbrezillon/linux-sunxi/commit/7f7324bc6170a45742352070fb4...
When it was rebased someone (Boris I guess) forgot to remove the "chip->read_buf(mtd, NULL, ecc->size);" line at line 1075 (after the patch) and likewise the "chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);" line at line 1161. With these 2 lines removed the sunxi-nand-next branch from Boris, rebased on 4.1-rc1 can write the nand boot parts and the brom / spl can load the spl / resp. u-boot.bin from there (on a cubieboard2).
You're right... I did spot this, but assumed this was my own mistake in merging these patches with our 4.0RC7 tree. Sorry, could have saved you some trouble if I were sharper.
I've also tried to get this code running on a cubieboard (non 2 so A10 rather then A20), the SPL loads fine there (indicating that the kernel bits work), but then I get:
U-Boot SPL 2015.07-rc1-00287-g050de86-dirty (May 25 2015 - 22:28:19) DRAM: 1024 MiB CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2 Nand initialised NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data ...
Thanks for testing this. I don't own an A10 myself, so I haven't observed this behaviour. First thing I would verify personally is whether all the clocks are properly configured. Could you make U-boot print &ccm->ahb_gate0 and &ccm->nand0_clk_cfg? For the first, bits 6 (DMA) and 13 (NAND) must be set, the second must have bit 31 set, bits 24 and 25 cleared (and otherwise, the accompanying PLL must be configured too... probably easier to use the OSC24M), and the divide ratios set to 0 (although a small divider, like 1, shouldn't be a problem either). I am assuming these values should be correct, but only because BROM initialised part of it. I am aware of the fact that the SPL driver doesn't control the DMA gating reg and the NAND post-dividers. It might be a good idea to do so for as long as we don't have a full DMA driver, so I'll patch that up today.
Roy
Which seems to indicate a problem with the SPL nand code on the A10. I'll investigate this further tomorrow evening.
A cleaned up version of my kernel work on this is available in my sunxi-wip branch.
Regards,
Hans

Hi,
On 05/26/2015 09:34 AM, Roy Spliet wrote:
Hello Hans,
Re-sent to everybody instead of just you. Reply inline.
Op 25-05-15 om 22:39 schreef Hans de Goede:
Hi,
On 25-05-15 20:35, Hans de Goede wrote:
Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters <CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration.
- Build
- Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND:
# flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Ok, so quick update the breakage was caused by this commit:
https://github.com/bbrezillon/linux-sunxi/commit/7f7324bc6170a45742352070fb4...
When it was rebased someone (Boris I guess) forgot to remove the "chip->read_buf(mtd, NULL, ecc->size);" line at line 1075 (after the patch) and likewise the "chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);" line at line 1161. With these 2 lines removed the sunxi-nand-next branch from Boris, rebased on 4.1-rc1 can write the nand boot parts and the brom / spl can load the spl / resp. u-boot.bin from there (on a cubieboard2).
You're right... I did spot this, but assumed this was my own mistake in merging these patches with our 4.0RC7 tree. Sorry, could have saved you some trouble if I were sharper.
I've also tried to get this code running on a cubieboard (non 2 so A10 rather then A20), the SPL loads fine there (indicating that the kernel bits work), but then I get:
U-Boot SPL 2015.07-rc1-00287-g050de86-dirty (May 25 2015 - 22:28:19) DRAM: 1024 MiB CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2 Nand initialised NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data ...
Thanks for testing this. I don't own an A10 myself, so I haven't observed this behaviour. First thing I would verify personally is whether all the clocks are properly configured. Could you make U-boot print &ccm->ahb_gate0 and &ccm->nand0_clk_cfg? For the first, bits 6 (DMA) and 13 (NAND) must be set, the second must have bit 31 set, bits 24 and 25 cleared (and otherwise, the accompanying PLL must be configured too... probably easier to use the OSC24M), and the divide ratios set to 0 (although a small divider, like 1, shouldn't be a problem either). I am assuming these values should be correct, but only because BROM initialised part of it. I am aware of the fact that the SPL driver doesn't control the DMA gating reg and the NAND post-dividers. It might be a good idea to do so for as long as we don't have a full DMA driver, so I'll patch that up today.
I've just tried the prelimary v4 of your patch-set from: https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
And the changes you've made fix these errors on the A10, good job.
Regards,
Hans

Hi,
I tried both the kernel from https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
and u-boot from https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
I can successfully compile and boot them on my A13-OLinuXino but there is no NAND available. Neither in kernel log nor in the u-boot output there is anything mentioned about NAND. I tried to enable all the NAND options, especially the "Support for NAND on Allwinner SoCs" in nconfig but I'm afraid I still have not found the right configuration.
Would it be possible to share the build configuration files?
Thanks in advance Alex
On Tue, May 26, 2015 at 7:52 AM, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 05/26/2015 09:34 AM, Roy Spliet wrote:
Hello Hans,
Re-sent to everybody instead of just you. Reply inline.
Op 25-05-15 om 22:39 schreef Hans de Goede:
Hi,
On 25-05-15 20:35, Hans de Goede wrote:
Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters
<CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration. 2) Build 3) Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND: # flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Ok, so quick update the breakage was caused by this commit:
https://github.com/bbrezillon/linux-sunxi/commit/7f7324bc6170a45742352070fb4...
When it was rebased someone (Boris I guess) forgot to remove the "chip->read_buf(mtd, NULL, ecc->size);" line at line 1075 (after the patch) and likewise the "chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);" line at line 1161. With these 2 lines removed the sunxi-nand-next branch from Boris, rebased on 4.1-rc1 can write the nand boot parts and the brom / spl can load the spl / resp. u-boot.bin from there (on a cubieboard2).
You're right... I did spot this, but assumed this was my own mistake in merging these patches with our 4.0RC7 tree. Sorry, could have saved you some trouble if I were sharper.
I've also tried to get this code running on a cubieboard (non 2 so A10 rather then A20), the SPL loads fine there (indicating that the kernel bits work), but then I get:
U-Boot SPL 2015.07-rc1-00287-g050de86-dirty (May 25 2015 - 22:28:19) DRAM: 1024 MiB CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2 Nand initialised NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data ...
Thanks for testing this. I don't own an A10 myself, so I haven't observed this behaviour. First thing I would verify personally is whether all the clocks are properly configured. Could you make U-boot print &ccm->ahb_gate0 and &ccm->nand0_clk_cfg? For the first, bits 6 (DMA) and 13 (NAND) must be set, the second must have bit 31 set, bits 24 and 25 cleared (and otherwise, the accompanying PLL must be configured too... probably easier to use the OSC24M), and the divide ratios set to 0 (although a small divider, like 1, shouldn't be a problem either). I am assuming these values should be correct, but only because BROM initialised part of it. I am aware of the fact that the SPL driver doesn't control the DMA gating reg and the NAND post-dividers. It might be a good idea to do so for as long as we don't have a full DMA driver, so I'll patch that up today.
I've just tried the prelimary v4 of your patch-set from: https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
And the changes you've made fix these errors on the A10, good job.
Regards,
Hans

Hello Alexander,
you have to put correct nand configuration in devicetree in arch/arm/boot/dts/sun5i-a13-olinuxino.dts of your board. For comparision you may check sun7i-a20-cubieboard2.dts which has appropriate definitions. sunxi-nand-wip branch works on a20.
Good luck! Daniel
Alexander Kaplan writes:
Hi,
I tried both the kernel from https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
and u-boot from https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
I can successfully compile and boot them on my A13-OLinuXino but there is no NAND available. Neither in kernel log nor in the u-boot output there is anything mentioned about NAND. I tried to enable all the NAND options, especially the "Support for NAND on Allwinner SoCs" in nconfig but I'm afraid I still have not found the right configuration.
Would it be possible to share the build configuration files?
Thanks in advance Alex
On Tue, May 26, 2015 at 7:52 AM, Hans de Goede hdegoede@redhat.com wrote:
Hi,
On 05/26/2015 09:34 AM, Roy Spliet wrote:
Hello Hans,
Re-sent to everybody instead of just you. Reply inline.
Op 25-05-15 om 22:39 schreef Hans de Goede:
Hi,
On 25-05-15 20:35, Hans de Goede wrote:
Hi,
On 22-05-15 09:04, Roy Spliet wrote:
Hello,
For my set-up I made use of Boris Brezillon's sunxi-nand tree[1], or actually I rebased his patches on top of 4.0rc7. This basically adds support for NAND-chip partitioning, ECC and randomisation. Docs for the DT specification in Documentation/devicetree/bindings/mtd/sunxi-nand.txt , and an example can be found in arch/arm/boot/dts/sun7i-a20-cubietruck.dts . [2] lists the acceptable configuration options for the boot and boot_rescue partitions, make sure to pick one of these (which should be no problem for MLC-type nand). The ECC mode for these boot partitions is called hw_syndrome.
Assuming you now have a Linux set-up kernel based on this tree with NAND support on an MMC, for U-boot what you should currently do is:
- in include/configs/sunxi-common.h, adjust the parameters
<CONFIG_NAND_SUNXI_>PAGE_SIZE, ECC_STEP, ECC_STRENGTH to match your NAND chip and DT configuration. 2) Build 3) Use your MMC to flash u-boot-sunxi-with-spl.bin onto NAND: # flash_erase /dev/mtd0 # nandwrite -p /dev/mtd0 u-boot-sunxi-with-spl.bin 4) Reboot without the MMC card and see U-boot load
Ok, it took me way longer then I wanted (see below) but I've this working now. It is cool to see u-boot load from nand :)
That should be all.
@Alex: To answer your question specifically: It's likely that the parameters in sunxi-common.h mentioned above might not match your NAND-chip configuration in the Linux kernel. I can't tell you precisely how to fetch these details from the 3.4 kernel, sorry. I recall Daniel using 24-bit strength ECC with otherwise equal parameters, but perhaps he can help you with this better than I can.
Alex, could it be that you are writing the nand using a (rebased) version of bbrezillon's sunxi-nand-next branch ?
I started with that too because it is much newer and contains various bug fixes, but it seems that it also contains a new bug causing it to write the NAND in such a way that the BROM and u-boot SPL code will not read it.
I've just pushed a rebased version of the sunxi-nand branch of Boris here:
https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
And that works for me, where as before I got the exact same errors trying to fel load a nand enabled spl.
I'm working on merging over all the changes from the sunxi-nand-next branch onto my working sunxi-nand-experiment branch 1 by 1 until I find the one which causes the breakage...
Ok, so quick update the breakage was caused by this commit:
https://github.com/bbrezillon/linux-sunxi/commit/7f7324bc6170a45742352070fb4...
When it was rebased someone (Boris I guess) forgot to remove the "chip->read_buf(mtd, NULL, ecc->size);" line at line 1075 (after the patch) and likewise the "chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);" line at line 1161. With these 2 lines removed the sunxi-nand-next branch from Boris, rebased on 4.1-rc1 can write the nand boot parts and the brom / spl can load the spl / resp. u-boot.bin from there (on a cubieboard2).
You're right... I did spot this, but assumed this was my own mistake in merging these patches with our 4.0RC7 tree. Sorry, could have saved you some trouble if I were sharper.
I've also tried to get this code running on a cubieboard (non 2 so A10 rather then A20), the SPL loads fine there (indicating that the kernel bits work), but then I get:
U-Boot SPL 2015.07-rc1-00287-g050de86-dirty (May 25 2015 - 22:28:19) DRAM: 1024 MiB CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2 Nand initialised NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data NAND timeout reading data ...
Thanks for testing this. I don't own an A10 myself, so I haven't observed this behaviour. First thing I would verify personally is whether all the clocks are properly configured. Could you make U-boot print &ccm->ahb_gate0 and &ccm->nand0_clk_cfg? For the first, bits 6 (DMA) and 13 (NAND) must be set, the second must have bit 31 set, bits 24 and 25 cleared (and otherwise, the accompanying PLL must be configured too... probably easier to use the OSC24M), and the divide ratios set to 0 (although a small divider, like 1, shouldn't be a problem either). I am assuming these values should be correct, but only because BROM initialised part of it. I am aware of the fact that the SPL driver doesn't control the DMA gating reg and the NAND post-dividers. It might be a good idea to do so for as long as we don't have a full DMA driver, so I'll patch that up today.
I've just tried the prelimary v4 of your patch-set from: https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
And the changes you've made fix these errors on the A10, good job.
Regards,
Hans

Hi Alexander,
On 05/26/2015 09:56 PM, Alexander Kaplan wrote:
Hi,
I tried both the kernel from https://github.com/jwrdegoede/linux-sunxi/commits/sunxi-nand-experiment
and u-boot from https://gitlab.com/turtle-solutions/u-boot/commits/sunxi-nand-wip
I can successfully compile and boot them on my A13-OLinuXino but there is no NAND available. Neither in kernel log nor in the u-boot output there is anything mentioned about NAND. I tried to enable all the NAND options, especially the "Support for NAND on Allwinner SoCs" in nconfig but I'm afraid I still have not found the right configuration.
Would it be possible to share the build configuration files?
I've just finished adding (partial) support for the A13-OLinuxino nand to my sunxi-wip kernel branch, and just pushed the result mere seconds ago.
I'm using the attached kernel .config file.
Note I've just also joined irc I'm hansg on #linux-sunxi @freenode so we can discuss this in realtime if you want.
Regards,
Hans

On 21 May 2015 at 20:08, Hans de Goede hdegoede@redhat.com wrote:
Hi Roy,
On 21-05-15 15:59, Roy Spliet wrote:
The following patches take the work by Daniel Kochmánski, and make some heavy modifications for readability and functionality, based on Boris Brezillon's Linux driver. Tested on an Olimex Lime w/ A20. Patches are sent as RFC. Open questions:
- Config options added are partially NAND-chip specific. Some options can
be autodetected based on the NAND ID, others require either brute-forcing or config options like these. Do they belong in sunxi-common? Should
I did not look at the u-boot patches but on the kernel side this is not completely solved I think.
AFAIK the BROM reads the nand in blocks and takes 1k from the start of block and discards the rest regardless of block size. On the other hand, the partition size in the DT is in bytes, not blocks. A person soldered an uncommon nand chip on an Olinuxino board without nand and the whole driver fell apart probably due to uncommon block size of the chip.
we make a Kconfig option for this? If bikeshedding is desired, are defines in sunxi-common.h good enough for now?
- Style is mostly kernel-like. Satisfied?
- Daniel: do you think we can work from here?
Please comment away!
Cool stuff. Overall this looks good I'll reply with more detailed feedback to your individual patches, 2 questions:
- Can you provide a quick howto (at developer level) on how to actually
get the spl and u-boot into the nand, what I'm looking for is unstructions like this:
a) Take this git repo + branch, build a kernel from it
I have some extra nand patches here: https://github.com/hramrach/linux-sunxi/commits/sunxi-nand-next
Unfortunately, this branch does not boot on a20 atm, at least from mmc. I suspect I picked a few too many clock patches but have to figure out what exactly breaks it.
However, you can cherry-pick
nand IDs nand partitions on cubieboards patch to ignore BBMs in case you have Allwinner formatted nand and it appears 90%+ bad.
with the bbrezillion sunxi-nand-next and these you should be able to access the cubieboard nand from Linux.
b) Look at this dts file for a nand settings example, adjust it for your board c) Once booted into the kernel using an updated dts you should have these block devices, dd spl to this one, and u-boot to this one.
You will probably need mtd-utils mtd_debug/nandwrite/ubiformat/ubiattach/...
There are some tutorials on how to use these but I personally did not try booting from nand so have no definitive answer what to write where.
Thanks
Michal

Hello Hans,
Sorry for ignoring the second half of your question so far. Here's what's on my mind. Op 21-05-15 om 20:08 schreef Hans de Goede:
Hi Roy,
- What is the plan to add support for loading files from nand in
u-boot proper, so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ?
For the full U-boot I agree we want both MMC and NAND support, regardless of where it was loaded from. From what I can tell U-boot already has UBI support. It sounds like a logical step to try and construct a proper NAND driver for U-boot that either co-exists with this SPL driver or, even better, shares code. That way, I only assume that the UBI and UBIFS layers will take care of all the rest. The NAND framework in u-boot resembles Linux in many ways. I'm currently in doubt whether we should take Boris' driver as a starting point, or rather use something heavily reduced that re-uses this SPL code. Either way, in U-boot we can perform a clean NAND-chip detection, preferably based on DT definitions as we also use on Linux, and take care of everything proper like PLL settings and a bunch of parameters which are now hard-coded or a configuration option in sunxi-common.h.
SPL is a different story. I don't know the exact size restriction, but for A10 I've heard it might be as little as 30KB. Current SPL with my patches and without MMC is already 23KiB. I personally think we can reduce it slightly by taking out support for reading everything other than the bootloader partition from SPL (so remove non-syndrome mode, remove the random seeds table...), but it certainly doesn't leave any room for the full NAND framework to do ID-based NAND chip detection. I personally think it's acceptable if NAND-SPL does not have MMC support and vice-versa. For NAND, SPL is only loaded when there is no first-level bootloader found on the MMC, so I safely dare to assume U-boot isn't there. MMCs are generally not so tiny that SPL fits but U-boot doesn't.
Questions, comments? Cheers,
Roy
Regards,
Hans

Hello Roy,
On 22-05-15 12:12, Roy Spliet wrote:
Hello Hans,
Sorry for ignoring the second half of your question so far. Here's what's on my mind. Op 21-05-15 om 20:08 schreef Hans de Goede:
Hi Roy,
- What is the plan to add support for loading files from nand in u-boot proper,
so that we can get (e.g.) extlinux.conf + kernel +dtb from a /boot on nand ?
For the full U-boot I agree we want both MMC and NAND support, regardless of where it was loaded from. From what I can tell U-boot already has UBI support. It sounds like a logical step to try and construct a proper NAND driver for U-boot that either co-exists with this SPL driver or, even better, shares code. That way, I only assume that the UBI and UBIFS layers will take care of all the rest.
Ack.
The NAND framework in u-boot resembles Linux in many ways. I'm currently in doubt whether we should take Boris' driver as a starting point, or rather use something heavily reduced that re-uses this SPL code. Either way, in U-boot we can perform a clean NAND-chip detection, preferably based on DT definitions as we also use on Linux, and take care of everything proper like PLL settings and a bunch of parameters which are now hard-coded or a configuration option in sunxi-common.h.
Have you seen Yassin Jaffer's work porting Boris' code to u-boot ?
https://github.com/yassinjaffer/u-boot/commits/sunxi-nand
Last time I mailed with Yassin (added to the Cc) he was ok with someone else picking this up and continuing with it as the does not have time to work on it.
SPL is a different story. I don't know the exact size restriction, but for A10 I've heard it might be as little as 30KB. Current SPL with my patches and without MMC is already 23KiB.
The BROM loads the SPL to a 32K sram and the stack sits in that same SRAM. Note I've some patches which switch the SPL from using a fill blown malloc to using simple-malloc.c which saves a significant amount of space, and the mmc code is not really that big, so I think we should be able to cram this all into the SPL.
I personally think we can reduce it slightly by taking out support for reading everything other than the bootloader partition from SPL (so remove non-syndrome mode, remove the random seeds table...),
I agree that removing (#if 0 it for now?) non boot partition support makes sense as a space saving measure.
but it certainly doesn't leave any room for the full NAND framework to do ID-based NAND chip detection.
What info do we need when we're only reading ? If the BROM can get away with a fixed way of reading the nand for booting, we should be able to make the SPL get away with it too ... I do really believe that we should be able to deal with different nand chips from a single binaries, with cheap chinese devices like the mk802 the chances are simply to big that the nand will differ from one revision to the next.
I personally think it's acceptable if NAND-SPL does not have MMC support and vice-versa.
Distros already need to build and distribute a u-boot-with-spl.bin per supported board. This doubles the number of builds they have to do and the number of files they need to distribute. If at all possible I would really like to have a unified SPL binary.
For NAND, SPL is only loaded when there is no first-level bootloader found on the MMC, so I safely dare to assume U-boot isn't there. MMCs are generally not so tiny that SPL fits but U-boot doesn't.
Right, this is mostly for distro / end-user convenience (and also to avoid needing to build all boards twice when preparing a pull-req).
Regards,
hans

fre 2015-05-22 klockan 15:51 +0200 skrev Hans de Goede:
What info do we need when we're only reading ? If the BROM can get away with a fixed way of reading the nand for booting, we should be able to make the SPL get away with it too ...
BROM tries at least 4 different strategies in reading the NAND boot blocks. Two different NAND protocol strategies and two different format strategies have been observed (4 different access patterns). And ontop of this it tries both randomizer scrambled and plain access.
Distros already need to build and distribute a u-boot-with-spl.bin per supported board. This doubles the number of builds they have to do and the number of files they need to distribute. If at all possible I would really like to have a unified SPL binary.
The SPL shrinks considerably in size if built in thumbs mode.
What I envisioned for sunix u-boot SPL was board-agnostic SPL binaries with a little configuration header. This way you only need two (or three is SPI is added) binaries, a list of board configurations and tool for applying the config and write the resulting binary to the boot device (NAND/MMC/SPI)
There isn't really that many board specific parameters.
Regards Henrik
participants (9)
-
Alexander Kaplan
-
Daniel Kochmański
-
Hans de Goede
-
Henrik Nordström
-
Ian Campbell
-
kaplan2539@gmail.com
-
Michal Suchanek
-
Roy Spliet
-
Scott Wood