Skip to contentSkip to conversation

Add arch/powerpc 4xx NDFC (NAND) support

RFC In review Stefan Roese 3 participants 3 messages Oct 10, 2007

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

RFC 1/1 Add arch/powerpc 4xx NDFC (NAND) support

This patch makes the PPC4xx NAND flash controller (NDFC) device-tree friendly using OF glue code to create and insert necessary platform devices. Such "constructor" approach makes NAND usable under arch/powerpc yet keeping full compatibility with arch/ppc.

This patch also introduces a "common" (not NOR only) of_parse_flash_partitions() routine in mtdpart.c that can/should be used by all drivers parsing device-tree partition informations. The current implementation is not compatible with the current physmap_of version and needs some additional work to make it really usable from both "drivers", physmap_of and ndfc_of. I'm just posting it right now to get some feedback, since this stuff is already sitting here too long on my disk and waiting for upstream merge.

Any feedback welcome. Thanks.

---
commit 721a340398e66872b9cc7e8b630fc92a7681ca04
tree ffbe1194146cb4fc324755f35c9062025b7ec0f6
parent 26f571d7c968dbd30656fc1421eeb0d9088aaad9
author Stefan Roese <[email protected]> Mon, 08 Oct 2007 16:00:49 +0200 committer Stefan Roese <[email protected]> Mon, 08 Oct 2007 16:00:49 +0200

 arch/powerpc/boot/dts/sequoia.dts    |   32 +++++++
 arch/powerpc/platforms/44x/Makefile  |    6 +
 arch/powerpc/platforms/44x/ndfc_of.c |  158 ++++++++++++++++++++++++++++++++++
 drivers/mtd/mtdpart.c                |   61 +++++++++++++
 drivers/mtd/nand/ndfc.c              |    6 +
 include/linux/mtd/partitions.h       |    2 
 6 files changed, 264 insertions(+), 1 deletions(-)
arch/powerpc/boot/dts/sequoia.dts +32 -0
index 36be75b..9b15482 100644
@@ -122,6 +122,38 @@
 			interrupt-map-mask = <ffffffff>;
 		};
 
