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