Root/drivers/mtd/ofpart.c

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
59        reg = of_get_property(pp, "reg", &len);
60        if (!reg) {
61            nr_parts--;
62            continue;
63        }
64
65        (*pparts)[i].offset = be32_to_cpu(reg[0]);
66        (*pparts)[i].size = be32_to_cpu(reg[1]);
67
68        partname = of_get_property(pp, "label", &len);
69        if (!partname)
70            partname = of_get_property(pp, "name", &len);
71        (*pparts)[i].name = (char *)partname;
72
73        if (of_get_property(pp, "read-only", &len))
74            (*pparts)[i].mask_flags = MTD_WRITEABLE;
75
76        i++;
77    }
78
79    if (!i) {
80        of_node_put(pp);
81        pr_err("No valid partition found on %s\n", node->full_name);
82        kfree(*pparts);
83        *pparts = NULL;
84        return -EINVAL;
85    }
86
87    return nr_parts;
88}
89
90static struct mtd_part_parser ofpart_parser = {
91    .owner = THIS_MODULE,
92    .parse_fn = parse_ofpart_partitions,
93    .name = "ofpart",
94};
95
96static int parse_ofoldpart_partitions(struct mtd_info *master,
97                      struct mtd_partition **pparts,
98                      struct mtd_part_parser_data *data)
99{
100    struct device_node *dp;
101    int i, plen, nr_parts;
102    const struct {
103        __be32 offset, len;
104    } *part;
105    const char *names;
106
107    if (!data)
108        return 0;
109
110    dp = data->of_node;
111    if (!dp)
112        return 0;
113
114    part = of_get_property(dp, "partitions", &plen);
115    if (!part)
116        return 0; /* No partitions found */
117
118    pr_warning("Device tree uses obsolete partition map binding: %s\n",
119            dp->full_name);
120
121    nr_parts = plen / sizeof(part[0]);
122
123    *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
124    if (!pparts)
125        return -ENOMEM;
126
127    names = of_get_property(dp, "partition-names", &plen);
128
129    for (i = 0; i < nr_parts; i++) {
130        (*pparts)[i].offset = be32_to_cpu(part->offset);
131        (*pparts)[i].size = be32_to_cpu(part->len) & ~1;
132        /* bit 0 set signifies read only partition */
133        if (be32_to_cpu(part->len) & 1)
134            (*pparts)[i].mask_flags = MTD_WRITEABLE;
135
136        if (names && (plen > 0)) {
137            int len = strlen(names) + 1;
138
139            (*pparts)[i].name = (char *)names;
140            plen -= len;
141            names += len;
142        } else {
143            (*pparts)[i].name = "unnamed";
144        }
145
146        part++;
147    }
148
149    return nr_parts;
150}
151
152static struct mtd_part_parser ofoldpart_parser = {
153    .owner = THIS_MODULE,
154    .parse_fn = parse_ofoldpart_partitions,
155    .name = "ofoldpart",
156};
157
158static int __init ofpart_parser_init(void)
159{
160    int rc;
161    rc = register_mtd_parser(&ofpart_parser);
162    if (rc)
163        goto out;
164
165    rc = register_mtd_parser(&ofoldpart_parser);
166    if (!rc)
167        return 0;
168
169    deregister_mtd_parser(&ofoldpart_parser);
170out:
171    return rc;
172}
173
174module_init(ofpart_parser_init);
175
176MODULE_LICENSE("GPL");
177MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
178MODULE_AUTHOR("Vitaly Wool, David Gibson");
179/*
180 * When MTD core cannot find the requested parser, it tries to load the module
181 * with the same name. Since we provide the ofoldpart parser, we should have
182 * the corresponding alias.
183 */
184MODULE_ALIAS("ofoldpart");
185

Archive Download this file



interactive