diff mbox

[1/3,v3] mtd: physmap_of: Add multiple regions and concatenation support

Message ID 1239883845-17804-1-git-send-email-sr@denx.de
State Accepted
Commit 143070e74630b9557e1bb64d899ff2cc5a1dcb48
Headers show

Commit Message

Stefan Roese April 16, 2009, 12:10 p.m. UTC
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>
Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
---
Changes in ver3:
- s/4/sizeof(u32)

Changes in ver2 (as suggested by Grant Likely):
- Removed MAX_RESOURCES introduced in ver1. Now we don't have a hard limit
  for "reg" tuples anymore.
- Used of_n_addr_cells() and of_n_size_cells() to determine size of each tuple.

 drivers/mtd/maps/physmap_of.c |  199 +++++++++++++++++++++++++++++------------
 1 files changed, 143 insertions(+), 56 deletions(-)

Comments

Grant Likely April 16, 2009, 1:26 p.m. UTC | #1
On Thu, Apr 16, 2009 at 6:10 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>;
>                };
>        };
>
> Signed-off-by: Stefan Roese <sr@denx.de>
> Reviewd-by: Grant Likely <grant.likely@secretlab.ca>

Yup, still looks good to me.  What boards has this been tested on?

g.

> ---
> Changes in ver3:
> - s/4/sizeof(u32)
>
> Changes in ver2 (as suggested by Grant Likely):
> - Removed MAX_RESOURCES introduced in ver1. Now we don't have a hard limit
>  for "reg" tuples anymore.
> - Used of_n_addr_cells() and of_n_size_cells() to determine size of each tuple.
>
>  drivers/mtd/maps/physmap_of.c |  199 +++++++++++++++++++++++++++++------------
>  1 files changed, 143 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
> index c83a60f..39d357b 100644
> --- a/drivers/mtd/maps/physmap_of.c
> +++ b/drivers/mtd/maps/physmap_of.c
> @@ -20,16 +20,23 @@
>  #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>
>
> +struct of_flash_list {
> +       struct mtd_info *mtd;
> +       struct map_info map;
> +       struct resource *res;
> +};
> +
>  struct of_flash {
> -       struct mtd_info         *mtd;
> -       struct map_info         map;
> -       struct resource         *res;
> +       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];
>  };
>
>  #ifdef CONFIG_MTD_PARTITIONS
> @@ -88,30 +95,44 @@ 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->list[0].mtd) {
> +               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 < info->list_size; i++) {
> +               if (info->list[i].mtd)
> +                       map_destroy(info->list[i].mtd);
>
> -       if (info->res) {
> -               release_resource(info->res);
> -               kfree(info->res);
> +               if (info->list[i].map.virt)
> +                       iounmap(info->list[i].map.virt);
> +
> +               if (info->list[i].res) {
> +                       release_resource(info->list[i].res);
> +                       kfree(info->list[i].res);
> +               }
>        }
>
> +       kfree(info);
> +
>        return 0;
>  }
>
> @@ -164,68 +185,130 @@ 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 reg_tuple_size;
> +       struct mtd_info **mtd_list = NULL;
> +
> +       reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
> +
> +       /*
> +        * 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 % reg_tuple_size != 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 /= reg_tuple_size;
>
>        err = -ENOMEM;
> -       info = kzalloc(sizeof(*info), GFP_KERNEL);
> +       info = kzalloc(sizeof(struct of_flash) +
> +                      sizeof(struct of_flash_list) * count, GFP_KERNEL);
> +       if (!info)
> +               goto err_out;
> +
> +       mtd_list = kzalloc(sizeof(struct mtd_info) * count, GFP_KERNEL);
>        if (!info)
>                goto err_out;
>
>        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->list[i].res = request_mem_region(res.start, res.end -
> +                                                      res.start + 1,
> +                                                      dev_name(&dev->dev));
> +               if (!info->list[i].res)
> +                       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->list[i].map.name = dev_name(&dev->dev);
> +               info->list[i].map.phys = res.start;
> +               info->list[i].map.size = res.end - res.start + 1;
> +               info->list[i].map.bankwidth = *width;
> +
> +               err = -ENOMEM;
> +               info->list[i].map.virt = ioremap(info->list[i].map.phys,
> +                                                info->list[i].map.size);
> +               if (!info->list[i].map.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->list[i].map);
>
> -       simple_map_init(&info->map);
> +               if (probe_type) {
> +                       info->list[i].mtd = do_map_probe(probe_type,
> +                                                        &info->list[i].map);
> +               } else {
> +                       info->list[i].mtd = obsolete_probe(dev,
> +                                                          &info->list[i].map);
> +               }
> +               mtd_list[i] = info->list[i].mtd;
>
> -       if (probe_type)
> -               info->mtd = do_map_probe(probe_type, &info->map);
> -       else
> -               info->mtd = obsolete_probe(dev, &info->map);
> +               err = -ENXIO;
> +               if (!info->list[i].mtd) {
> +                       dev_err(&dev->dev, "do_map_probe() failed\n");
> +                       goto err_out;
> +               } else {
> +                       info->list_size++;
> +               }
> +               info->list[i].mtd->owner = THIS_MODULE;
> +               info->list[i].mtd->dev.parent = &dev->dev;
> +       }
>
> -       err = -ENXIO;
> -       if (!info->mtd) {
> -               dev_err(&dev->dev, "do_map_probe() failed\n");
> -               goto err_out;
> +       err = 0;
> +       if (info->list_size == 1) {
> +               info->cmtd = info->list[0].mtd;
> +       } else if (info->list_size > 1) {
> +               /*
> +                * We detected multiple devices. Concatenate them together.
> +                */
> +#ifdef CONFIG_MTD_CONCAT
> +               info->cmtd = mtd_concat_create(mtd_list, info->list_size,
> +                                              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;
> -       info->mtd->dev.parent = &dev->dev;
> +       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;
>
> @@ -244,15 +327,19 @@ 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);
> +
> +       kfree(mtd_list);
>
>        return 0;
>
>  err_out:
> +       kfree(mtd_list);
>        of_flash_remove(dev);
> +
>        return err;
>  }
>
> --
> 1.6.2.3
>
>
Stefan Roese April 16, 2009, 1:37 p.m. UTC | #2
On Thursday 16 April 2009, Grant Likely wrote:
> > Signed-off-by: Stefan Roese <sr@denx.de>
> > Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
>
> Yup, still looks good to me.  What boards has this been tested on?

