at v3.11-rc3 197 lines 4.5 kB view raw
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");