[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 <david@gibson.dropbear.id.au>
Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
David Gibson 2007-09-07 13:23:53 +10:00 committed by Paul Mackerras
parent 3c607ce2a3
commit 2099172d61
3 changed files with 248 additions and 107 deletions

View File

@ -50,7 +50,7 @@ Table of Contents
g) Freescale SOC SEC Security Engines g) Freescale SOC SEC Security Engines
h) Board Control and Status (BCSR) h) Board Control and Status (BCSR)
i) Freescale QUICC Engine module (QE) i) Freescale QUICC Engine module (QE)
j) Flash chip nodes j) CFI or JEDEC memory-mapped NOR flash
k) Global Utilities Block k) Global Utilities Block
VII - Specifying interrupt information for devices 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 Flash chips (Memory Technology Devices) are often used for solid state
file systems on embedded devices. 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.
- device_type : has to be "rom" For JEDEC compatible devices, the following additional properties
- compatible : Should specify what this flash device is compatible with. are defined:
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 : - vendor-id : Contains the flash chip's vendor id (1 byte).
- device-id : Contains the flash chip's device id (1 byte).
- partitions : Several pairs of 32-bit values where the first value is In addition to the information on the flash bank itself, the
partition's offset from the start of the device and the second one is device tree may optionally contain additional information
partition size in bytes with LSB used to signify a read only describing partitions of the flash address space. This can be
partition (so, the partition size should always be an even number). used on platforms which have strong conventions about which
- partition-names : The list of concatenated zero terminated strings portions of the flash are used for what purposes, but which don't
representing the partition names. use an on-flash partition table such as RedBoot.
- probe-type : The type of probe which should be done for the chip
(JEDEC vs CFI actually). Valid ONLY for NOR flashes.
Example: 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@ff000000 { Flash partitions
device_type = "rom"; - reg : The partition's offset and size within the flash bank.
compatible = "direct-mapped"; - label : (optional) The label / name for this flash partition.
probe-type = "CFI"; If omitted, the label is taken from the node name (excluding
reg = <ff000000 01000000>; the unit address).
bank-width = <4>; - read-only : (optional) This parameter, if present, is a hint to
partitions = <00000000 00f80000 Linux that this flash partition should only be mounted
00f80000 00080001>; read-only. This is usually used for flash partitions
partition-names = "fs\0firmware"; containing early-boot firmware images or data which should not
}; be clobbered.
Example:
flash@ff000000 {
compatible = "amd,am29lv128ml", "cfi-flash";
reg = <ff000000 01000000>;
bank-width = <4>;
device-width = <1>;
#address-cells = <1>;
#size-cells = <1>;
fs@0 {
label = "fs";
reg = <0 f80000>;
};
firmware@f80000 {
label ="firmware";
reg = <f80000 80000>;
read-only;
};
};
k) Global Utilities Block k) Global Utilities Block

View File

