[LEDE-DEV] [RFC] brcm63xx: Add NAND flash support
Daniel Gonzalez Cabanelas
dgcbueu at gmail.com
Fri Apr 13 04:41:07 PDT 2018
Hi, since the adoption of the Linux kernel 4.9 there are available drivers for NAND flash in the brcm63xx target. However these drivers only support brcm NAND versions 4.0 and and up, giving support only for BCM6362 and BCM63268 SoCs
I've made a patch for including the versions present in BCM6328 and BCM6368 (versions 2.1 and 2.2), basically I just added the required registers. The NAND flash detection is ok, formating and mounting jffs2 filesystems also seems to be OK. But when writting an remounting the partitions I get plenty of jfss2 errors.
Probably the ECC in versions 2.1 and 2.2 need additional work, since some bits are missing when comparing with version 4.0.
I was testing this stuff using the NAND chip as the secondary flash. Which is de default configuration in the DGND3700 v1 (bcm6368), and hardware modded in the AD1018 (bcm6328).
Is there any plan to include NAND support?. Not as the main flash chip but secondary for a first approach for further support in the future.
Regards.
diff --git a/target/linux/brcm63xx/config-4.9 b/target/linux/brcm63xx/config-4.9
index f1c3471..7d48ba2 100644
--- a/target/linux/brcm63xx/config-4.9
+++ b/target/linux/brcm63xx/config-4.9
@@ -168,6 +168,9 @@ CONFIG_MTD_CFI_STAA=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BRCMNAND=y
+CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_PARSER_IMAGETAG=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_REDBOOT_PARTS=y
diff --git a/target/linux/brcm63xx/dts/ad1018-nor.dts b/target/linux/brcm63xx/dts/ad1018-nor.dts
index 93862c2..e7fcf7a 100644
--- a/target/linux/brcm63xx/dts/ad1018-nor.dts
+++ b/target/linux/brcm63xx/dts/ad1018-nor.dts
@@ -140,6 +140,26 @@
};
};
+&nflash {
+ status = "ok";
+
+ nandcs at 0 {
+ compatible = "brcm,nandcs";
+ #size-cells = <1>;
+ #address-cells = <1>;
+ reg = <0>;
+ nand-ecc-step-size = <512>;
+ nand-ecc-strength = <15>;
+ brcm,nand-oob-sector-size = <64>;
+ //nand-on-flash-bbt;
+
+ nand_flash at 0 {
+ label = "nand_flash";
+ reg = <0x0000000 0x8000000>;
+ };
+ };
+};
+
&uart0 {
status = "ok";
};
diff --git a/target/linux/brcm63xx/dts/bcm63268.dtsi b/target/linux/brcm63xx/dts/bcm63268.dtsi
index 1b4b3e6..938c49f 100644
--- a/target/linux/brcm63xx/dts/bcm63268.dtsi
+++ b/target/linux/brcm63xx/dts/bcm63268.dtsi
@@ -221,6 +221,19 @@
status = "disabled";
};
+ nflash: nand at 10000200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,nand-bcm6368", "brcm,brcmnand-v4.0", "brcm,brcmnand";
+ reg = <0x10000200 0x180>, <0x10000600 0x200>, <0x100000b0 0x10>;
+ reg-names = "nand", "nand-cache", "nand-int-base";
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <50>;
+
+ status = "disabled";
+ };
+
lsspi: spi at 10000800 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/target/linux/brcm63xx/dts/bcm6328.dtsi b/target/linux/brcm63xx/dts/bcm6328.dtsi
index d08b6ba..4155329 100644
--- a/target/linux/brcm63xx/dts/bcm6328.dtsi
+++ b/target/linux/brcm63xx/dts/bcm6328.dtsi
@@ -4,6 +4,7 @@
compatible = "brcm,bcm6328";
aliases {
+ nflash = &nflash;
pinctrl = &pinctrl;
serial0 = &uart0;
serial1 = &uart1;
@@ -179,6 +180,19 @@
status = "disabled";
};
+ nflash: nand at 10000200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,nand-bcm6368", "brcm,brcmnand-v2.1", "brcm,brcmnand";
+ reg = <0x10000200 0x180>, <0x10000400 0x200>, <0x10000070 0x10>;
+ reg-names = "nand", "nand-cache", "nand-int-base";
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <0>;
+
+ status = "disabled";
+ };
+
leds: led-controller at 10000800 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/target/linux/brcm63xx/dts/bcm6362.dtsi b/target/linux/brcm63xx/dts/bcm6362.dtsi
index 2ff5c52..9ead35b 100644
--- a/target/linux/brcm63xx/dts/bcm6362.dtsi
+++ b/target/linux/brcm63xx/dts/bcm6362.dtsi
@@ -265,6 +265,19 @@
status = "disabled";
};
+ nflash: nand at 10000200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,nand-bcm6368", "brcm,brcmnand-v4.0", "brcm,brcmnand";
+ reg = <0x10000200 0x180>, <0x10000600 0x200>, <0x10000070 0x10>;
+ reg-names = "nand", "nand-cache", "nand-int-base";
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <12>;
+
+ status = "disabled";
+ };
+
lsspi: spi at 10000800 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/target/linux/brcm63xx/dts/bcm6368.dtsi b/target/linux/brcm63xx/dts/bcm6368.dtsi
index b834f9e..f00997b 100644
--- a/target/linux/brcm63xx/dts/bcm6368.dtsi
+++ b/target/linux/brcm63xx/dts/bcm6368.dtsi
@@ -4,6 +4,7 @@
compatible = "brcm,bcm6368";
aliases {
+ nflash = &nflash;
pflash = &pflash;
pinctrl = &pinctrl;
serial0 = &uart0;
@@ -298,6 +299,19 @@
status = "disabled";
};
+ nflash: nand at 10000200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "brcm,nand-bcm6368", "brcm,brcmnand-v2.1", "brcm,brcmnand";
+ reg = <0x10000200 0x180>, <0x10000600 0x200>, <0x10000070 0x10>;
+ reg-names = "nand", "nand-cache", "nand-int-base";
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <10>;
+
+ status = "disabled";
+ };
+
lsspi: spi at 10000800 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/target/linux/brcm63xx/dts/dgnd3700v1.dts b/target/linux/brcm63xx/dts/dgnd3700v1.dts
index cafa098..d331d98 100644
--- a/target/linux/brcm63xx/dts/dgnd3700v1.dts
+++ b/target/linux/brcm63xx/dts/dgnd3700v1.dts
@@ -123,6 +123,26 @@
};
};
+&nflash {
+ status = "ok";
+
+ nandcs at 0 {
+ compatible = "brcm,nandcs";
+ #size-cells = <1>;
+ #address-cells = <1>;
+ reg = <0>;
+ nand-ecc-step-size = <512>;
+ nand-ecc-strength = <15>;
+ brcm,nand-oob-sector-size = <64>;
+ //nand-on-flash-bbt;
+
+ nand_flash at 0 {
+ label = "nand_flash";
+ reg = <0x0000000 0x8000000>;
+ };
+ };
+};
+
&pinctrl {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pci>;
diff --git a/target/linux/brcm63xx/patches-4.9/810-nand.patch b/target/linux/brcm63xx/patches-4.9/810-nand.patch
new file mode 100644
index 0000000..354407d
--- /dev/null
+++ b/target/linux/brcm63xx/patches-4.9/810-nand.patch
@@ -0,0 +1,226 @@
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -222,8 +222,38 @@
+ BRCMNAND_OOB_WRITE_10_BASE, /* offset 0x10, if non-contiguous */
+ BRCMNAND_FC_BASE,
+ };
+
++/* BRCMNAND v2.1 v2.2 */
++static const u16 brcmnand_regs_v21[] = {
++ [BRCMNAND_CMD_START] = 0x04,
++ [BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
++ [BRCMNAND_CMD_ADDRESS] = 0x0c,
++ [BRCMNAND_INTFC_STATUS] = 0x5c,
++ [BRCMNAND_CS_SELECT] = 0x14,
++ [BRCMNAND_CS_XOR] = 0x18,
++ [BRCMNAND_LL_OP] = 0,
++ [BRCMNAND_CS0_BASE] = 0x40,
++ [BRCMNAND_CS1_BASE] = 0,
++ [BRCMNAND_CORR_THRESHOLD] = 0,
++ [BRCMNAND_CORR_THRESHOLD_EXT] = 0,
++ [BRCMNAND_UNCORR_COUNT] = 0,
++ [BRCMNAND_CORR_COUNT] = 0,
++ [BRCMNAND_CORR_EXT_ADDR] = 0x60,
++ [BRCMNAND_CORR_ADDR] = 0x64,
++ [BRCMNAND_UNCORR_EXT_ADDR] = 0x68,
++ [BRCMNAND_UNCORR_ADDR] = 0x6c,
++ [BRCMNAND_SEMAPHORE] = 0x50,
++ [BRCMNAND_ID] = 0x54,
++ [BRCMNAND_ID_EXT] = 0x9c,
++ [BRCMNAND_LL_RDATA] = 0,
++ [BRCMNAND_OOB_READ_BASE] = 0x20,
++ [BRCMNAND_OOB_READ_10_BASE] = 0,
++ [BRCMNAND_OOB_WRITE_BASE] = 0x30,
++ [BRCMNAND_OOB_WRITE_10_BASE] = 0,
++ [BRCMNAND_FC_BASE] = 0x200,
++};
++
+ /* BRCMNAND v4.0 */
+ static const u16 brcmnand_regs_v40[] = {
+ [BRCMNAND_CMD_START] = 0x04,
+ [BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
+@@ -407,8 +437,17 @@
+ [BRCMNAND_CS_TIMING1] = 0x10,
+ [BRCMNAND_CS_TIMING2] = 0x14,
+ };
+
++/* Per chip-select offset for v2.1 v2.2 on CS0 only */
++static const u8 brcmnand_cs_offsets_cs0_v21[] = {
++ [BRCMNAND_CS_ACC_CONTROL] = 0x00, //0x40
++ [BRCMNAND_CS_CFG_EXT] = 0x04,
++ [BRCMNAND_CS_CFG] = 0x04,
++ [BRCMNAND_CS_TIMING1] = 0x08,
++ [BRCMNAND_CS_TIMING2] = 0x0c,
++};
++
+ /*
+ * Bitfields for the CFG and CFG_EXT registers. Pre-v7.1 controllers only had
+ * one config register, but once the bitfields overflowed, newer controllers
+ * (v7.1 and newer) added a CFG_EXT register and shuffled a few fields around.
+@@ -421,8 +460,9 @@
+ CFG_BUS_WIDTH = BIT(CFG_BUS_WIDTH_SHIFT),
+ CFG_DEVICE_SIZE_SHIFT = 24,
+
+ /* Only for pre-v7.1 (with no CFG_EXT register) */
++ CFG_PAGE_SIZE_SHIFT_21 = 30, /* only v2.1 BCM6368 */
+ CFG_PAGE_SIZE_SHIFT = 20,
+ CFG_BLK_SIZE_SHIFT = 28,
+
+ /* Only for v7.1+ (with CFG_EXT register) */
+@@ -455,18 +495,20 @@
+ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
+ {
+ static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
+ static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
++ static const unsigned int block_sizes_v2[] = { 16, 128, 8, 512, 0 };
+ static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
+
+ ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
+
+- /* Only support v4.0+? */
+- if (ctrl->nand_version < 0x0400) {
++ /* Only support v2.1+? */
++ if (ctrl->nand_version < 0x0201) {
+ dev_err(ctrl->dev, "version %#x not supported\n",
+ ctrl->nand_version);
+ return -ENODEV;
+ }
++ printk("NAND: Version %#x\n", ctrl->nand_version);
+
+ /* Register offsets */
+ if (ctrl->nand_version >= 0x0702)
+ ctrl->reg_offsets = brcmnand_regs_v72;
+@@ -477,8 +519,10 @@
+ else if (ctrl->nand_version >= 0x0500)
+ ctrl->reg_offsets = brcmnand_regs_v50;
+ else if (ctrl->nand_version >= 0x0400)
+ ctrl->reg_offsets = brcmnand_regs_v40;
++ else if (ctrl->nand_version >= 0x0201)
++ ctrl->reg_offsets = brcmnand_regs_v21;
+
+ /* Chip-select stride */
+ if (ctrl->nand_version >= 0x0701)
+ ctrl->reg_spacing = 0x14;
+@@ -491,10 +535,13 @@
+ } else {
+ ctrl->cs_offsets = brcmnand_cs_offsets;
+
+ /* v5.0 and earlier has a different CS0 offset layout */
+- if (ctrl->nand_version <= 0x0500)
++ if (ctrl->nand_version >= 0x0300)
+ ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
++ else if (ctrl->nand_version >= 0x0201)
++ ctrl->cs0_offsets = brcmnand_cs_offsets_cs0_v21;
++
+ }
+
+ /* Page / block sizes */
+ if (ctrl->nand_version >= 0x0701) {
+@@ -504,13 +551,19 @@
+ } else {
+ ctrl->page_sizes = page_sizes;
+ if (ctrl->nand_version >= 0x0600)
+ ctrl->block_sizes = block_sizes_v6;
+- else
++ else if (ctrl->nand_version >= 0x0202)
+ ctrl->block_sizes = block_sizes_v4;
++ else
++ ctrl->block_sizes = block_sizes_v2;
++
+
+ if (ctrl->nand_version < 0x0400) {
+- ctrl->max_page_size = 4096;
++ if (ctrl->nand_version <= 0x0202)
++ ctrl->max_page_size = 2048;
++ else
++ ctrl->max_page_size = 4096;
+ ctrl->max_block_size = 512 * 1024;
+ }
+ }
+
+@@ -2023,10 +2076,15 @@
+ (cfg->ful_adr_bytes << CFG_FUL_ADR_BYTES_SHIFT) |
+ (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) |
+ (device_size << CFG_DEVICE_SIZE_SHIFT);
+ if (cfg_offs == cfg_ext_offs) {
+- tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
+- (block_size << CFG_BLK_SIZE_SHIFT);
++ if (ctrl->nand_version = 0x0201){
++ tmp |= (page_size << CFG_PAGE_SIZE_SHIFT_21) |
++ (block_size << CFG_BLK_SIZE_SHIFT);
++ } else {
++ tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) |
++ (block_size << CFG_BLK_SIZE_SHIFT);
++ }
+ nand_writereg(ctrl, cfg_offs, tmp);
+ } else {
+ nand_writereg(ctrl, cfg_offs, tmp);
+ tmp = (page_size << CFG_EXT_PAGE_SIZE_SHIFT) |
+@@ -2377,8 +2435,9 @@
+ };
+ EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
+
+ static const struct of_device_id brcmnand_of_match[] = {
++ { .compatible = "brcm,brcmnand-v2.1" },
+ { .compatible = "brcm,brcmnand-v4.0" },
+ { .compatible = "brcm,brcmnand-v5.0" },
+ { .compatible = "brcm,brcmnand-v6.0" },
+ { .compatible = "brcm,brcmnand-v6.1" },
+--- a/arch/mips/bcm63xx/clk.c
++++ b/arch/mips/bcm63xx/clk.c
+@@ -428,8 +428,25 @@
+ .set = pcie_set,
+ };
+
+ /*
++ * NAND clock
++ */
++static void nand_set(struct clk *clk, int enable)
++{
++ if (BCMCPU_IS_6362())
++ bcm_hwclock_set(CKCTL_6362_NAND_EN, enable);
++ else if (BCMCPU_IS_6368())
++ bcm_hwclock_set(CKCTL_6368_NAND_EN, enable);
++ else if (BCMCPU_IS_63268())
++ bcm_hwclock_set(CKCTL_63268_NAND_EN, enable);
++}
++
++static struct clk clk_nand = {
++ .set = nand_set,
++};
++
++/*
+ * Internal peripheral clock
+ */
+ static struct clk clk_periph = {
+ .rate = (50 * 1000 * 1000),
+@@ -610,8 +627,9 @@
+ CLKDEV_INIT("10000120.serial", "refclk", &clk_periph),
+ CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
+ CLKDEV_INIT("10001000.spi", "pll", &clk_hsspi_pll),
+ /* gated clocks */
++ CLKDEV_INIT(NULL, "nand", &clk_nand),
+ CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
+ CLKDEV_INIT(NULL, "usbh", &clk_usbh),
+ CLKDEV_INIT(NULL, "usbd", &clk_usbd),
+ CLKDEV_INIT(NULL, "spi", &clk_spi),
+@@ -627,8 +645,9 @@
+ CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
+ CLKDEV_INIT("10000100.serial", "refclk", &clk_periph),
+ CLKDEV_INIT("10000120.serial", "refclk", &clk_periph),
+ /* gated clocks */
++ CLKDEV_INIT(NULL, "nand", &clk_nand),
+ CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
+ CLKDEV_INIT(NULL, "usbh", &clk_usbh),
+ CLKDEV_INIT(NULL, "usbd", &clk_usbd),
+ CLKDEV_INIT(NULL, "spi", &clk_spi),
+@@ -645,8 +664,9 @@
+ CLKDEV_INIT("100001a0.serial", "refclk", &clk_periph),
+ CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
+ CLKDEV_INIT("10001000.spi", "pll", &clk_hsspi_pll),
+ /* gated clocks */
++ CLKDEV_INIT(NULL, "nand", &clk_nand),
+ CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
+ CLKDEV_INIT(NULL, "usbh", &clk_usbh),
+ CLKDEV_INIT(NULL, "usbd", &clk_usbd),
+ CLKDEV_INIT(NULL, "spi", &clk_spi),
More information about the Lede-dev
mailing list