[RFC][POWERPC] Add arch/powerpc 4xx NDFC (NAND) support

David Gibson david at gibson.dropbear.id.au
Wed Oct 10 16:38:57 EST 2007


On Wed, Oct 10, 2007 at 08:32:12AM +0200, Stefan Roese wrote:
> 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.
> 
> Signed-off-by: Stefan Roese <sr at denx.de>
> 
> ---
> commit 721a340398e66872b9cc7e8b630fc92a7681ca04
> tree ffbe1194146cb4fc324755f35c9062025b7ec0f6
> parent 26f571d7c968dbd30656fc1421eeb0d9088aaad9
> author Stefan Roese <sr at denx.de> Mon, 08 Oct 2007 16:00:49 +0200
> committer Stefan Roese <sr at denx.de> 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(-)
> 
> diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts
> index 36be75b..9b15482 100644
> --- a/arch/powerpc/boot/dts/sequoia.dts
> +++ b/arch/powerpc/boot/dts/sequoia.dts
> @@ -122,6 +122,38 @@
>  			interrupt-map-mask = <ffffffff>;
>  		};
>  
> +		ndfc at 1d0000000, {
> +			device_type = "nand";

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

> +			compatible = "ibm,ndfc";

This should probably have a more specific value for the revision in
addition to 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 at 0 {
> +				device_type = "nand-chip";

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

> +				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.

> +				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 at 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.

> +					label = "content";
> +					reg = <0 0>;
> +				};
> +			};
> +		};
> +
>  		POB0: opb {
>  		  	compatible = "ibm,opb-440epx", "ibm,opb";
>  			#address-cells = <1>;
> diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
> index 10ce674..d6195ee 100644
> --- a/arch/powerpc/platforms/44x/Makefile
> +++ b/arch/powerpc/platforms/44x/Makefile
> @@ -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
> diff --git a/arch/powerpc/platforms/44x/ndfc_of.c b/arch/powerpc/platforms/44x/ndfc_of.c
> new file mode 100644
> index 0000000..e5b41cf
> --- /dev/null
> +++ b/arch/powerpc/platforms/44x/ndfc_of.c
> @@ -0,0 +1,158 @@
> +/*
> + * PPC4xx NAND wrapper from device tree to platform device
> + *
> + * Stefan Roese <sr at denx.de>
> + *
> + * 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);
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index 6174a97..cc620ee 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
> @@ -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);
> diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
> index fd7a8d5..7901019 100644
> --- a/drivers/mtd/nand/ndfc.c
> +++ b/drivers/mtd/nand/ndfc.c
> @@ -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;
> diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
> index da6b3d6..546a098 100644
> --- a/include/linux/mtd/partitions.h
> +++ b/include/linux/mtd/partitions.h
> @@ -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
> Linuxppc-dev at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 

-- 
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



More information about the Linuxppc-dev mailing list