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        int list_size; /* number of elements in of_flash_list */
  38        struct of_flash_list    list[0];
  39};
  40
  41static int of_flash_remove(struct platform_device *dev)
  42{
  43        struct of_flash *info;
  44        int i;
  45
  46        info = dev_get_drvdata(&dev->dev);
  47        if (!info)
  48                return 0;
  49        dev_set_drvdata(&dev->dev, NULL);
  50
  51        if (info->cmtd != info->list[0].mtd) {
  52                mtd_device_unregister(info->cmtd);
  53                mtd_concat_destroy(info->cmtd);
  54        }
  55
  56        if (info->cmtd)
  57                mtd_device_unregister(info->cmtd);
  58
  59        for (i = 0; i < info->list_size; i++) {
  60                if (info->list[i].mtd)
  61                        map_destroy(info->list[i].mtd);
  62
  63                if (info->list[i].map.virt)
  64                        iounmap(info->list[i].map.virt);
  65
  66                if (info->list[i].res) {
  67                        release_resource(info->list[i].res);
  68                        kfree(info->list[i].res);
  69                }
  70        }
  71
  72        kfree(info);
  73
  74        return 0;
  75}
  76
  77/* Helper function to handle probing of the obsolete "direct-mapped"
  78 * compatible binding, which has an extra "probe-type" property
  79 * describing the type of flash probe necessary. */
  80static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
  81                                                  struct map_info *map)
  82{
  83        struct device_node *dp = dev->dev.of_node;
  84        const char *of_probe;
  85        struct mtd_info *mtd;
  86        static const char *rom_probe_types[]
  87                = { "cfi_probe", "jedec_probe", "map_rom"};
  88        int i;
  89
  90        dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
  91                 "flash binding\n");
  92
  93        of_probe = of_get_property(dp, "probe-type", NULL);
  94        if (!of_probe) {
  95                for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
  96                        mtd = do_map_probe(rom_probe_types[i], map);
  97                        if (mtd)
  98                                return mtd;
  99                }
 100                return NULL;
 101        } else if (strcmp(of_probe, "CFI") == 0) {
 102                return do_map_probe("cfi_probe", map);
 103        } else if (strcmp(of_probe, "JEDEC") == 0) {
 104                return do_map_probe("jedec_probe", map);
 105        } else {
 106                if (strcmp(of_probe, "ROM") != 0)
 107                        dev_warn(&dev->dev, "obsolete_probe: don't know probe "
 108                                 "type '%s', mapping as rom\n", of_probe);
 109                return do_map_probe("mtd_rom", map);
 110        }
 111}
 112
 113/* When partitions are set we look for a linux,part-probe property which
 114   specifies the list of partition probers to use. If none is given then the
 115   default is use. These take precedence over other device tree
 116   information. */
 117static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
 118                                        "ofpart", "ofoldpart", NULL };
 119static const char ** __devinit of_get_probes(struct device_node *dp)
 120{
 121        const char *cp;
 122        int cplen;
 123        unsigned int l;
 124        unsigned int count;
 125        const char **res;
 126
 127        cp = of_get_property(dp, "linux,part-probe", &cplen);
 128        if (cp == NULL)
 129                return part_probe_types_def;
 130
 131        count = 0;
 132        for (l = 0; l != cplen; l++)
 133                if (cp[l] == 0)
 134                        count++;
 135
 136        res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
 137        count = 0;
 138        while (cplen > 0) {
 139                res[count] = cp;
 140                l = strlen(cp) + 1;
 141                cp += l;
 142                cplen -= l;
 143                count++;
 144        }
 145        return res;
 146}
 147
 148static void __devinit of_free_probes(const char **probes)
 149{
 150        if (probes != part_probe_types_def)
 151                kfree(probes);
 152}
 153
 154static struct of_device_id of_flash_match[];
 155static int __devinit of_flash_probe(struct platform_device *dev)
 156{
 157        const char **part_probe_types;
 158        const struct of_device_id *match;
 159        struct device_node *dp = dev->dev.of_node;
 160        struct resource res;
 161        struct of_flash *info;
 162        const char *probe_type;
 163        const __be32 *width;
 164        int err;
 165        int i;
 166        int count;
 167        const __be32 *p;
 168        int reg_tuple_size;
 169        struct mtd_info **mtd_list = NULL;
 170        resource_size_t res_size;
 171        struct mtd_part_parser_data ppdata;
 172
 173        match = of_match_device(of_flash_match, &dev->dev);
 174        if (!match)
 175                return -EINVAL;
 176        probe_type = match->data;
 177
 178        reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
 179
 180        /*
 181         * Get number of "reg" tuples. Scan for MTD devices on area's
 182         * described by each "reg" region. This makes it possible (including
 183         * the concat support) to support the Intel P30 48F4400 chips which
 184         * consists internally of 2 non-identical NOR chips on one die.
 185         */
 186        p = of_get_property(dp, "reg", &count);
 187        if (count % reg_tuple_size != 0) {
 188                dev_err(&dev->dev, "Malformed reg property on %s\n",
 189                                dev->dev.of_node->full_name);
 190                err = -EINVAL;
 191                goto err_flash_remove;
 192        }
 193        count /= reg_tuple_size;
 194
 195        err = -ENOMEM;
 196        info = kzalloc(sizeof(struct of_flash) +
 197                       sizeof(struct of_flash_list) * count, GFP_KERNEL);
 198        if (!info)
 199                goto err_flash_remove;
 200
 201        dev_set_drvdata(&dev->dev, info);
 202
 203        mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
 204        if (!mtd_list)
 205                goto err_flash_remove;
 206
 207        for (i = 0; i < count; i++) {
 208                err = -ENXIO;
 209                if (of_address_to_resource(dp, i, &res)) {
 210                        /*
 211                         * Continue with next register tuple if this
 212                         * one is not mappable
 213                         */
 214                        continue;
 215                }
 216
 217                dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
 218
 219                err = -EBUSY;
 220                res_size = resource_size(&res);
 221                info->list[i].res = request_mem_region(res.start, res_size,
 222                                                       dev_name(&dev->dev));
 223                if (!info->list[i].res)
 224                        goto err_out;
 225
 226                err = -ENXIO;
 227                width = of_get_property(dp, "bank-width", NULL);
 228                if (!width) {
 229                        dev_err(&dev->dev, "Can't get bank width from device"
 230                                " tree\n");
 231                        goto err_out;
 232                }
 233
 234                info->list[i].map.name = dev_name(&dev->dev);
 235                info->list[i].map.phys = res.start;
 236                info->list[i].map.size = res_size;
 237                info->list[i].map.bankwidth = be32_to_cpup(width);
 238
 239                err = -ENOMEM;
 240                info->list[i].map.virt = ioremap(info->list[i].map.phys,
 241                                                 info->list[i].map.size);
 242                if (!info->list[i].map.virt) {
 243                        dev_err(&dev->dev, "Failed to ioremap() flash"
 244                                " region\n");
 245                        goto err_out;
 246                }
 247
 248                simple_map_init(&info->list[i].map);
 249
 250                if (probe_type) {
 251                        info->list[i].mtd = do_map_probe(probe_type,
 252                                                         &info->list[i].map);
 253                } else {
 254                        info->list[i].mtd = obsolete_probe(dev,
 255                                                           &info->list[i].map);
 256                }
 257                mtd_list[i] = info->list[i].mtd;
 258
 259                err = -ENXIO;
 260                if (!info->list[i].mtd) {
 261                        dev_err(&dev->dev, "do_map_probe() failed\n");
 262                        goto err_out;
 263                } else {
 264                        info->list_size++;
 265                }
 266                info->list[i].mtd->owner = THIS_MODULE;
 267                info->list[i].mtd->dev.parent = &dev->dev;
 268        }
 269
 270        err = 0;
 271        if (info->list_size == 1) {
 272                info->cmtd = info->list[0].mtd;
 273        } else if (info->list_size > 1) {
 274                /*
 275                 * We detected multiple devices. Concatenate them together.
 276                 */
 277                info->cmtd = mtd_concat_create(mtd_list, info->list_size,
 278                                               dev_name(&dev->dev));
 279                if (info->cmtd == NULL)
 280                        err = -ENXIO;
 281        }
 282        if (err)
 283                goto err_out;
 284
 285        ppdata.of_node = dp;
 286        part_probe_types = of_get_probes(dp);
 287        mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
 288                        NULL, 0);
 289        of_free_probes(part_probe_types);
 290
 291        kfree(mtd_list);
 292
 293        return 0;
 294
 295err_out:
 296        kfree(mtd_list);
 297err_flash_remove:
 298        of_flash_remove(dev);
 299
 300        return err;
 301}
 302
 303static struct of_device_id of_flash_match[] = {
 304        {
 305                .compatible     = "cfi-flash",
 306                .data           = (void *)"cfi_probe",
 307        },
 308        {
 309                /* FIXME: JEDEC chips can't be safely and reliably
 310                 * probed, although the mtd code gets it right in
 311                 * practice most of the time.  We should use the
 312                 * vendor and device ids specified by the binding to
 313                 * bypass the heuristic probe code, but the mtd layer
 314                 * provides, at present, no interface for doing so
 315                 * :(. */
 316                .compatible     = "jedec-flash",
 317                .data           = (void *)"jedec_probe",
 318        },
 319        {
 320                .compatible     = "mtd-ram",
 321                .data           = (void *)"map_ram",
 322        },
 323        {
 324                .type           = "rom",
 325                .compatible     = "direct-mapped"
 326        },
 327        { },
 328};
 329MODULE_DEVICE_TABLE(of, of_flash_match);
 330
 331static struct platform_driver of_flash_driver = {
 332        .driver = {
 333                .name = "of-flash",
 334                .owner = THIS_MODULE,
 335                .of_match_table = of_flash_match,
 336        },
 337        .probe          = of_flash_probe,
 338        .remove         = of_flash_remove,
 339};
 340
 341static int __init of_flash_init(void)
 342{
 343        return platform_driver_register(&of_flash_driver);
 344}
 345
 346static void __exit of_flash_exit(void)
 347{
 348        platform_driver_unregister(&of_flash_driver);
 349}
 350
 351module_init(of_flash_init);
 352module_exit(of_flash_exit);
 353
 354MODULE_LICENSE("GPL");
 355MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
 356MODULE_DESCRIPTION("Device tree based MTD map driver");
 357