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@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@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@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@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@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@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@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@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@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@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@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@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),


_______________________________________________
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev

Reply via email to