I tested this version on PPC405EX Kilauea equipped only one "standard" 
Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360 
board (kmeter1) which is equipped with the Intel P30 part mentioned in the 
bindings description. Slightly modified since this board support is not yet 
pushed upstream and currently using v2.6.28 (physmap_of.c has received minor 
modifications after 2.6.28 release).

Thanks.

Best regards,
Stefan
Grant Likely April 16, 2009, 1:46 p.m. UTC | #3
On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
> On Thursday 16 April 2009, Grant Likely wrote:
>> > Signed-off-by: Stefan Roese <sr@denx.de>
>> > Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
>>
>> Yup, still looks good to me.  What boards has this been tested on?
>
> I tested this version on PPC405EX Kilauea equipped only one "standard"
> Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
> board (kmeter1) which is equipped with the Intel P30 part mentioned in the
> bindings description. Slightly modified since this board support is not yet
> pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
> modifications after 2.6.28 release).

Okay.  It will be good to get this one into -next for some testing
exposure.  Unless he asks me to do otherwise, I'll leave this one to
David to pick up.

g.
Stefan Roese April 16, 2009, 1:49 p.m. UTC | #4
On Thursday 16 April 2009, Grant Likely wrote:
> >> Yup, still looks good to me.  What boards has this been tested on?
> >
> > I tested this version on PPC405EX Kilauea equipped only one "standard"
> > Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
> > board (kmeter1) which is equipped with the Intel P30 part mentioned in
> > the bindings description. Slightly modified since this board support is
> > not yet pushed upstream and currently using v2.6.28 (physmap_of.c has
> > received minor modifications after 2.6.28 release).
>
> Okay.  It will be good to get this one into -next for some testing
> exposure.  Unless he asks me to do otherwise, I'll leave this one to
> David to pick up.

Understood. Thanks Grant.