+		ndfc@1d0000000, {
+			device_type = "nand";
+			compatible = "ibm,ndfc";
+			reg = <1 d0000000 2000>;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+			/* ndfc stuff, composed off ndfc_settings. */
+			/* select bank on CE[3], 4 Addr, 1 Col 3 Row 512b page */
+			ccr-settings = <3001000>;
+
+			chip@0 {
+				device_type = "nand-chip";
+				reg = <0 1>;
+				chip-nr = <1>;
+				chip-offset = <3>;
+				chip-delay = <50>;
+				chip-bank-settings = <80002222>;
+
+				/* normal NAND ECC stuff */
+				ecc-bytes = <6>;
+				ecc-pos = <0 1 2 3 6 7>;
+				/* list of tuples assumed here */
+				ecc-oobfree = <8 8>;
+
+				partition@0 {
+					label = "content";
+					reg = <0 0>;
+				};
+			};
+		};
+
 		POB0: opb {
 		  	compatible = "ibm,opb-440epx", "ibm,opb";
 			#address-cells = <1>;
arch/powerpc/platforms/44x/Makefile +5 -1
index 10ce674..d6195ee 100644
@@ -1,4 +1,8 @@
 obj-$(CONFIG_44x)	:= misc_44x.o
 obj-$(CONFIG_EBONY)	+= ebony.o
-obj-$(CONFIG_BAMBOO) += bamboo.o
+obj-$(CONFIG_BAMBOO)	+= bamboo.o
 obj-$(CONFIG_SEQUOIA)	+= sequoia.o
+
+ifeq ($(CONFIG_MTD_NAND_NDFC),y)
+obj-y			+= ndfc_of.o
+endif
arch/powerpc/platforms/44x/ndfc_of.c new file +158 -0

158 lines not on this page · raw message

drivers/mtd/mtdpart.c +61 -0

73 lines not on this page · raw message

drivers/mtd/nand/ndfc.c +6 -0
index fd7a8d5..7901019 100644
@@ -24,7 +24,9 @@
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
+#ifndef CONFIG_PPC_MERGE
 #include <asm/ibm44x.h>
+#endif
 
 struct ndfc_nand_mtd {
 	struct mtd_info			mtd;
@@ -230,7 +232,11 @@ static int ndfc_nand_probe(struct platform_device *pdev)
 	struct ndfc_controller *ndfc = &ndfc_ctrl;
 	unsigned long long phys = settings->ndfc_erpn | res->start;
 
+#if !defined(CONFIG_PHYS_64BIT) || defined(CONFIG_PPC_MERGE)
+	ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+#else
 	ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+#endif
 	if (!ndfc->ndfcbase) {
 		printk(KERN_ERR "NDFC: ioremap failed\n");
 		return -EIO;
include/linux/mtd/partitions.h +2 -0
index da6b3d6..546a098 100644
@@ -68,6 +68,8 @@ extern int register_mtd_parser(struct mtd_part_parser *parser);
 extern int deregister_mtd_parser(struct mtd_part_parser *parser);
 extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 				struct mtd_partition **pparts, unsigned long origin);
+extern int of_parse_flash_partitions(struct device_node *node,
+				     struct mtd_partition **parts);
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 
#1 lore raw
Quoted 38 lines · Stefan Roese

This patch makes the PPC4xx NAND flash controller (NDFC) device-tree friendly using OF glue code to create and insert necessary platform devices. Such "constructor" approach makes NAND usable under arch/powerpc yet keeping full compatibility with arch/ppc.

This patch also introduces a "common" (not NOR only) of_parse_flash_partitions() routine in mtdpart.c that can/should be used by all drivers parsing device-tree partition informations. The current implementation is not compatible with the current physmap_of version and needs some additional work to make it really usable from both "drivers", physmap_of and ndfc_of. I'm just posting it right now to get some feedback, since this stuff is already sitting here too long on my disk and waiting for upstream merge.

Any feedback welcome. Thanks.

---
commit 721a340398e66872b9cc7e8b630fc92a7681ca04
tree ffbe1194146cb4fc324755f35c9062025b7ec0f6
parent 26f571d7c968dbd30656fc1421eeb0d9088aaad9
author Stefan Roese <[email protected]> Mon, 08 Oct 2007 16:00:49 +0200 committer Stefan Roese <[email protected]> Mon, 08 Oct 2007 16:00:49 +0200

 arch/powerpc/boot/dts/sequoia.dts    |   32 +++++++
 arch/powerpc/platforms/44x/Makefile  |    6 +
 arch/powerpc/platforms/44x/ndfc_of.c |  158 ++++++++++++++++++++++++++++++++++
 drivers/mtd/mtdpart.c                |   61 +++++++++++++
 drivers/mtd/nand/ndfc.c              |    6 +
 include/linux/mtd/partitions.h       |    2 
 6 files changed, 264 insertions(+), 1 deletions(-)
arch/powerpc/boot/dts/sequoia.dts +0 -0
index 36be75b..9b15482 100644

arch/powerpc/boot/dts/sequoia.dts line 126

Quoted 5 lines
arch/powerpc/boot/dts/sequoia.dts +2 -0
@@ -122,6 +122,38 @@
 			interrupt-map-mask = <ffffffff>;
 		};
 
+		ndfc@1d0000000, {
+			device_type = "nand";

Ditch the device_type. There's no call for it here.

arch/powerpc/boot/dts/sequoia.dts line 127

Quoted 1 line
arch/powerpc/boot/dts/sequoia.dts +1 -0
+			compatible = "ibm,ndfc";

This should probably have a more specific value for the revision in addition to ibm,ndfc.

arch/powerpc/boot/dts/sequoia.dts line 137

Quoted 10 lines
arch/powerpc/boot/dts/sequoia.dts +10 -0
+			reg = <1 d0000000 2000>;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+			/* ndfc stuff, composed off ndfc_settings. */
+			/* select bank on CE[3], 4 Addr, 1 Col 3 Row 512b page */
+			ccr-settings = <3001000>;
+
+			chip@0 {
+				device_type = "nand-chip";

Ditch this device_type too, it makes absolutely no sense here. You probably should have a compatible, though.

arch/powerpc/boot/dts/sequoia.dts line 138

Quoted 1 line
arch/powerpc/boot/dts/sequoia.dts +1 -0
+				reg = <0 1>;

I don't really know how the ndfc works. Can the reg size here ever be anything other than 1 sensibly? If not, then you should set #size-cells=0 instead.

arch/powerpc/boot/dts/sequoia.dts line 150

Quoted 12 lines
arch/powerpc/boot/dts/sequoia.dts +12 -0
+				chip-nr = <1>;
+				chip-offset = <3>;
+				chip-delay = <50>;
+				chip-bank-settings = <80002222>;
+
+				/* normal NAND ECC stuff */
+				ecc-bytes = <6>;
+				ecc-pos = <0 1 2 3 6 7>;
+				/* list of tuples assumed here */
+				ecc-oobfree = <8 8>;
+
+				partition@0 {

Ok, the partitions really are per-chip, not across the controller's domain as a whole? Oh and if this is here, then the chip needs #address-cells and #size-cells.

Quoted 310 lines
arch/powerpc/boot/dts/sequoia.dts +6 -0
+					label = "content";
+					reg = <0 0>;
+				};
+			};
+		};
+
 		POB0: opb {
 		  	compatible = "ibm,opb-440epx", "ibm,opb";
 			#address-cells = <1>;
arch/powerpc/platforms/44x/Makefile +5 -1
index 10ce674..d6195ee 100644
@@ -1,4 +1,8 @@
 obj-$(CONFIG_44x)	:= misc_44x.o
 obj-$(CONFIG_EBONY)	+= ebony.o
-obj-$(CONFIG_BAMBOO) += bamboo.o
+obj-$(CONFIG_BAMBOO)	+= bamboo.o
 obj-$(CONFIG_SEQUOIA)	+= sequoia.o
+
+ifeq ($(CONFIG_MTD_NAND_NDFC),y)
+obj-y			+= ndfc_of.o
+endif
arch/powerpc/platforms/44x/ndfc_of.c new file +158 -0
new file mode 100644
index 0000000..e5b41cf
@@ -0,0 +1,158 @@
+/*
+ * PPC4xx NAND wrapper from device tree to platform device
+ *
+ * Stefan Roese <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/ndfc.h>
+#include <linux/of.h>
+
+static struct ndfc_controller_settings ndfc_settings;
+static struct platform_nand_ctrl nand_ctrl = {
+	.priv = &ndfc_settings,
+};
+
+static struct ndfc_chip_settings chip_settings;
+static struct nand_ecclayout ecclayout;
+static struct mtd_partition *nand_parts;
+
+static struct platform_nand_chip nand_chip = {
+	.ecclayout = &ecclayout,
+	.priv = &chip_settings,
+};
+
+static struct resource r;
+
+static struct platform_device ndfc_dev = {
+	.name = "ndfc-nand",
+	.id = 0,
+	.num_resources = 1,
+	.resource = &r,
+	.dev = {
+		.platform_data = &nand_ctrl,
+	}
+};
+
+static struct platform_device nand_dev = {
+	.name = "ndfc-chip",
+	.id = 0,
+	.num_resources = 1,
+	.resource = &r,
+	.dev = {
+		.platform_data = &nand_chip,
+		.parent = &ndfc_dev.dev,
+	}
+};
+
+/* Until this will be settled */
+static inline u32 of_get_int(struct device_node *np, const char *name)
+{
+	unsigned int size;
+	const u32 *prop = of_get_property(np, name, &size);
+
+	if ((prop == NULL) || (size != sizeof(int))) {
+		printk(KERN_WARNING "%s property missing!\n", __FUNCTION__);
+		return 0;
+	}
+
+	return *prop;
+}
+
+static int ppc4xx_setup_nand_chip_node(struct device_node *dev)
+{
+	unsigned int what = -ENODEV;
+	unsigned int size, amnt;
+	const u32 *prop;
+	int i;
+
+	/* process necessary properties */
+	what = of_get_int(dev, "chip-nr");
+	nand_chip.nr_chips = what;
+
+	what = of_get_int(dev, "chip-offset");
+	nand_chip.chip_offset = what;
+
+	what = of_get_int(dev, "chip-delay");
+	nand_chip.chip_delay = what;
+
+	what = of_get_int(dev, "ecc-bytes");
+	ecclayout.eccbytes = what;
+
+	what = of_get_int(dev, "chip-bank-settings");
+	chip_settings.bank_settings = what;
+
+	prop = of_get_property(dev, "ecc-pos", &size);
+	for (i = 0; i < (size/sizeof(unsigned int)); i++)
+		ecclayout.eccpos[i] = prop[i];
+
+	prop = of_get_property(dev, "ecc-oobfree", &size);
+	amnt = size/sizeof(unsigned int);
+
+	for (i = 0; i < amnt; i += 2) {
+		nand_chip.ecclayout->oobfree[i].offset = prop[i];
+		nand_chip.ecclayout->oobfree[i].length = prop[i+1];
+	}
+
+	nand_chip.nr_partitions = of_parse_flash_partitions(dev, &nand_parts);
+	nand_chip.partitions = nand_parts;
+
+	return 0;
+}
+
+static int __init ppc4xx_setup_nand_node(struct device_node *dev)
+{
+	struct device_node *child = NULL;
+	int ret = 0;
+
+	memset(&r, 0, sizeof(r));
+
+	/* generic NDFC register */
+	ret = of_address_to_resource(dev, 0, &r);
+	if (ret)
+		goto err;
+
+	/* Now let's create platform_data stuff based on dts entries */
+	ret = of_get_int(dev, "ccr-settings");
+
+	ndfc_settings.ccr_settings = ret;
+	ndfc_settings.ndfc_erpn = r.start & 0xf00000000ULL;
+
+	child = of_get_next_child(dev, NULL);
+	/* NAND platform device is sole, so assuming one child of ndfc node */
+	if (child != NULL)
+		ppc4xx_setup_nand_chip_node(child);
+
+	ndfc_dev.resource = &r;
+	nand_dev.resource = &r;
+
+	platform_device_register(&ndfc_dev);
+	platform_device_register(&nand_dev);
+
+err:
+	return ret;
+}
+
+static int ppc4xx_init_nand(void)
+{
+	struct device_node *np =
+		of_find_compatible_node(NULL, "nand", "ibm,ndfc");
+
+	if (np != NULL)
+		ppc4xx_setup_nand_node(np);
+
+	return 0;
+}
+arch_initcall(ppc4xx_init_nand);
drivers/mtd/mtdpart.c +61 -0
index 6174a97..cc620ee 100644
@@ -21,6 +21,10 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/compatmac.h>
 
+#ifdef CONFIG_PPC_MERGE
+#include <linux/of.h>
+#endif
+
 /* Our partition linked list */
 static LIST_HEAD(mtd_partitions);
 
@@ -557,6 +561,63 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
 	return ret;
 }
 
+#ifdef CONFIG_PPC_MERGE
+int of_parse_flash_partitions(struct device_node *dp,
+			      struct mtd_partition **mparts)
+{
+	int nr_parts = 0;
+	int i;
+	struct device_node *pp;
+	const char *partname;
+	struct mtd_partition *parts;
+
+	/* First count the subnodes */
+	for (pp = dp->child; pp; pp = pp->sibling)
+		nr_parts++;
+
+	if (nr_parts) {
+		parts = kzalloc(nr_parts * sizeof(struct mtd_partition),
+				GFP_KERNEL);
+		if (!parts) {
+			printk(KERN_ERR
+			       "Can't allocate the flash partition data!\n");
+			return -ENOMEM;
+		}
+
+		for (pp = dp->child, i = 0 ; pp; pp = pp->sibling, i++) {
+			const u32 *reg;
+			int len;
+
+			reg = of_get_property(pp, "reg", &len);
+			if (!reg || (len != 2*sizeof(u32))) {
+				printk(KERN_ERR "Invalid 'reg' on %s\n",
+				       dp->full_name);
+				kfree(parts);
+				parts = NULL;
+				return -EINVAL;
+			}
+			parts[i].offset = reg[0];
+			parts[i].size = reg[1];
+
+			partname = of_get_property(pp, "label", &len);
+			if (!partname)
+				partname = of_get_property(pp, "name", &len);
+			parts[i].name = (char *)partname;
+			if (of_get_property(pp, "read-only", &len))
+				parts[i].mask_flags = MTD_WRITEABLE;
+			(*mparts) = parts;
+		}
+	} else {
+		printk(KERN_ERR
+		       "Node %s does not seem to contain partitions definition!\n",
+		       dp->full_name);
+		return -EINVAL;
+	}
+
+	return nr_parts;
+}
+#endif
+
 EXPORT_SYMBOL_GPL(parse_mtd_partitions);
 EXPORT_SYMBOL_GPL(register_mtd_parser);
 EXPORT_SYMBOL_GPL(deregister_mtd_parser);
drivers/mtd/nand/ndfc.c +6 -0
index fd7a8d5..7901019 100644
@@ -24,7 +24,9 @@
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
+#ifndef CONFIG_PPC_MERGE
 #include <asm/ibm44x.h>
+#endif
 
 struct ndfc_nand_mtd {
 	struct mtd_info			mtd;
@@ -230,7 +232,11 @@ static int ndfc_nand_probe(struct platform_device *pdev)
 	struct ndfc_controller *ndfc = &ndfc_ctrl;
 	unsigned long long phys = settings->ndfc_erpn | res->start;
 
+#if !defined(CONFIG_PHYS_64BIT) || defined(CONFIG_PPC_MERGE)
+	ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+#else
 	ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+#endif
 	if (!ndfc->ndfcbase) {
 		printk(KERN_ERR "NDFC: ioremap failed\n");
 		return -EIO;
include/linux/mtd/partitions.h +2 -0
index da6b3d6..546a098 100644
@@ -68,6 +68,8 @@ extern int register_mtd_parser(struct mtd_part_parser *parser);
 extern int deregister_mtd_parser(struct mtd_part_parser *parser);
 extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
 				struct mtd_partition **pparts, unsigned long origin);
+extern int of_parse_flash_partitions(struct device_node *node,
+				     struct mtd_partition **parts);
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 

_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#2 lore raw
In reply to Stefan Roese

arch/powerpc/boot/dts/sequoia.dts line 128

Quoted 12 lines · Stefan Roese
arch/powerpc/boot/dts/sequoia.dts +4 -0
index 36be75b..9b15482 100644
@@ -122,6 +122,38 @@
 			interrupt-map-mask = <ffffffff>;
 		};
 
+		ndfc@1d0000000, {
+			device_type = "nand";
+			compatible = "ibm,ndfc";
+			reg = <1 d0000000 2000>;

I think this should be handled the way it's done for nor flash, since ndfc is relocatable within EBC address space.

Thanks,
Valentine.