From 0d279d47612d1b63155a1d9637a6fc5143dad594 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 30 Jul 2007 15:55:02 +1000 Subject: [POWERPC] Fixes to allow use of Ebony's flash chips through physmap_of This patch contains a handful of small fixes to allow the Ebony's flash to be exposed as MTD devices via the physmap_of driver. Specifically it: - Makes a small addition to the device tree and zImage wrapper to record the correct address for the flash in the device tree based on the board switches as reported via an FPGA register. - Prohibits building the old hard-coded "Ebony" flash map on arch/powerpc kernels, in favour of using physmap_of's device tree based approach. - Enables MTD and physmap_of in the Ebony defconfig. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- drivers/mtd/maps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd/maps') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index cc6c73442435..6cd132c75187 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -362,7 +362,7 @@ config MTD_WALNUT config MTD_EBONY tristate "Flash devices mapped on IBM 440GP Ebony" - depends on MTD_JEDECPROBE && EBONY + depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE help This enables access routines for the flash chips on the IBM 440GP Ebony board. If you have one of these boards and would like to -- cgit v1.2.3 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 --- Documentation/powerpc/booting-without-of.txt | 92 +++++++---- arch/powerpc/boot/dts/ebony.dts | 30 ++-- drivers/mtd/maps/physmap_of.c | 239 +++++++++++++++++++-------- 3 files changed, 251 insertions(+), 110 deletions(-) (limited to 'drivers/mtd/maps') diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 76733a3962f0..20e0e6cb0347 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -50,7 +50,7 @@ Table of Contents g) Freescale SOC SEC Security Engines h) Board Control and Status (BCSR) i) Freescale QUICC Engine module (QE) - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash k) Global Utilities Block VII - Specifying interrupt information for devices @@ -1757,45 +1757,69 @@ platforms are moved over to use the flattened-device-tree model. }; }; - j) Flash chip nodes + j) CFI or JEDEC memory-mapped NOR flash Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. - Required properties: + - compatible : should contain the specific model of flash chip(s) + used, if known, followed by either "cfi-flash" or "jedec-flash" + - reg : Address range of the flash chip + - bank-width : Width (in bytes) of the flash bank. Equal to the + device width times the number of interleaved chips. + - device-width : (optional) Width of a single flash chip. If + omitted, assumed to be equal to 'bank-width'. + - #address-cells, #size-cells : Must be present if the flash has + sub-nodes representing partitions (see below). In this case + both #address-cells and #size-cells must be equal to 1. + + For JEDEC compatible devices, the following additional properties + are defined: + + - vendor-id : Contains the flash chip's vendor id (1 byte). + - device-id : Contains the flash chip's device id (1 byte). + + In addition to the information on the flash bank itself, the + device tree may optionally contain additional information + describing partitions of the flash address space. This can be + used on platforms which have strong conventions about which + portions of the flash are used for what purposes, but which don't + use an on-flash partition table such as RedBoot. + + Each partition is represented as a sub-node of the flash device. + Each node's name represents the name of the corresponding + partition of the flash device. + + Flash partitions + - reg : The partition's offset and size within the flash bank. + - label : (optional) The label / name for this flash partition. + If omitted, the label is taken from the node name (excluding + the unit address). + - read-only : (optional) This parameter, if present, is a hint to + Linux that this flash partition should only be mounted + read-only. This is usually used for flash partitions + containing early-boot firmware images or data which should not + be clobbered. - - device_type : has to be "rom" - - compatible : Should specify what this flash device is compatible with. - Currently, this is most likely to be "direct-mapped" (which - corresponds to the MTD physmap mapping driver). - - reg : Offset and length of the register set (or memory mapping) for - the device. - - bank-width : Width of the flash data bus in bytes. Required - for the NOR flashes (compatible == "direct-mapped" and others) ONLY. - - Recommended properties : - - - partitions : Several pairs of 32-bit values where the first value is - partition's offset from the start of the device and the second one is - partition size in bytes with LSB used to signify a read only - partition (so, the partition size should always be an even number). - - partition-names : The list of concatenated zero terminated strings - representing the partition names. - - probe-type : The type of probe which should be done for the chip - (JEDEC vs CFI actually). Valid ONLY for NOR flashes. - - Example: + Example: - flash@ff000000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "CFI"; - reg = ; - bank-width = <4>; - partitions = <00000000 00f80000 - 00f80000 00080001>; - partition-names = "fs\0firmware"; - }; + flash@ff000000 { + compatible = "amd,am29lv128ml", "cfi-flash"; + reg = ; + bank-width = <4>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + fs@0 { + label = "fs"; + reg = <0 f80000>; + }; + firmware@f80000 { + label ="firmware"; + reg = ; + read-only; + }; + }; k) Global Utilities Block diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts index 37599bda5500..bc259972aaa0 100644 --- a/arch/powerpc/boot/dts/ebony.dts +++ b/arch/powerpc/boot/dts/ebony.dts @@ -138,13 +138,16 @@ interrupt-parent = <&UIC1>; small-flash@0,80000 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 80000>; - partition-names = "OpenBIOS"; reg = <0 80000 80000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "OpenBIOS"; + reg = <0 80000>; + read-only; + }; }; ds1743@1,0 { @@ -154,14 +157,19 @@ }; large-flash@2,0 { - device_type = "rom"; - compatible = "direct-mapped"; - probe-type = "JEDEC"; + compatible = "jedec-flash"; bank-width = <1>; - partitions = <0 380000 - 380000 80000>; - partition-names = "fs", "firmware"; reg = <2 0 400000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "fs"; + reg = <0 380000>; + }; + partition@380000 { + label = "firmware"; + reg = <380000 80000>; + }; }; ir@3,0 { diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bbb42c35b69b..3df001bfee36 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 From 8d9ae994d8fce807fc90fb8e3b6ac8df1cc7dce6 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Sat, 15 Sep 2007 04:54:12 +1000 Subject: [POWERPC] Make partitions optional in physmap_of The latest physmap_of driver has a small error where it will fail the probe with: physmap-flash: probe of fff00000.small-flas failed with error -2 if there are no partition subnodes in the device tree and the old style binding is not used. Since partition definitions are optional, the probe should still succeed. Signed-off-by: Josh Boyer Acked-by: David Gibson --- drivers/mtd/maps/physmap_of.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd/maps') diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 3df001bfee36..096dd47b5d5d 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -142,6 +142,8 @@ static int __devinit process_partitions(struct physmap_flash_info *info, } } else { nr_parts = parse_obsolete_partitions(dev, info, dp); + if (nr_parts == -ENOENT) + nr_parts = 0; } if (nr_parts < 0) -- cgit v1.2.3 From c4d5e375470862fd741f93bf0686d7ac2f7fdce4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2007 11:22:25 +1000 Subject: [POWERPC] Cleanups for physmap_of.c (v2) This patch includes a whole batch of smallish cleanups for drivers/mtd/physmap_of.c. - A bunch of uneeded #includes are removed - We switch to the modern linux/of.h etc. in place of asm/prom.h - Use some helper macros to avoid some ugly inline #ifdefs - A few lines of unreachable code are removed - A number of indentation / line-wrapping fixes - More consistent use of kernel idioms such as if (!p) instead of if (p == NULL) - Clarify some printk()s and other informative strings. - parse_obsolete_partitions() now returns 0 if no partition information is found, instead of returning -ENOENT which the caller had to handle specially. - (the big one) Despite the name, this driver really has nothing to do with drivers/mtd/physmap.c. The fact that the flash chips must be physically direct mapped is a constrant, but doesn't really say anything about the actual purpose of this driver, which is to instantiate MTD devices based on information from the device tree. Therefore the physmap name is replaced everywhere within the file with "of_flash". The file itself and the Kconfig option is not renamed for now (so that the diff is actually a diff). That can come later. Signed-off-by: David Gibson Signed-off-by: Josh Boyer --- drivers/mtd/maps/physmap_of.c | 224 +++++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 125 deletions(-) (limited to 'drivers/mtd/maps') diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 096dd47b5d5d..cf75a566442e 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -1,5 +1,5 @@ /* - * Normal mappings of chips in physical memory for OF devices + * Flash mappings described by the OF (or flattened) device tree * * Copyright (C) 2006 MontaVista Software Inc. * Author: Vitaly Wool @@ -15,20 +15,15 @@ #include #include -#include #include -#include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include -struct physmap_flash_info { +struct of_flash { struct mtd_info *mtd; struct map_info map; struct resource *res; @@ -38,8 +33,10 @@ struct physmap_flash_info { }; #ifdef CONFIG_MTD_PARTITIONS +#define OF_FLASH_PARTS(info) ((info)->parts) + static int parse_obsolete_partitions(struct of_device *dev, - struct physmap_flash_info *info, + struct of_flash *info, struct device_node *dp) { int i, plen, nr_parts; @@ -50,17 +47,15 @@ static int parse_obsolete_partitions(struct of_device *dev, part = of_get_property(dp, "partitions", &plen); if (!part) - return -ENOENT; + return 0; /* No partitions found */ 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"); + info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); + if (!info->parts) return -ENOMEM; - } names = of_get_property(dp, "partition-names", &plen); @@ -86,8 +81,8 @@ static int parse_obsolete_partitions(struct of_device *dev, return nr_parts; } -static int __devinit process_partitions(struct physmap_flash_info *info, - struct of_device *dev) +static int __devinit parse_partitions(struct of_flash *info, + struct of_device *dev) { const char *partname; static const char *part_probe_types[] @@ -109,89 +104,68 @@ static int __devinit process_partitions(struct physmap_flash_info *info, 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; - } + if (nr_parts == 0) + return parse_obsolete_partitions(dev, info, dp); + + info->parts = kzalloc(nr_parts * sizeof(*info->parts), + GFP_KERNEL); + if (!info->parts) + 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; + 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; } - } else { - nr_parts = parse_obsolete_partitions(dev, info, dp); - if (nr_parts == -ENOENT) - nr_parts = 0; - } + info->parts[i].offset = reg[0]; + info->parts[i].size = reg[1]; - if (nr_parts < 0) - return nr_parts; + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + info->parts[i].name = (char *)partname; - if (nr_parts > 0) - add_mtd_partitions(info->mtd, info->parts, nr_parts); - else - add_mtd_device(info->mtd); + if (of_get_property(pp, "read-only", &len)) + info->parts[i].mask_flags = MTD_WRITEABLE; + } - return 0; + return nr_parts; } #else /* MTD_PARTITIONS */ -static int __devinit process_partitions(struct physmap_flash_info *info, - struct device_node *dev) -{ - add_mtd_device(info->mtd); - return 0; -} +#define OF_FLASH_PARTS(info) (0) +#define parse_partitions(info, dev) (0) #endif /* MTD_PARTITIONS */ -static int of_physmap_remove(struct of_device *dev) +static int of_flash_remove(struct of_device *dev) { - struct physmap_flash_info *info; + struct of_flash *info; info = dev_get_drvdata(&dev->dev); - if (info == NULL) + if (!info) return 0; dev_set_drvdata(&dev->dev, NULL); - if (info->mtd != NULL) { -#ifdef CONFIG_MTD_PARTITIONS - if (info->parts) { + if (info->mtd) { + if (OF_FLASH_PARTS(info)) { del_mtd_partitions(info->mtd); - kfree(info->parts); + kfree(OF_FLASH_PARTS(info)); } else { del_mtd_device(info->mtd); } -#else - del_mtd_device(info->mtd); -#endif map_destroy(info->mtd); } - if (info->map.virt != NULL) + if (info->map.virt) iounmap(info->map.virt); - if (info->res != NULL) { + if (info->res) { release_resource(info->res); kfree(info->res); } @@ -229,52 +203,49 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, 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); + dev_warn(&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) +static int __devinit of_flash_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 *)match->data; + struct of_flash *info; + const char *probe_type = match->data; const u32 *width; int err; + err = -ENXIO; if (of_address_to_resource(dp, 0, &res)) { - dev_err(&dev->dev, "Can't get the flash mapping!\n"); - err = -EINVAL; + dev_err(&dev->dev, "Can't get IO address from device tree\n"); goto err_out; } - dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n", - (unsigned long long)res.end - res.start + 1, - (unsigned long long)res.start); + dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", + (unsigned long long)res.start, (unsigned long long)res.end); - info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); - if (info == NULL) { - err = -ENOMEM; + err = -ENOMEM; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) goto err_out; - } memset(info, 0, sizeof(*info)); dev_set_drvdata(&dev->dev, info); + err = -EBUSY; info->res = request_mem_region(res.start, res.end - res.start + 1, - dev->dev.bus_id); - if (info->res == NULL) { - dev_err(&dev->dev, "Could not reserve memory region\n"); - err = -ENOMEM; + dev->dev.bus_id); + if (!info->res) goto err_out; - } + err = -ENXIO; width = of_get_property(dp, "bank-width", NULL); - if (width == NULL) { - dev_err(&dev->dev, "Can't get the flash bank width!\n"); - err = -EINVAL; + if (!width) { + dev_err(&dev->dev, "Can't get bank width from device tree\n"); goto err_out; } @@ -283,10 +254,10 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev info->map.size = res.end - res.start + 1; info->map.bankwidth = *width; + err = -ENOMEM; info->map.virt = ioremap(info->map.phys, info->map.size); - if (info->map.virt == NULL) { - dev_err(&dev->dev, "Failed to ioremap flash region\n"); - err = EIO; + if (!info->map.virt) { + dev_err(&dev->dev, "Failed to ioremap() flash region\n"); goto err_out; } @@ -297,25 +268,30 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev else info->mtd = obsolete_probe(dev, &info->map); - if (info->mtd == NULL) { - dev_err(&dev->dev, "map_probe failed\n"); - err = -ENXIO; + err = -ENXIO; + if (!info->mtd) { + dev_err(&dev->dev, "do_map_probe() failed\n"); goto err_out; } info->mtd->owner = THIS_MODULE; - return process_partitions(info, dev); + err = parse_partitions(info, dev); + if (err < 0) + goto err_out; -err_out: - of_physmap_remove(dev); - return err; + if (err > 0) + add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err); + else + add_mtd_device(info->mtd); return 0; - +err_out: + of_flash_remove(dev); + return err; } -static struct of_device_id of_physmap_match[] = { +static struct of_device_id of_flash_match[] = { { .compatible = "cfi-flash", .data = (void *)"cfi_probe", @@ -337,30 +313,28 @@ static struct of_device_id of_physmap_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, of_flash_match); -MODULE_DEVICE_TABLE(of, of_physmap_match); - - -static struct of_platform_driver of_physmap_flash_driver = { - .name = "physmap-flash", - .match_table = of_physmap_match, - .probe = of_physmap_probe, - .remove = of_physmap_remove, +static struct of_platform_driver of_flash_driver = { + .name = "of-flash", + .match_table = of_flash_match, + .probe = of_flash_probe, + .remove = of_flash_remove, }; -static int __init of_physmap_init(void) +static int __init of_flash_init(void) { - return of_register_platform_driver(&of_physmap_flash_driver); + return of_register_platform_driver(&of_flash_driver); } -static void __exit of_physmap_exit(void) +static void __exit of_flash_exit(void) { - of_unregister_platform_driver(&of_physmap_flash_driver); + of_unregister_platform_driver(&of_flash_driver); } -module_init(of_physmap_init); -module_exit(of_physmap_exit); +module_init(of_flash_init); +module_exit(of_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vitaly Wool "); -MODULE_DESCRIPTION("Configurable MTD map driver for OF"); +MODULE_DESCRIPTION("Device tree based MTD map driver"); -- cgit v1.2.3