Best regards,
Stefan
Artem Bityutskiy April 16, 2009, 1:51 p.m. UTC | #5
On Thu, 2009-04-16 at 07:46 -0600, Grant Likely wrote:
> On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
> > On Thursday 16 April 2009, Grant Likely wrote:
> >> > Signed-off-by: Stefan Roese <sr@denx.de>
> >> > Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
> >>
> >> Yup, still looks good to me.  What boards has this been tested on?
> >
> > I tested this version on PPC405EX Kilauea equipped only one "standard"
> > Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
> > board (kmeter1) which is equipped with the Intel P30 part mentioned in the
> > bindings description. Slightly modified since this board support is not yet
> > pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
> > modifications after 2.6.28 release).
> 
> Okay.  It will be good to get this one into -next for some testing
> exposure.  Unless he asks me to do otherwise, I'll leave this one to
> David to pick up.

David usually picks up stuff just before or during merge window,
so if you want linux-next exposure, you need to have some extra
care.
Grant Likely April 16, 2009, 2:05 p.m. UTC | #6
On Thu, Apr 16, 2009 at 7:51 AM, Artem Bityutskiy
<dedekind@infradead.org> wrote:
> On Thu, 2009-04-16 at 07:46 -0600, Grant Likely wrote:
>> On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
>> > On Thursday 16 April 2009, Grant Likely wrote:
>> >> > Signed-off-by: Stefan Roese <sr@denx.de>
>> >> > Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
>> >>
>> >> Yup, still looks good to me.  What boards has this been tested on?
>> >
>> > I tested this version on PPC405EX Kilauea equipped only one "standard"
>> > Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
>> > board (kmeter1) which is equipped with the Intel P30 part mentioned in the
>> > bindings description. Slightly modified since this board support is not yet
>> > pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
>> > modifications after 2.6.28 release).
>>
>> Okay.  It will be good to get this one into -next for some testing
>> exposure.  Unless he asks me to do otherwise, I'll leave this one to
>> David to pick up.
>
> David usually picks up stuff just before or during merge window,
> so if you want linux-next exposure, you need to have some extra
> care.

Okay, thanks.

David, I'd like to get this into a -next tree.  Are you okay with it
going in via the powerpc tree?

g.
David Woodhouse April 16, 2009, 6:38 p.m. UTC | #7
On Thu, 16 Apr 2009, Artem Bityutskiy wrote:

> On Thu, 2009-04-16 at 07:46 -0600, Grant Likely wrote:
>> On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
>>> On Thursday 16 April 2009, Grant Likely wrote:
>>>>> Signed-off-by: Stefan Roese <sr@denx.de>
>>>>> Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
>>>>
>>>> Yup, still looks good to me.  What boards has this been tested on?
>>>
>>> I tested this version on PPC405EX Kilauea equipped only one "standard"
>>> Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
>>> board (kmeter1) which is equipped with the Intel P30 part mentioned in the
>>> bindings description. Slightly modified since this board support is not yet
>>> pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
>>> modifications after 2.6.28 release).
>>
>> Okay.  It will be good to get this one into -next for some testing
>> exposure.  Unless he asks me to do otherwise, I'll leave this one to
>> David to pick up.
>
> David usually picks up stuff just before or during merge window,
> so if you want linux-next exposure, you need to have some extra
> care.

I don't necessarily do that on purpose; it just works out that way when 
I'm busy.
Artem Bityutskiy April 17, 2009, 8:26 a.m. UTC | #8
On Thu, 2009-04-16 at 19:38 +0100, David Woodhouse wrote:
> On Thu, 16 Apr 2009, Artem Bityutskiy wrote:
> 
> > On Thu, 2009-04-16 at 07:46 -0600, Grant Likely wrote:
> >> On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
> >>> On Thursday 16 April 2009, Grant Likely wrote:
> >>>>> Signed-off-by: Stefan Roese <sr@denx.de>
> >>>>> Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
> >>>>
> >>>> Yup, still looks good to me.  What boards has this been tested on?
> >>>
> >>> I tested this version on PPC405EX Kilauea equipped only one "standard"
> >>> Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
> >>> board (kmeter1) which is equipped with the Intel P30 part mentioned in the
> >>> bindings description. Slightly modified since this board support is not yet
> >>> pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
> >>> modifications after 2.6.28 release).
> >>
> >> Okay.  It will be good to get this one into -next for some testing
> >> exposure.  Unless he asks me to do otherwise, I'll leave this one to
> >> David to pick up.
> >
> > David usually picks up stuff just before or during merge window,
> > so if you want linux-next exposure, you need to have some extra
> > care.
> 
> I don't necessarily do that on purpose; it just works out that way when 
> I'm busy.

