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 <[EMAIL PROTECTED]> > > --- > 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(-) > > 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>; > }; > > + [EMAIL PROTECTED], { > + 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>; > + > + [EMAIL PROTECTED] { > + 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>; > + > + [EMAIL PROTECTED] { 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 <[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); > 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@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 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev