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