* [PATCH] mtd: physmap_of: Add multiple regions and concatenation support
@ 2009-04-03 9:55 Stefan Roese
2009-04-03 14:04 ` Grant Likely
0 siblings, 1 reply; 3+ messages in thread
From: Stefan Roese @ 2009-04-03 9:55 UTC (permalink / raw)
To: linux-mtd, linuxppc-dev; +Cc: Grant Likely
This patch adds support to handle multiple non-identical chips in one
flash device tree node. It also adds concat support to physmap_of. This
makes it possible to support e.g. the Intel P30 48F4400 chips which
internally consists of 2 non-identical NOR chips on one die. Additionally
partitions now can span over multiple chips.
To describe such a chip's, multiple "reg" tuples are now supported in one
flash device tree node. Here an dts example:
flash@f0000000,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0 0x00000000 0x02000000
0 0x02000000 0x02000000>;
bank-width = <2>;
partition@0 {
label = "test-part1";
reg = <0 0x04000000>;
};
};
Signed-off-by: Stefan Roese <sr@denx.de>
CC: Grant Likely <grant.likely@secretlab.ca>
---
drivers/mtd/maps/physmap_of.c | 174 ++++++++++++++++++++++++++++-------------
1 files changed, 120 insertions(+), 54 deletions(-)
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 5fcfec0..c1c2d08 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -20,13 +20,17 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#define MAX_RESOURCES 4
+
struct of_flash {
- struct mtd_info *mtd;
- struct map_info map;
- struct resource *res;
+ struct mtd_info *mtd[MAX_RESOURCES];
+ struct mtd_info *cmtd;
+ struct map_info map[MAX_RESOURCES];
+ struct resource *res[MAX_RESOURCES];
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
#endif
@@ -88,28 +92,40 @@ static int parse_obsolete_partitions(struct of_device *dev,
static int of_flash_remove(struct of_device *dev)
{
struct of_flash *info;
+ int i;
info = dev_get_drvdata(&dev->dev);
if (!info)
return 0;
dev_set_drvdata(&dev->dev, NULL);
- if (info->mtd) {
+#ifdef CONFIG_MTD_CONCAT
+ if (info->cmtd != info->mtd[0]) {
+ del_mtd_device(info->cmtd);
+ mtd_concat_destroy(info->cmtd);
+ }
+#endif
+
+ if (info->cmtd) {
if (OF_FLASH_PARTS(info)) {
- del_mtd_partitions(info->mtd);
+ del_mtd_partitions(info->cmtd);
kfree(OF_FLASH_PARTS(info));
} else {
- del_mtd_device(info->mtd);
+ del_mtd_device(info->cmtd);
}
- map_destroy(info->mtd);
}
- if (info->map.virt)
- iounmap(info->map.virt);
+ for (i = 0; i < MAX_RESOURCES; i++) {
+ if (info->mtd[i])
+ map_destroy(info->mtd[i]);
+
+ if (info->map[i].virt)
+ iounmap(info->map[i].virt);
- if (info->res) {
- release_resource(info->res);
- kfree(info->res);
+ if (info->res[i]) {
+ release_resource(info->res[i]);
+ kfree(info->res[i]);
+ }
}
return 0;
@@ -164,15 +180,25 @@ static int __devinit of_flash_probe(struct of_device *dev,
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 IO address from device tree\n");
+ int i;
+ int count;
+ const u32 *p;
+ int devices_found = 0;
+
+ /*
+ * Get number of "reg" tuples. Scan for MTD devices on area's
+ * described by each "reg" region. This makes it possible (including
+ * the concat support) to support the Intel P30 48F4400 chips which
+ * consists internally of 2 non-identical NOR chips on one die.
+ */
+ p = of_get_property(dp, "reg", &count);
+ if (count % 12 != 0) {
+ dev_err(&dev->dev, "Malformed reg property on %s\n",
+ dev->node->full_name);
+ err = -EINVAL;
goto err_out;
}
-
- dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
- (unsigned long long)res.start, (unsigned long long)res.end);
+ count /= 12;
err = -ENOMEM;
info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -181,50 +207,90 @@ static int __devinit of_flash_probe(struct of_device *dev,
dev_set_drvdata(&dev->dev, info);
- err = -EBUSY;
- info->res = request_mem_region(res.start, res.end - res.start + 1,
- dev_name(&dev->dev));
- if (!info->res)
- goto err_out;
+ for (i = 0; i < count; i++) {
+ err = -ENXIO;
+ if (of_address_to_resource(dp, i, &res)) {
+ dev_err(&dev->dev, "Can't get IO address from device"
+ " tree\n");
+ goto err_out;
+ }
- err = -ENXIO;
- width = of_get_property(dp, "bank-width", NULL);
- if (!width) {
- dev_err(&dev->dev, "Can't get bank width from device tree\n");
- goto err_out;
- }
+ dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
+ (unsigned long long)res.start,
+ (unsigned long long)res.end);
+
+ err = -EBUSY;
+ info->res[i] = request_mem_region(res.start, res.end -
+ res.start + 1,
+ dev_name(&dev->dev));
+ if (!info->res[i])
+ goto err_out;
+
+ err = -ENXIO;
+ width = of_get_property(dp, "bank-width", NULL);
+ if (!width) {
+ dev_err(&dev->dev, "Can't get bank width from device"
+ " tree\n");
+ goto err_out;
+ }
- info->map.name = dev_name(&dev->dev);
- info->map.phys = res.start;
- info->map.size = res.end - res.start + 1;
- info->map.bankwidth = *width;
+ info->map[i].name = dev_name(&dev->dev);
+ info->map[i].phys = res.start;
+ info->map[i].size = res.end - res.start + 1;
+ info->map[i].bankwidth = *width;
+
+ err = -ENOMEM;
+ info->map[i].virt = ioremap(info->map[i].phys,
+ info->map[i].size);
+ if (!info->map[i].virt) {
+ dev_err(&dev->dev, "Failed to ioremap() flash"
+ " region\n");
+ goto err_out;
+ }
- err = -ENOMEM;
- info->map.virt = ioremap(info->map.phys, info->map.size);
- if (!info->map.virt) {
- dev_err(&dev->dev, "Failed to ioremap() flash region\n");
- goto err_out;
- }
+ simple_map_init(&info->map[i]);
- simple_map_init(&info->map);
+ if (probe_type)
+ info->mtd[i] = do_map_probe(probe_type, &info->map[i]);
+ else
+ info->mtd[i] = obsolete_probe(dev, &info->map[i]);
- if (probe_type)
- info->mtd = do_map_probe(probe_type, &info->map);
- else
- info->mtd = obsolete_probe(dev, &info->map);
+ err = -ENXIO;
+ if (!info->mtd[i]) {
+ dev_err(&dev->dev, "do_map_probe() failed\n");
+ goto err_out;
+ } else {
+ devices_found++;
+ }
+ info->mtd[i]->owner = THIS_MODULE;
+ }
- err = -ENXIO;
- if (!info->mtd) {
- dev_err(&dev->dev, "do_map_probe() failed\n");
- goto err_out;
+ err = 0;
+ if (devices_found == 1) {
+ info->cmtd = info->mtd[0];
+ } else if (devices_found > 1) {
+ /*
+ * We detected multiple devices. Concatenate them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ info->cmtd = mtd_concat_create(info->mtd, devices_found,
+ dev_name(&dev->dev));
+ if (info->cmtd == NULL)
+ err = -ENXIO;
+#else
+ printk(KERN_ERR "physmap_of: multiple devices "
+ "found but MTD concat support disabled.\n");
+ err = -ENXIO;
+#endif
}
- info->mtd->owner = THIS_MODULE;
+ if (err)
+ goto err_out;
#ifdef CONFIG_MTD_PARTITIONS
/* First look for RedBoot table or partitions on the command
* line, these take precedence over device tree information */
- err = parse_mtd_partitions(info->mtd, part_probe_types,
- &info->parts, 0);
+ err = parse_mtd_partitions(info->cmtd, part_probe_types,
+ &info->parts, 0);
if (err < 0)
return err;
@@ -243,10 +309,10 @@ static int __devinit of_flash_probe(struct of_device *dev,
}
if (err > 0)
- add_mtd_partitions(info->mtd, info->parts, err);
+ add_mtd_partitions(info->cmtd, info->parts, err);
else
#endif
- add_mtd_device(info->mtd);
+ add_mtd_device(info->cmtd);
return 0;
--
1.6.2.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] mtd: physmap_of: Add multiple regions and concatenation support
2009-04-03 9:55 [PATCH] mtd: physmap_of: Add multiple regions and concatenation support Stefan Roese
@ 2009-04-03 14:04 ` Grant Likely
2009-04-06 7:43 ` Stefan Roese
0 siblings, 1 reply; 3+ messages in thread
From: Grant Likely @ 2009-04-03 14:04 UTC (permalink / raw)
To: Stefan Roese; +Cc: linuxppc-dev, devicetree-discuss, linux-mtd
On Fri, Apr 3, 2009 at 3:55 AM, Stefan Roese <sr@denx.de> wrote:
> This patch adds support to handle multiple non-identical chips in one
> flash device tree node. It also adds concat support to physmap_of. This
> makes it possible to support e.g. the Intel P30 48F4400 chips which
> internally consists of 2 non-identical NOR chips on one die. Additionally
> partitions now can span over multiple chips.
>
> To describe such a chip's, multiple "reg" tuples are now supported in one
> flash device tree node. Here an dts example:
>
> flash@f0000000,0 {
> #address-cells = <1>;
> #size-cells = <1>;
> compatible = "cfi-flash";
> reg = <0 0x00000000 0x02000000
> 0 0x02000000 0x02000000>;
> bank-width = <2>;
> partition@0 {
> label = "test-part1";
> reg = <0 0x04000000>;
> };
> };
Binding looks good to me. Add a variant of this blurb to
Documentation/powerpc/booting-without-of.txt. For extra credit,
factor out the MTD stuff and move it to
Documentation/powerpc/dts-bindings/. Remember to cc: the
devicetree-discuss@ozlabs.org list when you post the binding
documentation.
> Signed-off-by: Stefan Roese <sr@denx.de>
> CC: Grant Likely <grant.likely@secretlab.ca>
> ---
> drivers/mtd/maps/physmap_of.c | 174 ++++++++++++++++++++++++++++-------------
> 1 files changed, 120 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
> index 5fcfec0..c1c2d08 100644
> --- a/drivers/mtd/maps/physmap_of.c
> +++ b/drivers/mtd/maps/physmap_of.c
> @@ -20,13 +20,17 @@
> #include <linux/mtd/mtd.h>
> #include <linux/mtd/map.h>
> #include <linux/mtd/partitions.h>
> +#include <linux/mtd/concat.h>
> #include <linux/of.h>
> #include <linux/of_platform.h>
>
> +#define MAX_RESOURCES 4
> +
Why is this static? Instead you could define:
struct of_flash_list {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
};
struct of_flash {
struct mtd_info *cmtd;
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *parts;
#endif
int list_size; /* number of elements in of_flash_list */
struct of_flash_list list[0];
};
Using a zero length array at the end of the structure allows you to do
this after counting the number of reg tuples:
f = kzalloc(sizeof(struct of_flash) + sizeof(struct of_flash_list)*num_chips);
That eliminates a needless hard limit to the number of flash chips.
> struct of_flash {
> - struct mtd_info *mtd;
> - struct map_info map;
> - struct resource *res;
> + struct mtd_info *mtd[MAX_RESOURCES];
> + struct mtd_info *cmtd;
> + struct map_info map[MAX_RESOURCES];
> + struct resource *res[MAX_RESOURCES];
> #ifdef CONFIG_MTD_PARTITIONS
> struct mtd_partition *parts;
> #endif
> @@ -88,28 +92,40 @@ static int parse_obsolete_partitions(struct of_device *dev,
> static int of_flash_remove(struct of_device *dev)
> {
> struct of_flash *info;
> + int i;
>
> info = dev_get_drvdata(&dev->dev);
> if (!info)
> return 0;
> dev_set_drvdata(&dev->dev, NULL);
>
> - if (info->mtd) {
> +#ifdef CONFIG_MTD_CONCAT
> + if (info->cmtd != info->mtd[0]) {
> + del_mtd_device(info->cmtd);
> + mtd_concat_destroy(info->cmtd);
> + }
> +#endif
> +
> + if (info->cmtd) {
> if (OF_FLASH_PARTS(info)) {
> - del_mtd_partitions(info->mtd);
> + del_mtd_partitions(info->cmtd);
> kfree(OF_FLASH_PARTS(info));
> } else {
> - del_mtd_device(info->mtd);
> + del_mtd_device(info->cmtd);
> }
> - map_destroy(info->mtd);
> }
>
> - if (info->map.virt)
> - iounmap(info->map.virt);
> + for (i = 0; i < MAX_RESOURCES; i++) {
> + if (info->mtd[i])
> + map_destroy(info->mtd[i]);
> +
> + if (info->map[i].virt)
> + iounmap(info->map[i].virt);
>
> - if (info->res) {
> - release_resource(info->res);
> - kfree(info->res);
> + if (info->res[i]) {
> + release_resource(info->res[i]);
> + kfree(info->res[i]);
> + }
> }
>
> return 0;
> @@ -164,15 +180,25 @@ static int __devinit of_flash_probe(struct of_device *dev,
> 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 IO address from device tree\n");
> + int i;
> + int count;
> + const u32 *p;
> + int devices_found = 0;
> +
> + /*
> + * Get number of "reg" tuples. Scan for MTD devices on area's
> + * described by each "reg" region. This makes it possible (including
> + * the concat support) to support the Intel P30 48F4400 chips which
> + * consists internally of 2 non-identical NOR chips on one die.
> + */
> + p = of_get_property(dp, "reg", &count);
> + if (count % 12 != 0) {
This doesn't work. You cannot know the size of each reg tuple until
#address-cells/#size-cells is parsed for the parent node. It won't
always be 12. Use of_n_addr_cells() + of_n_size_cells() to determine
size of each tuple.
Other than that, I think it looks good, but I'll look again when you repost.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] mtd: physmap_of: Add multiple regions and concatenation support
2009-04-03 14:04 ` Grant Likely
@ 2009-04-06 7:43 ` Stefan Roese
0 siblings, 0 replies; 3+ messages in thread
From: Stefan Roese @ 2009-04-06 7:43 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, devicetree-discuss, linux-mtd
On Friday 03 April 2009, Grant Likely wrote:
> > flash@f0000000,0 {
> > #address-cells = <1>;
> > #size-cells = <1>;
> > compatible = "cfi-flash";
> > reg = <0 0x00000000 0x02000000
> > 0 0x02000000 0x02000000>;
> > bank-width = <2>;
> > partition@0 {
> > label = "test-part1";
> > reg = <0 0x04000000>;
> > };
> > };
>
> Binding looks good to me. Add a variant of this blurb to
> Documentation/powerpc/booting-without-of.txt. For extra credit,
> factor out the MTD stuff and move it to
> Documentation/powerpc/dts-bindings/. Remember to cc: the
> devicetree-discuss@ozlabs.org list when you post the binding
> documentation.
OK, will do.
> > Signed-off-by: Stefan Roese <sr@denx.de>
> > CC: Grant Likely <grant.likely@secretlab.ca>
> > ---
> > drivers/mtd/maps/physmap_of.c | 174
> > ++++++++++++++++++++++++++++------------- 1 files changed, 120
> > insertions(+), 54 deletions(-)
> >
> > diff --git a/drivers/mtd/maps/physmap_of.c
> > b/drivers/mtd/maps/physmap_of.c index 5fcfec0..c1c2d08 100644
> > --- a/drivers/mtd/maps/physmap_of.c
> > +++ b/drivers/mtd/maps/physmap_of.c
> > @@ -20,13 +20,17 @@
> > #include <linux/mtd/mtd.h>
> > #include <linux/mtd/map.h>
> > #include <linux/mtd/partitions.h>
> > +#include <linux/mtd/concat.h>
> > #include <linux/of.h>
> > #include <linux/of_platform.h>
> >
> > +#define MAX_RESOURCES 4
> > +
>
> Why is this static?
Because I cloned it from physmap.c.
> Instead you could define:
>
> struct of_flash_list {
> struct mtd_info *mtd;
> struct map_info map;
> struct resource *res;
> };
>
> struct of_flash {
> struct mtd_info *cmtd;
> #ifdef CONFIG_MTD_PARTITIONS
> struct mtd_partition *parts;
> #endif
> int list_size; /* number of elements in of_flash_list */
> struct of_flash_list list[0];
> };
>
> Using a zero length array at the end of the structure allows you to do
> this after counting the number of reg tuples:
>
> f = kzalloc(sizeof(struct of_flash) + sizeof(struct
> of_flash_list)*num_chips);
>
> That eliminates a needless hard limit to the number of flash chips.
Good idea. Will update. Thanks.
> > struct of_flash {
> > - struct mtd_info *mtd;
> > - struct map_info map;
> > - struct resource *res;
> > + struct mtd_info *mtd[MAX_RESOURCES];
> > + struct mtd_info *cmtd;
> > + struct map_info map[MAX_RESOURCES];
> > + struct resource *res[MAX_RESOURCES];
> > #ifdef CONFIG_MTD_PARTITIONS
> > struct mtd_partition *parts;
> > #endif
> > @@ -88,28 +92,40 @@ static int parse_obsolete_partitions(struct of_device
> > *dev, static int of_flash_remove(struct of_device *dev)
> > {
> > struct of_flash *info;
> > + int i;
> >
> > info = dev_get_drvdata(&dev->dev);
> > if (!info)
> > return 0;
> > dev_set_drvdata(&dev->dev, NULL);
> >
> > - if (info->mtd) {
> > +#ifdef CONFIG_MTD_CONCAT
> > + if (info->cmtd != info->mtd[0]) {
> > + del_mtd_device(info->cmtd);
> > + mtd_concat_destroy(info->cmtd);
> > + }
> > +#endif
> > +
> > + if (info->cmtd) {
> > if (OF_FLASH_PARTS(info)) {
> > - del_mtd_partitions(info->mtd);
> > + del_mtd_partitions(info->cmtd);
> > kfree(OF_FLASH_PARTS(info));
> > } else {
> > - del_mtd_device(info->mtd);
> > + del_mtd_device(info->cmtd);
> > }
> > - map_destroy(info->mtd);
> > }
> >
> > - if (info->map.virt)
> > - iounmap(info->map.virt);
> > + for (i = 0; i < MAX_RESOURCES; i++) {
> > + if (info->mtd[i])
> > + map_destroy(info->mtd[i]);
> > +
> > + if (info->map[i].virt)
> > + iounmap(info->map[i].virt);
> >
> > - if (info->res) {
> > - release_resource(info->res);
> > - kfree(info->res);
> > + if (info->res[i]) {
> > + release_resource(info->res[i]);
> > + kfree(info->res[i]);
> > + }
> > }
> >
> > return 0;
> > @@ -164,15 +180,25 @@ static int __devinit of_flash_probe(struct
> > of_device *dev, 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 IO address from device
> > tree\n"); + int i;
> > + int count;
> > + const u32 *p;
> > + int devices_found = 0;
> > +
> > + /*
> > + * Get number of "reg" tuples. Scan for MTD devices on area's
> > + * described by each "reg" region. This makes it possible
> > (including + * the concat support) to support the Intel P30
> > 48F4400 chips which + * consists internally of 2 non-identical NOR
> > chips on one die. + */
> > + p = of_get_property(dp, "reg", &count);
> > + if (count % 12 != 0) {
>
> This doesn't work. You cannot know the size of each reg tuple until
> #address-cells/#size-cells is parsed for the parent node. It won't
> always be 12. Use of_n_addr_cells() + of_n_size_cells() to determine
> size of each tuple.
OK, I'll change it in the next patch version.
Thanks.
Best regards,
Stefan
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-04-06 7:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-03 9:55 [PATCH] mtd: physmap_of: Add multiple regions and concatenation support Stefan Roese
2009-04-03 14:04 ` Grant Likely
2009-04-06 7:43 ` Stefan Roese
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).