Yeah, not that I try to blame you, but I think we need to expose stuff
to linux-next. And people who send patches are frustrated when their
stuff gets no attention for very long time.

I understand that MTD tree maintenance is a burden, and you are very
busy, and no one pays you for this job. Thanks for doing it!

I'm going to try to help you. I've just created a git tree where
I'll push patches I consider OK and I approve. Here it is:
git://git.infradead.org/users/dedekind/l2-mtd-2.6.git

My hope is that you would look at that tree from time to time
and pull it. At least you may be sure I looked at the patches and
did some validation. This should save your time and help MTD
users.

Thanks.
Josh Boyer April 17, 2009, 12:45 p.m. UTC | #9
On Thu, Apr 16, 2009 at 2:38 PM, David Woodhouse <dwmw2@infradead.org> wrote:
> On Thu, 16 Apr 2009, Artem Bityutskiy wrote:
>
>> On Thu, 2009-04-16 at 07:46 -0600, Grant Likely wrote:
>>> Okay.  It will be good to get this one into -next for some testing
>>> exposure.  Unless he asks me to do otherwise, I'll leave this one to
>>> David to pick up.
>>
>> David usually picks up stuff just before or during merge window,
>> so if you want linux-next exposure, you need to have some extra
>> care.
>
> I don't necessarily do that on purpose; it just works out that way when I'm
> busy.

Are you ever _not_ busy? ;)

josh
Stefan Roese June 6, 2009, 3:59 a.m. UTC | #10
On Thursday 16 April 2009 15:49:44 Stefan Roese wrote:
> > Okay.  It will be good to get this one into -next for some testing
> > exposure.  Unless he asks me to do otherwise, I'll leave this one to
> > David to pick up.
>
> Understood. Thanks Grant.

David, just checking on the status of this patch. Is it in your queue for the 
next merge window?

Thanks,
Stefan
David Woodhouse June 6, 2009, 7:25 a.m. UTC | #11
On Fri, 2009-04-17 at 11:26 +0300, Artem Bityutskiy wrote:
> 
> I'm going to try to help you. I've just created a git tree where
> I'll push patches I consider OK and I approve. Here it is:
> git://git.infradead.org/users/dedekind/l2-mtd-2.6.git
> 
> My hope is that you would look at that tree from time to time
> and pull it. At least you may be sure I looked at the patches and
> did some validation. This should save your time and help MTD
> users.

This was _really_ useful. Thank you very much.
Grant Likely June 17, 2009, 5:53 a.m. UTC | #12
On Thu, Apr 16, 2009 at 7:46 AM, Grant Likely<grant.likely@secretlab.ca> wrote:
> On Thu, Apr 16, 2009 at 7:37 AM, Stefan Roese <sr@denx.de> wrote:
>> On Thursday 16 April 2009, Grant Likely wrote:
>>> > Signed-off-by: Stefan Roese <sr@denx.de>
>>> > Reviewd-by: Grant Likely <grant.likely@secretlab.ca>
>>>
>>> Yup, still looks good to me.  What boards has this been tested on?
>>
>> I tested this version on PPC405EX Kilauea equipped only one "standard"
>> Spansion S29GL512 NOR chip. And a slightly modified version on an MPC8360
>> board (kmeter1) which is equipped with the Intel P30 part mentioned in the
>> bindings description. Slightly modified since this board support is not yet
>> pushed upstream and currently using v2.6.28 (physmap_of.c has received minor
>> modifications after 2.6.28 release).
>
> Okay.  It will be good to get this one into -next for some testing
> exposure.  Unless he asks me to do otherwise, I'll leave this one to
> David to pick up.

