linux/drivers/mtd/ofpart.c
<<
>>
Prefs
   1/*
   2 * Flash partitions described by the OF (or flattened) device tree
   3 *
   4 * Copyright © 2006 MontaVista Software Inc.
   5 * Author: Vitaly Wool <vwool@ru.mvista.com>
   6 *
   7 * Revised to handle newer style flash binding by:
   8 *   Copyright © 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/init.h>
  18#include <linux/of.h>
  19#include <linux/mtd/mtd.h>
  20#include <linux/slab.h>
  21#include <linux/mtd/partitions.h>
  22
  23static int parse_ofpart_partitions(struct mtd_info *master,
  24                                   struct mtd_partition **pparts,
  25                                   struct mtd_part_parser_data *data)
  26{
  27        struct device_node *node;
  28        const char *partname;
  29        struct device_node *pp;
  30        int nr_parts, i;
  31
  32
  33        if (!data)
  34                return 0;
  35
  36        node = data->of_node;
  37        if (!node)
  38                return 0;
  39
  40        /* First count the subnodes */
  41        pp = NULL;
  42        nr_parts = 0;
  43        while ((pp = of_get_next_child(node, pp)))
  44                nr_parts++;
  45
  46        if (nr_parts == 0)
  47                return 0;
  48
  49        *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
  50        if (!*pparts)
  51                return -ENOMEM;
  52
  53        pp = NULL;
  54        i = 0;
  55        while ((pp = of_get_next_child(node, pp))) {
  56                const __be32 *reg;
  57                int len;
  58                int a_cells, s_cells;
  59
  60                reg = of_get_property(pp, "reg", &len);
  61                if (!reg) {
  62                        nr_parts--;
  63                        continue;
  64                }
  65
  66                a_cells = of_n_addr_cells(pp);
  67                s_cells = of_n_size_cells(pp);
  68                (*pparts)[i].offset = of_read_number(reg, a_cells);
  69                (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
  70
  71                partname = of_get_property(pp, "label", &len);
  72                if (!partname)
  73                        partname = of_get_property(pp, "name", &len);
  74                (*pparts)[i].name = (char *)partname;
  75
  76                if (of_get_property(pp, "read-only", &len))
  77                        (*pparts)[i].mask_flags |= MTD_WRITEABLE;
  78
  79                if (of_get_property(pp, "lock", &len))
  80                        (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
  81
  82                i++;
  83        }
  84
  85        if (!i) {
  86                of_node_put(pp);
  87                pr_err("No valid partition found on %s\n", node->full_name);
  88                kfree(*pparts);
  89                *pparts = NULL;
  90                return -EINVAL;
  91        }
  92
  93        return nr_parts;
  94}
  95
  96static struct mtd_part_parser ofpart_parser = {
  97        .owner = THIS_MODULE,
  98        .parse_fn = parse_ofpart_partitions,
  99        .name = "ofpart",
 100};
 101
 102static int parse_ofoldpart_partitions(struct mtd_info *master,
 103                                      struct mtd_partition **pparts,
 104                                      struct mtd_part_parser_data *data)
 105{
 106        struct device_node *dp;
 107        int i, plen, nr_parts;
 108        const struct {
 109                __be32 offset, len;
 110        } *part;
 111        const char *names;
 112
 113        if (!data)
 114                return 0;
 115
 116        dp = data->of_node;
 117        if (!dp)
 118                return 0;
 119
 120        part = of_get_property(dp, "partitions", &plen);
 121        if (!part)
 122                return 0; /* No partitions found */
 123
 124        pr_warning("Device tree uses obsolete partition map binding: %s\n",
 125                        dp->full_name);
 126
 127        nr_parts = plen / sizeof(part[0]);
 128
 129        *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
 130        if (!*pparts)
 131                return -ENOMEM;
 132
 133        names = of_get_property(dp, "partition-names", &plen);
 134
 135        for (i = 0; i < nr_parts; i++) {
 136                (*pparts)[i].offset = be32_to_cpu(part->offset);
 137                (*pparts)[i].size   = be32_to_cpu(part->len) & ~1;
 138                /* bit 0 set signifies read only partition */
 139                if (be32_to_cpu(part->len) & 1)
 140                        (*pparts)[i].mask_flags = MTD_WRITEABLE;
 141
 142                if (names && (plen > 0)) {
 143                        int len = strlen(names) + 1;
 144
 145                        (*pparts)[i].name = (char *)names;
 146                        plen -= len;
 147                        names += len;
 148                } else {
 149                        (*pparts)[i].name = "unnamed";
 150                }
 151
 152                part++;
 153        }
 154
 155        return nr_parts;
 156}
 157
 158static struct mtd_part_parser ofoldpart_parser = {
 159        .owner = THIS_MODULE,
 160        .parse_fn = parse_ofoldpart_partitions,
 161        .name = "ofoldpart",
 162};
 163
 164static int __init ofpart_parser_init(void)
 165{
 166        int rc;
 167        rc = register_mtd_parser(&ofpart_parser);
 168        if (rc)
 169                goto out;
 170
 171        rc = register_mtd_parser(&ofoldpart_parser);
 172        if (!rc)
 173                return 0;
 174
 175        deregister_mtd_parser(&ofoldpart_parser);
 176out:
 177        return rc;
 178}
 179
 180static void __exit ofpart_parser_exit(void)
 181{
 182        deregister_mtd_parser(&ofpart_parser);
 183        deregister_mtd_parser(&ofoldpart_parser);
 184}
 185
 186module_init(ofpart_parser_init);
 187module_exit(ofpart_parser_exit);
 188
 189MODULE_LICENSE("GPL");
 190MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
 191MODULE_AUTHOR("Vitaly Wool, David Gibson");
 192/*
 193 * When MTD core cannot find the requested parser, it tries to load the module
 194 * with the same name. Since we provide the ofoldpart parser, we should have
 195 * the corresponding alias.
 196 */
 197MODULE_ALIAS("ofoldpart");
 198