From 2099172d61abda1b793b499bb8edcaac4de2cdae Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 7 Sep 2007 13:23:53 +1000 Subject: [POWERPC] Document and implement an improved flash device binding for powerpc This replaces the binding for flash chips in booting-without-of.txt with an clarified and improved version. It also makes drivers/mtd/maps/physmap_of.c recognize this new binding. Finally it revises the Ebony device tree source to use the new binding as an example. Signed-off-by: David Gibson Acked-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- drivers/mtd/maps/physmap_of.c | 239 ++++++++++++++++++++++++++++++------------ 1 file changed, 174 insertions(+), 65 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bbb42c35b69..3df001bfee3 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -4,6 +4,9 @@ * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool * + * Revised to handle newer style flash binding by: + * Copyright (C) 2007 David Gibson, IBM Corporation. + * * 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 @@ -30,56 +33,135 @@ struct physmap_flash_info { struct map_info map; struct resource *res; #ifdef CONFIG_MTD_PARTITIONS - int nr_parts; struct mtd_partition *parts; #endif }; -static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; -#endif - #ifdef CONFIG_MTD_PARTITIONS -static int parse_flash_partitions(struct device_node *node, - struct mtd_partition **parts) +static int parse_obsolete_partitions(struct of_device *dev, + struct physmap_flash_info *info, + struct device_node *dp) { - int i, plen, retval = -ENOMEM; - const u32 *part; - const char *name; + int i, plen, nr_parts; + const struct { + u32 offset, len; + } *part; + const char *names; - part = of_get_property(node, "partitions", &plen); - if (part == NULL) - goto err; + part = of_get_property(dp, "partitions", &plen); + if (!part) + return -ENOENT; - retval = plen / (2 * sizeof(u32)); - *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL); - if (*parts == NULL) { + dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); + + nr_parts = plen / sizeof(part[0]); + + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), GFP_KERNEL); + if (!info->parts) { printk(KERN_ERR "Can't allocate the flash partition data!\n"); - goto err; + return -ENOMEM; } - name = of_get_property(node, "partition-names", &plen); + names = of_get_property(dp, "partition-names", &plen); - for (i = 0; i < retval; i++) { - (*parts)[i].offset = *part++; - (*parts)[i].size = *part & ~1; - if (*part++ & 1) /* bit 0 set signifies read only partition */ - (*parts)[i].mask_flags = MTD_WRITEABLE; + for (i = 0; i < nr_parts; i++) { + info->parts[i].offset = part->offset; + info->parts[i].size = part->len & ~1; + if (part->len & 1) /* bit 0 set signifies read only partition */ + info->parts[i].mask_flags = MTD_WRITEABLE; - if (name != NULL && plen > 0) { - int len = strlen(name) + 1; + if (names && (plen > 0)) { + int len = strlen(names) + 1; - (*parts)[i].name = (char *)name; + info->parts[i].name = (char *)names; plen -= len; - name += len; - } else - (*parts)[i].name = "unnamed"; + names += len; + } else { + info->parts[i].name = "unnamed"; + } + + part++; } -err: - return retval; + + return nr_parts; } -#endif + +static int __devinit process_partitions(struct physmap_flash_info *info, + struct of_device *dev) +{ + const char *partname; + static const char *part_probe_types[] + = { "cmdlinepart", "RedBoot", NULL }; + struct device_node *dp = dev->node, *pp; + int nr_parts, i; + + /* First look for RedBoot table or partitions on the command + * line, these take precedence over device tree information */ + nr_parts = parse_mtd_partitions(info->mtd, part_probe_types, + &info->parts, 0); + if (nr_parts > 0) { + add_mtd_partitions(info->mtd, info->parts, nr_parts); + return 0; + } + + /* First count the subnodes */ + nr_parts = 0; + for (pp = dp->child; pp; pp = pp->sibling) + nr_parts++; + + if (nr_parts) { + info->parts = kzalloc(nr_parts * sizeof(struct mtd_partition), + GFP_KERNEL); + if (!info->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))) { + dev_err(&dev->dev, "Invalid 'reg' on %s\n", + dp->full_name); + kfree(info->parts); + info->parts = NULL; + return -EINVAL; + } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; + + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; + + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; + } + } else { + nr_parts = parse_obsolete_partitions(dev, info, dp); + } + + if (nr_parts < 0) + return nr_parts; + + if (nr_parts > 0) + add_mtd_partitions(info->mtd, info->parts, nr_parts); + else + add_mtd_device(info->mtd); + + return 0; +} +#else /* MTD_PARTITIONS */ +static int __devinit process_partitions(struct physmap_flash_info *info, + struct device_node *dev) +{ + add_mtd_device(info->mtd); + return 0; +} +#endif /* MTD_PARTITIONS */ static int of_physmap_remove(struct of_device *dev) { @@ -92,7 +174,7 @@ static int of_physmap_remove(struct of_device *dev) if (info->mtd != NULL) { #ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts) { + if (info->parts) { del_mtd_partitions(info->mtd); kfree(info->parts); } else { @@ -115,17 +197,51 @@ static int of_physmap_remove(struct of_device *dev) return 0; } +/* Helper function to handle probing of the obsolete "direct-mapped" + * compatible binding, which has an extra "probe-type" property + * describing the type of flash probe necessary. */ +static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, + struct map_info *map) +{ + struct device_node *dp = dev->node; + const char *of_probe; + struct mtd_info *mtd; + static const char *rom_probe_types[] + = { "cfi_probe", "jedec_probe", "map_rom"}; + int i; + + dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" " + "flash binding\n"); + + of_probe = of_get_property(dp, "probe-type", NULL); + if (!of_probe) { + for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) { + mtd = do_map_probe(rom_probe_types[i], map); + if (mtd) + return mtd; + } + return NULL; + } else if (strcmp(of_probe, "CFI") == 0) { + return do_map_probe("cfi_probe", map); + } else if (strcmp(of_probe, "JEDEC") == 0) { + return do_map_probe("jedec_probe", map); + } else { + if (strcmp(of_probe, "ROM") != 0) + dev_dbg(&dev->dev, "obsolete_probe: don't know probe type " + "'%s', mapping as rom\n", of_probe); + return do_map_probe("mtd_rom", map); + } +} + static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match) { struct device_node *dp = dev->node; struct resource res; struct physmap_flash_info *info; - const char **probe_type; - const char *of_probe; + const char *probe_type = (const char *)match->data; const u32 *width; int err; - if (of_address_to_resource(dp, 0, &res)) { dev_err(&dev->dev, "Can't get the flash mapping!\n"); err = -EINVAL; @@ -174,21 +290,11 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev simple_map_init(&info->map); - of_probe = of_get_property(dp, "probe-type", NULL); - if (of_probe == NULL) { - probe_type = rom_probe_types; - for (; info->mtd == NULL && *probe_type != NULL; probe_type++) - info->mtd = do_map_probe(*probe_type, &info->map); - } else if (!strcmp(of_probe, "CFI")) - info->mtd = do_map_probe("cfi_probe", &info->map); - else if (!strcmp(of_probe, "JEDEC")) - info->mtd = do_map_probe("jedec_probe", &info->map); - else { - if (strcmp(of_probe, "ROM")) - dev_dbg(&dev->dev, "map_probe: don't know probe type " - "'%s', mapping as rom\n", of_probe); - info->mtd = do_map_probe("mtd_rom", &info->map); - } + if (probe_type) + info->mtd = do_map_probe(probe_type, &info->map); + else + info->mtd = obsolete_probe(dev, &info->map); + if (info->mtd == NULL) { dev_err(&dev->dev, "map_probe failed\n"); err = -ENXIO; @@ -196,19 +302,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev } info->mtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); - if (err > 0) { - add_mtd_partitions(info->mtd, info->parts, err); - } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) { - dev_info(&dev->dev, "Using OF partition information\n"); - add_mtd_partitions(info->mtd, info->parts, err); - info->nr_parts = err; - } else -#endif - - add_mtd_device(info->mtd); - return 0; + return process_partitions(info, dev); err_out: of_physmap_remove(dev); @@ -220,6 +314,21 @@ err_out: } static struct of_device_id of_physmap_match[] = { + { + .compatible = "cfi-flash", + .data = (void *)"cfi_probe", + }, + { + /* FIXME: JEDEC chips can't be safely and reliably + * probed, although the mtd code gets it right in + * practice most of the time. We should use the + * vendor and device ids specified by the binding to + * bypass the heuristic probe code, but the mtd layer + * provides, at present, no interface for doing so + * :(. */ + .compatible = "jedec-flash", + .data = (void *)"jedec_probe", + }, { .type = "rom", .compatible = "direct-mapped" -- cgit v1.2.3