[PATCH 0/5] mtd: pxa3xx_nand: add support for Armada 8k

This series adds NAND flash support to Aramda 8k systems. Patches make the necessary changes to the pxa3xx_nand driver and DT files.
Baruch Siach (2): arm: dts: armada-cp110-master: update nand-controller mtd: pxa3xx_nand: remove dead code
Shmuel Hazan (3): arm: dts: armada-cp110-slave: add missing cps_nand mtd: pxa3xx_nand: port to use driver model mtd: nand: pxa3xx: enable NAND controller if the SoC needs it
arch/arm/dts/armada-cp110-master.dtsi | 15 ++- arch/arm/dts/armada-cp110-slave.dtsi | 16 +++ drivers/mtd/nand/raw/Kconfig | 2 + drivers/mtd/nand/raw/pxa3xx_nand.c | 176 ++++++++++++++------------ 4 files changed, 123 insertions(+), 86 deletions(-)

From: Shmuel Hazan shmuel.h@siklu.com
Align node properties to kernel dts node.
Keep U-Boot specific nand-enable-arbiter, and num-cs for compatibility with the current driver.
Signed-off-by: Shmuel Hazan shmuel.h@siklu.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- arch/arm/dts/armada-cp110-slave.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi index b426a4eb6910..6cf217783709 100644 --- a/arch/arm/dts/armada-cp110-slave.dtsi +++ b/arch/arm/dts/armada-cp110-slave.dtsi @@ -267,6 +267,22 @@ utmi-port = <UTMI_PHY_TO_USB3_HOST0>; status = "disabled"; }; + + cps_nand: nand@720000 { + compatible = "marvell,armada-8k-nand-controller", + "marvell,armada370-nand-controller"; + reg = <0x720000 0x54>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "core", "reg"; + clocks = <&cps_syscon0 1 2>, + <&cps_syscon0 1 17>; + marvell,system-controller = <&cps_syscon0>; + nand-enable-arbiter; + num-cs = <1>; + status = "disabled"; + }; };
cps_pcie0: pcie@f4600000 {

Align node properties to kernel dts node.
The change of compatible property does not affect any currently supported board.
Keep U-Boot specific nand-enable-arbiter, and num-cs for compatibility with the current driver.
Signed-off-by: Baruch Siach baruch@tkos.co.il --- arch/arm/dts/armada-cp110-master.dtsi | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index cd5c974482e6..7d0d31da306d 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -285,15 +285,18 @@ };
cpm_nand: nand@720000 { - compatible = "marvell,mvebu-pxa3xx-nand"; - reg = <0x720000 0x100>; + compatible = "marvell,armada-8k-nand-controller", + "marvell,armada370-nand-controller"; + reg = <0x720000 0x54>; #address-cells = <1>; - - clocks = <&cpm_syscon0 1 2>; + #size-cells = <0>; + interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "core", "reg"; + clocks = <&cpm_syscon0 1 2>, + <&cpm_syscon0 1 17>; + marvell,system-controller = <&cpm_syscon0>; nand-enable-arbiter; num-cs = <1>; - nand-ecc-strength = <4>; - nand-ecc-step-size = <512>; status = "disabled"; };

From: Shmuel Hazan shmuel.h@siklu.com
Signed-off-by: Shmuel Hazan shmuel.h@siklu.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- drivers/mtd/nand/raw/Kconfig | 2 + drivers/mtd/nand/raw/pxa3xx_nand.c | 114 +++++++++++++---------------- 2 files changed, 54 insertions(+), 62 deletions(-)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 06b2ff972cad..bcfaa09ac720 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -195,6 +195,8 @@ endif config NAND_PXA3XX bool "Support for NAND on PXA3xx and Armada 370/XP/38x" select SYS_NAND_SELF_INIT + select DM_MTD + select SYSCON imply CMD_NAND help This enables the driver for the NAND flash device found on diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index a30e82166b96..d455201b91a3 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <linux/types.h> +#include <dm/uclass.h> +#include <dm/read.h>
#include "pxa3xx_nand.h"
@@ -417,6 +419,14 @@ static struct nand_ecclayout ecc_layout_8KB_bch8bit = { /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000)
+static const struct udevice_id pxa3xx_nand_dt_ids[] = { + { + .compatible = "marvell,mvebu-pxa3xx-nand", + .data = PXA3XX_NAND_VARIANT_ARMADA370, + }, + {} +}; + static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) { /* We only support the Armada 370/XP/38x for now */ @@ -1810,79 +1820,58 @@ fail_disable_clk: return ret; }
-static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) +static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *info) { struct pxa3xx_nand_platform_data *pdata; - const void *blob = gd->fdt_blob; - int node = -1;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM;
- /* Get address decoding nodes from the FDT blob */ - do { - node = fdt_node_offset_by_compatible(blob, node, - "marvell,mvebu-pxa3xx-nand"); - if (node < 0) - break; - - /* Bypass disabeld nodes */ - if (!fdtdec_get_is_enabled(blob, node)) - continue; - - /* Get the first enabled NAND controler base address */ - info->mmio_base = - (void __iomem *)fdtdec_get_addr_size_auto_noparent( - blob, node, "reg", 0, NULL, true); + info->mmio_base = dev_read_addr_ptr(dev);
- pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); - if (pdata->num_cs != 1) { - pr_err("pxa3xx driver supports single CS only\n"); - break; - } - - if (fdtdec_get_bool(blob, node, "nand-enable-arbiter")) - pdata->enable_arbiter = 1; + pdata->num_cs = dev_read_u32_default(dev, "num-cs", 1); + if (pdata->num_cs != 1) { + pr_err("pxa3xx driver supports single CS only\n"); + return -EINVAL; + }
- if (fdtdec_get_bool(blob, node, "nand-keep-config")) - pdata->keep_config = 1; + if (dev_read_bool(dev, "nand-enable-arbiter")) + pdata->enable_arbiter = 1;
- /* - * ECC parameters. - * If these are not set, they will be selected according - * to the detected flash type. - */ - /* ECC strength */ - pdata->ecc_strength = fdtdec_get_int(blob, node, - "nand-ecc-strength", 0); + if (dev_read_bool(dev, "nand-keep-config")) + pdata->keep_config = 1;
- /* ECC step size */ - pdata->ecc_step_size = fdtdec_get_int(blob, node, - "nand-ecc-step-size", 0); - - info->pdata = pdata; + /* + * ECC parameters. + * If these are not set, they will be selected according + * to the detected flash type. + */ + /* ECC strength */ + pdata->ecc_strength = dev_read_u32_default(dev, "nand-ecc-strength", 0);
- /* Currently support only a single NAND controller */ - return 0; + /* ECC step size */ + pdata->ecc_step_size = dev_read_u32_default(dev, "nand-ecc-step-size", + 0);
- } while (node >= 0); + info->pdata = pdata;
- return -EINVAL; + return 0; }
-static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) +static int pxa3xx_nand_probe(struct udevice *dev) { struct pxa3xx_nand_platform_data *pdata; int ret, cs, probe_success; + struct pxa3xx_nand_info *info = dev_get_priv(dev);
- ret = pxa3xx_nand_probe_dt(info); + ret = pxa3xx_nand_probe_dt(dev, info); if (ret) return ret;
pdata = info->pdata;
- ret = alloc_nand_resource(info); + ret = alloc_nand_resource(dev, info); if (ret) { dev_err(&pdev->dev, "alloc nand resource failed\n"); return ret; @@ -1918,22 +1907,23 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info) return 0; }
-/* - * Main initialization routine - */ +U_BOOT_DRIVER(pxa3xx_nand) = { + .name = "pxa3xx-nand", + .id = UCLASS_MTD, + .of_match = pxa3xx_nand_dt_ids, + .probe = pxa3xx_nand_probe, + .priv_auto_alloc_size = sizeof(struct pxa3xx_nand_info) + + sizeof(struct pxa3xx_nand_host) * CONFIG_SYS_MAX_NAND_DEVICE, +}; + void board_nand_init(void) { - struct pxa3xx_nand_info *info; - struct pxa3xx_nand_host *host; + struct udevice *dev; int ret;
- info = kzalloc(sizeof(*info) + - sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE, - GFP_KERNEL); - if (!info) - return; - - ret = pxa3xx_nand_probe(info); - if (ret) - return; + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_GET_DRIVER(pxa3xx_nand), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); }

The kfree() call is unreachable, and is not needed. Remove this call and the fail_disable_clk label.
Signed-off-by: Baruch Siach baruch@tkos.co.il --- drivers/mtd/nand/raw/pxa3xx_nand.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index d455201b91a3..54ba65fa8202 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -1769,7 +1769,7 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) struct pxa3xx_nand_host *host; struct nand_chip *chip = NULL; struct mtd_info *mtd; - int ret, cs; + int cs;
pdata = info->pdata; if (pdata->num_cs <= 0) @@ -1805,19 +1805,13 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) /* Allocate a buffer to allow flash detection */ info->buf_size = INIT_BUFFER_SIZE; info->data_buff = kmalloc(info->buf_size, GFP_KERNEL); - if (info->data_buff == NULL) { - ret = -ENOMEM; - goto fail_disable_clk; - } + if (info->data_buff == NULL) + return -ENOMEM;
/* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK);
return 0; - - kfree(info->data_buff); -fail_disable_clk: - return ret; }
static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *info)

From: Shmuel Hazan shmuel.h@siklu.com
Based on Linux kernel commit fc256f5789cb ("mtd: nand: pxa3xx: enable NAND controller if the SoC needs it"). This commit adds support for the Armada 8040 nand controller.
The kernel commit says this:
Marvell recent SoCs like A7k/A8k do not boot with NAND flash controller activated by default. Enabling the controller is a matter of writing in a system controller register that may also be used for other NAND related choices.
Signed-off-by: Shmuel Hazan shmuel.h@siklu.com Signed-off-by: Baruch Siach baruch@tkos.co.il --- drivers/mtd/nand/raw/pxa3xx_nand.c | 50 ++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 54ba65fa8202..7506c5bb2884 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <linux/types.h> +#include <syscon.h> +#include <regmap.h> #include <dm/uclass.h> #include <dm/read.h>
@@ -119,6 +121,10 @@ DECLARE_GLOBAL_DATA_PTR; #define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ #define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */
+/* System control register and bit to enable NAND on some SoCs */ +#define GENCONF_SOC_DEVICE_MUX 0x208 +#define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0) + /* * This should be large enough to read 'ONFI' and 'JEDEC'. * Let's use 7 bytes, which is the maximum ID count supported @@ -159,6 +165,7 @@ enum { enum pxa3xx_nand_variant { PXA3XX_NAND_VARIANT_PXA, PXA3XX_NAND_VARIANT_ARMADA370, + PXA3XX_NAND_VARIANT_ARMADA_8K, };
struct pxa3xx_nand_host { @@ -424,13 +431,16 @@ static const struct udevice_id pxa3xx_nand_dt_ids[] = { .compatible = "marvell,mvebu-pxa3xx-nand", .data = PXA3XX_NAND_VARIANT_ARMADA370, }, + { + .compatible = "marvell,armada-8k-nand-controller", + .data = PXA3XX_NAND_VARIANT_ARMADA_8K, + }, {} };
-static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void) +static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(struct udevice *dev) { - /* We only support the Armada 370/XP/38x for now */ - return PXA3XX_NAND_VARIANT_ARMADA370; + return dev_get_driver_data(dev); }
static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, @@ -707,7 +717,8 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) info->retcode = ERR_UNCORERR; if (status & NDSR_CORERR) { info->retcode = ERR_CORERR; - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && + if ((info->variant == PXA3XX_NAND_VARIANT_ARMADA370 || + info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) && info->ecc_bch) info->ecc_err_cnt = NDSR_ERR_CNT(status); else @@ -762,7 +773,8 @@ static irqreturn_t pxa3xx_nand_irq(struct pxa3xx_nand_info *info) nand_writel(info, NDCB0, info->ndcb2);
/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */ - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 || + info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) nand_writel(info, NDCB0, info->ndcb3); }
@@ -1677,7 +1689,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) }
/* Device detection must be done with ECC disabled */ - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 || + info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) nand_writel(info, NDECCCTRL, 0x0);
if (nand_scan_ident(mtd, 1, NULL)) @@ -1727,7 +1740,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) * (aka split) command handling, */ if (mtd->writesize > info->chunk_size) { - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 || + info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) { chip->cmdfunc = nand_cmdfunc_extended; } else { dev_err(&info->pdev->dev, @@ -1763,7 +1777,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return nand_scan_tail(mtd); }
-static int alloc_nand_resource(struct pxa3xx_nand_info *info) +static int alloc_nand_resource(struct udevice *dev, struct pxa3xx_nand_info *info) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_host *host; @@ -1775,7 +1789,7 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) if (pdata->num_cs <= 0) return -ENODEV;
- info->variant = pxa3xx_nand_get_variant(); + info->variant = pxa3xx_nand_get_variant(dev); for (cs = 0; cs < pdata->num_cs; cs++) { chip = (struct nand_chip *) ((u8 *)&info[1] + sizeof(*host) * cs); @@ -1811,6 +1825,24 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) /* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK);
+ /* + * Some SoCs like A7k/A8k need to enable manually the NAND + * controller to avoid being bootloader dependent. This is done + * through the use of a single bit in the System Functions registers. + */ + if (pxa3xx_nand_get_variant(dev) == PXA3XX_NAND_VARIANT_ARMADA_8K) { + struct regmap *sysctrl_base = syscon_regmap_lookup_by_phandle( + dev, "marvell,system-controller"); + u32 reg; + + if (IS_ERR(sysctrl_base)) + return PTR_ERR(sysctrl_base); + + regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, ®); + reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN; + regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg); + } + return 0; }
participants (1)
-
Baruch Siach