linux/drivers/mtd/maps/physmap_of.c
<<
>>
Prefs
   1/*
   2 * Flash mappings described by the OF (or flattened) device tree
   3 *
   4 * Copyright (C) 2006 MontaVista Software Inc.
   5 * Author: Vitaly Wool <vwool@ru.mvista.com>
   6 *
   7 * Revised to handle newer style flash binding by:
   8 *   Copyright (C) 2007 David Gibson, IBM Corporation.
   9 *
  10 * This program is free software; you can redistribute  it and/or modify it
  11 * under  the terms of  the GNU General  Public License as published by the
  12 * Free Software Foundation;  either version 2 of the  License, or (at your
  13 * option) any later version.
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/types.h>
  18#include <linux/init.h>
  19#include <linux/device.h>
  20#include <linux/mtd/mtd.h>
  21#include <linux/mtd/map.h>
  22#include <linux/mtd/partitions.h>
  23#include <linux/mtd/concat.h>
  24#include <linux/of.h>
  25#include <linux/of_address.h>
  26#include <linux/of_platform.h>
  27#include <linux/slab.h>
  28
  29struct of_flash_list {
  30        struct mtd_info *mtd;
  31        struct map_info map;
  32        struct resource *res;
  33};
  34
  35struct of_flash {
  36        struct mtd_info         *cmtd;
  37#ifdef CONFIG_MTD_PARTITIONS
  38        struct mtd_partition    *parts;
  39#endif
  40        int list_size; /* number of elements in of_flash_list */
  41        struct of_flash_list    list[0];
  42};
  43
  44#ifdef CONFIG_MTD_PARTITIONS
  45#define OF_FLASH_PARTS(info)    ((info)->parts)
  46
  47static int parse_obsolete_partitions(struct platform_device *dev,
  48                                     struct of_flash *info,
  49                                     struct device_node *dp)
  50{
  51        int i, plen, nr_parts;
  52        const struct {
  53                __be32 offset, len;
  54        } *part;
  55        const char *names;
  56
  57        part = of_get_property(dp, "partitions", &plen);
  58        if (!part)
  59                return 0; /* No partitions found */
  60
  61        dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
  62
  63        nr_parts = plen / sizeof(part[0]);
  64
  65        info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
  66        if (!info->parts)
  67                return -ENOMEM;
  68
  69        names = of_get_property(dp, "partition-names", &plen);
  70
  71        for (i = 0; i < nr_parts; i++) {
  72                info->parts[i].offset = be32_to_cpu(part->offset);
  73                info->parts[i].size   = be32_to_cpu(part->len) & ~1;
  74                if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */
  75                        info->parts[i].mask_flags = MTD_WRITEABLE;
  76
  77                if (names && (plen > 0)) {
  78                        int len = strlen(names) + 1;
  79
  80                        info->parts[i].name = (char *)names;
  81                        plen -= len;
  82                        names += len;
  83                } else {
  84                        info->parts[i].name = "unnamed";
  85                }
  86
  87                part++;
  88        }
  89
  90        return nr_parts;
  91}
  92#else /* MTD_PARTITIONS */
  93#define OF_FLASH_PARTS(info)            (0)
  94#define parse_partitions(info, dev)     (0)
  95#endif /* MTD_PARTITIONS */
  96
  97static int of_flash_remove(struct platform_device *dev)
  98{
  99        struct of_flash *info;
 100        int i;
 101
 102        info = dev_get_drvdata(&dev->dev);
 103        if (!info)
 104                return 0;
 105        dev_set_drvdata(&dev->dev, NULL);
 106
 107#ifdef CONFIG_MTD_CONCAT
 108        if (info->cmtd != info->list[0].mtd) {
 109                del_mtd_device(info->cmtd);
 110                mtd_concat_destroy(info->cmtd);
 111        }
 112#endif
 113
 114        if (info->cmtd) {
 115                if (OF_FLASH_PARTS(info)) {
 116                        del_mtd_partitions(info->cmtd);
 117                        kfree(OF_FLASH_PARTS(info));
 118                } else {
 119                        del_mtd_device(info->cmtd);
 120                }
 121        }
 122
 123        for (i = 0; i < info->list_size; i++) {
 124                if (info->list[i].mtd)
 125                        map_destroy(info->list[i].mtd);
 126
 127                if (info->list[i].map.virt)
 128                        iounmap(info->list[i].map.virt);
 129
 130                if (info->list[i].res) {
 131                        release_resource(info->list[i].res);
 132                        kfree(info->list[i].res);
 133                }
 134        }
 135
 136        kfree(info);
 137
 138        return 0;
 139}
 140
 141/* Helper function to handle probing of the obsolete "direct-mapped"
 142 * compatible binding, which has an extra "probe-type" property
 143 * describing the type of flash probe necessary. */
 144static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
 145                                                  struct map_info *map)
 146{
 147        struct device_node *dp = dev->dev.of_node;
 148        const char *of_probe;
 149        struct mtd_info *mtd;
 150        static const char *rom_probe_types[]
 151                = { "cfi_probe", "jedec_probe", "map_rom"};
 152        int i;
 153
 154        dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
 155                 "flash binding\n");
 156
 157        of_probe = of_get_property(dp, "probe-type", NULL);
 158        if (!of_probe) {
 159                for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
 160                        mtd = do_map_probe(rom_probe_types[i], map);
 161                        if (mtd)
 162                                return mtd;
 163                }
 164                return NULL;
 165        } else if (strcmp(of_probe, "CFI") == 0) {
 166                return do_map_probe("cfi_probe", map);
 167        } else if (strcmp(of_probe, "JEDEC") == 0) {
 168                return do_map_probe("jedec_probe", map);
 169        } else {
 170                if (strcmp(of_probe, "ROM") != 0)
 171                        dev_warn(&dev->dev, "obsolete_probe: don't know probe "
 172                                 "type '%s', mapping as rom\n", of_probe);
 173                return do_map_probe("mtd_rom", map);
 174        }
 175}
 176
 177#ifdef CONFIG_MTD_PARTITIONS
 178/* When partitions are set we look for a linux,part-probe property which
 179   specifies the list of partition probers to use. If none is given then the
 180   default is use. These take precedence over other device tree
 181   information. */
 182static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
 183static const char ** __devinit of_get_probes(struct device_node *dp)
 184{
 185        const char *cp;
 186        int cplen;
 187        unsigned int l;
 188        unsigned int count;
 189        const char **res;
 190
 191        cp = of_get_property(dp, "linux,part-probe", &cplen);
 192        if (cp == NULL)
 193                return part_probe_types_def;
 194
 195        count = 0;
 196        for (l = 0; l != cplen; l++)
 197                if (cp[l] == 0)
 198                        count++;
 199
 200        res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
 201        count = 0;
 202        while (cplen > 0) {
 203                res[count] = cp;
 204                l = strlen(cp) + 1;
 205                cp += l;
 206                cplen -= l;
 207                count++;
 208        }
 209        return res;
 210}
 211
 212static void __devinit of_free_probes(const char **probes)
 213{
 214        if (probes != part_probe_types_def)
 215                kfree(probes);
 216}
 217#endif
 218
 219static int __devinit of_flash_probe(struct platform_device *dev,
 220                                    const struct of_device_id *match)
 221{
 222#ifdef CONFIG_MTD_PARTITIONS
 223        const char **part_probe_types;
 224#endif
 225        struct device_node *dp = dev->dev.of_node;
 226        struct resource res;
 227        struct of_flash *info;
 228        const char *probe_type = match->data;
 229        const __be32 *width;
 230        int err;
 231        int i;
 232        int count;
 233        const __be32 *p;
 234        int reg_tuple_size;
 235        struct mtd_info **mtd_list = NULL;
 236        resource_size_t res_size;
 237
 238        reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
 239
 240        /*
 241         * Get number of "reg" tuples. Scan for MTD devices on area's
 242         * described by each "reg" region. This makes it possible (including
 243         * the concat support) to support the Intel P30 48F4400 chips which
 244         * consists internally of 2 non-identical NOR chips on one die.
 245         */
 246        p = of_get_property(dp, "reg", &count);
 247        if (count % reg_tuple_size != 0) {
 248                dev_err(&dev->dev, "Malformed reg property on %s\n",
 249                                dev->dev.of_node->full_name);
 250                err = -EINVAL;
 251                goto err_flash_remove;
 252        }
 253        count /= reg_tuple_size;
 254
 255        err = -ENOMEM;
 256        info = kzalloc(sizeof(struct of_flash) +
 257                       sizeof(struct of_flash_list) * count, GFP_KERNEL);
 258        if (!info)
 259                goto err_flash_remove;
 260
 261        dev_set_drvdata(&dev->dev, info);
 262
 263        mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
 264        if (!mtd_list)
 265                goto err_flash_remove;
 266
 267        for (i = 0; i < count; i++) {
 268                err = -ENXIO;
 269                if (of_address_to_resource(dp, i, &res)) {
 270                        /*
 271                         * Continue with next register tuple if this
 272                         * one is not mappable
 273                         */
 274                        continue;
 275                }
 276
 277                dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
 278
 279                err = -EBUSY;
 280                res_size = resource_size(&res);
 281                info->list[i].res = request_mem_region(res.start, res_size,
 282                                                       dev_name(&dev->dev));
 283                if (!info->list[i].res)
 284                        goto err_out;
 285
 286                err = -ENXIO;
 287                width = of_get_property(dp, "bank-width", NULL);
 288                if (!width) {
 289                        dev_err(&dev->dev, "Can't get bank width from device"
 290                                " tree\n");
 291                        goto err_out;
 292                }
 293
 294                info->list[i].map.name = dev_name(&dev->dev);
 295                info->list[i].map.phys = res.start;
 296                info->list[i].map.size = res_size;
 297                info->list[i].map.bankwidth = be32_to_cpup(width);
 298
 299                err = -ENOMEM;
 300                info->list[i].map.virt = ioremap(info->list[i].map.phys,
 301                                                 info->list[i].map.size);
 302                if (!info->list[i].map.virt) {
 303                        dev_err(&dev->dev, "Failed to ioremap() flash"
 304                                " region\n");
 305                        goto err_out;
 306                }
 307
 308                simple_map_init(&info->list[i].map);
 309
 310                if (probe_type) {
 311                        info->list[i].mtd = do_map_probe(probe_type,
 312                                                         &info->list[i].map);
 313                } else {
 314                        info->list[i].mtd = obsolete_probe(dev,
 315                                                           &info->list[i].map);
 316                }
 317                mtd_list[i] = info->list[i].mtd;
 318
 319                err = -ENXIO;
 320                if (!info->list[i].mtd) {
 321                        dev_err(&dev->dev, "do_map_probe() failed\n");
 322                        goto err_out;
 323                } else {
 324                        info->list_size++;
 325                }
 326                info->list[i].mtd->owner = THIS_MODULE;
 327                info->list[i].mtd->dev.parent = &dev->dev;
 328        }
 329
 330        err = 0;
 331        if (info->list_size == 1) {
 332                info->cmtd = info->list[0].mtd;
 333        } else if (info->list_size > 1) {
 334                /*
 335                 * We detected multiple devices. Concatenate them together.
 336                 */
 337#ifdef CONFIG_MTD_CONCAT
 338                info->cmtd = mtd_concat_create(mtd_list, info->list_size,
 339                                               dev_name(&dev->dev));
 340                if (info->cmtd == NULL)
 341                        err = -ENXIO;
 342#else
 343                printk(KERN_ERR "physmap_of: multiple devices "
 344                       "found but MTD concat support disabled.\n");
 345                err = -ENXIO;
 346#endif
 347        }
 348        if (err)
 349                goto err_out;
 350
 351#ifdef CONFIG_MTD_PARTITIONS
 352        part_probe_types = of_get_probes(dp);
 353        err = parse_mtd_partitions(info->cmtd, part_probe_types,
 354                                   &info->parts, 0);
 355        if (err < 0) {
 356                of_free_probes(part_probe_types);
 357                goto err_out;
 358        }
 359        of_free_probes(part_probe_types);
 360
 361#ifdef CONFIG_MTD_OF_PARTS
 362        if (err == 0) {
 363                err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
 364                if (err < 0)
 365                        goto err_out;
 366        }
 367#endif
 368
 369        if (err == 0) {
 370                err = parse_obsolete_partitions(dev, info, dp);
 371                if (err < 0)
 372                        goto err_out;
 373        }
 374
 375        if (err > 0)
 376                add_mtd_partitions(info->cmtd, info->parts, err);
 377        else
 378#endif
 379                add_mtd_device(info->cmtd);
 380
 381        kfree(mtd_list);
 382
 383        return 0;
 384
 385err_out:
 386        kfree(mtd_list);
 387err_flash_remove:
 388        of_flash_remove(dev);
 389
 390        return err;
 391}
 392
 393static struct of_device_id of_flash_match[] = {
 394        {
 395                .compatible     = "cfi-flash",
 396                .data           = (void *)"cfi_probe",
 397        },
 398        {
 399                /* FIXME: JEDEC chips can't be safely and reliably
 400                 * probed, although the mtd code gets it right in
 401                 * practice most of the time.  We should use the
 402                 * vendor and device ids specified by the binding to
 403                 * bypass the heuristic probe code, but the mtd layer
 404                 * provides, at present, no interface for doing so
 405                 * :(. */
 406                .compatible     = "jedec-flash",
 407                .data           = (void *)"jedec_probe",
 408        },
 409        {
 410                .compatible     = "mtd-ram",
 411                .data           = (void *)"map_ram",
 412        },
 413        {
 414                .type           = "rom",
 415                .compatible     = "direct-mapped"
 416        },
 417        { },
 418};
 419MODULE_DEVICE_TABLE(of, of_flash_match);
 420
 421static struct of_platform_driver of_flash_driver = {
 422        .driver = {
 423                .name = "of-flash",
 424                .owner = THIS_MODULE,
 425                .of_match_table = of_flash_match,
 426        },
 427        .probe          = of_flash_probe,
 428        .remove         = of_flash_remove,
 429};
 430
 431static int __init of_flash_init(void)
 432{
 433        return of_register_platform_driver(&of_flash_driver);
 434}
 435
 436static void __exit of_flash_exit(void)
 437{
 438        of_unregister_platform_driver(&of_flash_driver);
 439}
 440
 441module_init(of_flash_init);
 442module_exit(of_flash_exit);
 443
 444MODULE_LICENSE("GPL");
 445MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
 446MODULE_DESCRIPTION("Device tree based MTD map driver");
 447