David, what's the status of this patch?  Will it be merged for 2.6.31?

g.
Stefan Roese June 23, 2009, 6:36 a.m. UTC | #13
On Wednesday 17 June 2009 07:53:51 Grant Likely wrote:
> David, what's the status of this patch?  Will it be merged for 2.6.31?

It's merged now.

Thanks,
Stefan
diff mbox

Patch

diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index c83a60f..39d357b 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -20,16 +20,23 @@ 
 #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>
 
+struct of_flash_list {
+	struct mtd_info *mtd;
+	struct map_info map;
+	struct resource *res;
+};
+
 struct of_flash {
-	struct mtd_info		*mtd;
-	struct map_info		map;
-	struct resource		*res;
+	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];
 };
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -88,30 +95,44 @@  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->list[0].mtd) {
+		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 < info->list_size; i++) {
+		if (info->list[i].mtd)
+			map_destroy(info->list[i].mtd);
 
-	if (info->res) {
-		release_resource(info->res);
-		kfree(info->res);
+		if (info->list[i].map.virt)
+			iounmap(info->list[i].map.virt);
+
+		if (info->list[i].res) {
+			release_resource(info->list[i].res);
+			kfree(info->list[i].res);
+		}
 	}
 
+	kfree(info);
+
 	return 0;
 }
 
@@ -164,68 +185,130 @@  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 reg_tuple_size;
+	struct mtd_info **mtd_list = NULL;
+
+	reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
+
+	/*
+	 * 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 % reg_tuple_size != 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 /= reg_tuple_size;
 
 	err = -ENOMEM;
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = kzalloc(sizeof(struct of_flash) +
+		       sizeof(struct of_flash_list) * count, GFP_KERNEL);
+	if (!info)
+		goto err_out;
+
+	mtd_list = kzalloc(sizeof(struct mtd_info) * count, GFP_KERNEL);
 	if (!info)
 		goto err_out;
 
 	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->list[i].res = request_mem_region(res.start, res.end -
+						       res.start + 1,
+						       dev_name(&dev->dev));
+		if (!info->list[i].res)
+			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->list[i].map.name = dev_name(&dev->dev);
+		info->list[i].map.phys = res.start;
+		info->list[i].map.size = res.end - res.start + 1;
+		info->list[i].map.bankwidth = *width;
+
+		err = -ENOMEM;
+		info->list[i].map.virt = ioremap(info->list[i].map.phys,
+						 info->list[i].map.size);
+		if (!info->list[i].map.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->list[i].map);
 
-	simple_map_init(&info->map);
+		if (probe_type) {
+			info->list[i].mtd = do_map_probe(probe_type,
+							 &info->list[i].map);
+		} else {
+			info->list[i].mtd = obsolete_probe(dev,
+							   &info->list[i].map);
+		}
+		mtd_list[i] = info->list[i].mtd;
 
-	if (probe_type)
-		info->mtd = do_map_probe(probe_type, &info->map);
-	else
-		info->mtd = obsolete_probe(dev, &info->map);
+		err = -ENXIO;
+		if (!info->list[i].mtd) {
+			dev_err(&dev->dev, "do_map_probe() failed\n");
+			goto err_out;
+		} else {
+			info->list_size++;
+		}
+		info->list[i].mtd->owner = THIS_MODULE;
+		info->list[i].mtd->dev.parent = &dev->dev;
+	}
 
-	err = -ENXIO;
-	if (!info->mtd) {
-		dev_err(&dev->dev, "do_map_probe() failed\n");
-		goto err_out;
+	err = 0;
+	if (info->list_size == 1) {
+		info->cmtd = info->list[0].mtd;
+	} else if (info->list_size > 1) {
+		/*
+		 * We detected multiple devices. Concatenate them together.
+		 */
+#ifdef CONFIG_MTD_CONCAT
+		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
+					       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;
-	info->mtd->dev.parent = &dev->dev;
+	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;
 
@@ -244,15 +327,19 @@  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);
+
+	kfree(mtd_list);
 
 	return 0;
 
 err_out:
+	kfree(mtd_list);
 	of_flash_remove(dev);
+
 	return err;
 }