@ -138,13 +138,16 @@
interrupt-parent = <&UIC1>; interrupt-parent = <&UIC1>;
small-flash@0,80000 { small-flash@0,80000 {
device_type = "rom"; compatible = "jedec-flash";
compatible = "direct-mapped";
probe-type = "JEDEC";
bank-width = <1>; bank-width = <1>;
partitions = <0 80000>;
partition-names = "OpenBIOS";
reg = <0 80000 80000>; reg = <0 80000 80000>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "OpenBIOS";
reg = <0 80000>;
read-only;
};
}; };
ds1743@1,0 { ds1743@1,0 {
@ -154,14 +157,19 @@
}; };
large-flash@2,0 { large-flash@2,0 {
device_type = "rom"; compatible = "jedec-flash";
compatible = "direct-mapped";
probe-type = "JEDEC";
bank-width = <1>; bank-width = <1>;
partitions = <0 380000
380000 80000>;
partition-names = "fs", "firmware";
reg = <2 0 400000>; 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 { ir@3,0 {

View File

@ -4,6 +4,9 @@
* Copyright (C) 2006 MontaVista Software Inc. * Copyright (C) 2006 MontaVista Software Inc.
* Author: Vitaly Wool <vwool@ru.mvista.com> * Author: Vitaly Wool <vwool@ru.mvista.com>
* *
* 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 * 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 * 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 * 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 map_info map;
struct resource *res; struct resource *res;
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
int nr_parts;
struct mtd_partition *parts; struct mtd_partition *parts;
#endif #endif
}; };
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; static int parse_obsolete_partitions(struct of_device *dev,
#endif struct physmap_flash_info *info,
struct device_node *dp)
#ifdef CONFIG_MTD_PARTITIONS
static int parse_flash_partitions(struct device_node *node,
struct mtd_partition **parts)
{ {
int i, plen, retval = -ENOMEM; int i, plen, nr_parts;
const u32 *part; const struct {
const char *name; u32 offset, len;
} *part;
const char *names;
part = of_get_property(node, "partitions", &plen); part = of_get_property(dp, "partitions", &plen);
if (part == NULL) if (!part)
goto err; return -ENOENT;
retval = plen / (2 * sizeof(u32)); dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
*parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
if (*parts == NULL) { 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"); 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++) { for (i = 0; i < nr_parts; i++) {
(*parts)[i].offset = *part++; info->parts[i].offset = part->offset;
(*parts)[i].size = *part & ~1; info->parts[i].size = part->len & ~1;
if (*part++ & 1) /* bit 0 set signifies read only partition */ if (part->len & 1) /* bit 0 set signifies read only partition */
(*parts)[i].mask_flags = MTD_WRITEABLE; info->parts[i].mask_flags = MTD_WRITEABLE;
if (name != NULL && plen > 0) { if (names && (plen > 0)) {
int len = strlen(name) + 1; int len = strlen(names) + 1;
(*parts)[i].name = (char *)name; info->parts[i].name = (char *)names;
plen -= len; plen -= len;
name += len; names += len;
} else } else {
(*parts)[i].name = "unnamed"; 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) 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) { if (info->mtd != NULL) {
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS
if (info->nr_parts) { if (info->parts) {
del_mtd_partitions(info->mtd); del_mtd_partitions(info->mtd);
kfree(info->parts); kfree(info->parts);
} else { } else {
@ -115,17 +197,51 @@ static int of_physmap_remove(struct of_device *dev)
return 0; 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) static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
{ {
struct device_node *dp = dev->node; struct device_node *dp = dev->node;
struct resource res; struct resource res;
struct physmap_flash_info *info; struct physmap_flash_info *info;
const char **probe_type; const char *probe_type = (const char *)match->data;
const char *of_probe;
const u32 *width; const u32 *width;
int err; int err;
if (of_address_to_resource(dp, 0, &res)) { if (of_address_to_resource(dp, 0, &res)) {
dev_err(&dev->dev, "Can't get the flash mapping!\n"); dev_err(&dev->dev, "Can't get the flash mapping!\n");
err = -EINVAL; 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); simple_map_init(&info->map);
of_probe = of_get_property(dp, "probe-type", NULL); if (probe_type)
if (of_probe == NULL) { info->mtd = do_map_probe(probe_type, &info->map);
probe_type = rom_probe_types; else
for (; info->mtd == NULL && *probe_type != NULL; probe_type++) info->mtd = obsolete_probe(dev, &info->map);
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 (info->mtd == NULL) { if (info->mtd == NULL) {
dev_err(&dev->dev, "map_probe failed\n"); dev_err(&dev->dev, "map_probe failed\n");
err = -ENXIO; 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; info->mtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS return process_partitions(info, dev);
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;
err_out: err_out:
of_physmap_remove(dev); of_physmap_remove(dev);
@ -220,6 +314,21 @@ err_out:
} }
static struct of_device_id of_physmap_match[] = { 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", .type = "rom",
.compatible = "direct-mapped" .compatible = "direct-mapped"