OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | --- a/drivers/mtd/maps/lantiq-flash.c |
2 | +++ b/drivers/mtd/maps/lantiq-flash.c |
||
3 | @@ -19,6 +19,7 @@ |
||
4 | #include <linux/mtd/cfi.h> |
||
5 | #include <linux/platform_device.h> |
||
6 | #include <linux/mtd/physmap.h> |
||
7 | +#include <linux/mtd/concat.h> |
||
8 | #include <linux/of.h> |
||
9 | |||
10 | #include <lantiq_soc.h> |
||
11 | @@ -38,13 +39,16 @@ enum { |
||
12 | LTQ_NOR_NORMAL |
||
13 | }; |
||
14 | |||
15 | +#define MAX_RESOURCES 4 |
||
16 | + |
||
17 | struct ltq_mtd { |
||
18 | - struct resource *res; |
||
19 | - struct mtd_info *mtd; |
||
20 | - struct map_info *map; |
||
21 | + struct mtd_info *mtd[MAX_RESOURCES]; |
||
22 | + struct mtd_info *cmtd; |
||
23 | + struct map_info map[MAX_RESOURCES]; |
||
24 | }; |
||
25 | |||
26 | static const char ltq_map_name[] = "ltq_nor"; |
||
27 | +static const char * const ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL }; |
||
28 | |||
29 | static map_word |
||
30 | ltq_read16(struct map_info *map, unsigned long adr) |
||
31 | @@ -108,11 +112,43 @@ ltq_copy_to(struct map_info *map, unsign |
||
32 | } |
||
33 | |||
34 | static int |
||
35 | +ltq_mtd_remove(struct platform_device *pdev) |
||
36 | +{ |
||
37 | + struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); |
||
38 | + int i; |
||
39 | + |
||
40 | + if (ltq_mtd == NULL) |
||
41 | + return 0; |
||
42 | + |
||
43 | + if (ltq_mtd->cmtd) { |
||
44 | + mtd_device_unregister(ltq_mtd->cmtd); |
||
45 | + if (ltq_mtd->cmtd != ltq_mtd->mtd[0]) |
||
46 | + mtd_concat_destroy(ltq_mtd->cmtd); |
||
47 | + } |
||
48 | + |
||
49 | + for (i = 0; i < MAX_RESOURCES; i++) { |
||
50 | + if (ltq_mtd->mtd[i] != NULL) |
||
51 | + map_destroy(ltq_mtd->mtd[i]); |
||
52 | + } |
||
53 | + |
||
54 | + kfree(ltq_mtd); |
||
55 | + |
||
56 | + return 0; |
||
57 | +} |
||
58 | + |
||
59 | +static int |
||
60 | ltq_mtd_probe(struct platform_device *pdev) |
||
61 | { |
||
62 | struct ltq_mtd *ltq_mtd; |
||
63 | struct cfi_private *cfi; |
||
64 | - int err; |
||
65 | + int err = 0; |
||
66 | + int i; |
||
67 | + int devices_found = 0; |
||
68 | + |
||
69 | + static const char *rom_probe_types[] = { |
||
70 | + "cfi_probe", "jedec_probe", NULL |
||
71 | + }; |
||
72 | + const char **type; |
||
73 | |||
74 | if (of_machine_is_compatible("lantiq,falcon") && |
||
75 | (ltq_boot_select() != BS_FLASH)) { |
||
76 | @@ -126,75 +162,89 @@ ltq_mtd_probe(struct platform_device *pd |
||
77 | |||
78 | platform_set_drvdata(pdev, ltq_mtd); |
||
79 | |||
80 | - ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
81 | - if (!ltq_mtd->res) { |
||
82 | - dev_err(&pdev->dev, "failed to get memory resource\n"); |
||
83 | - return -ENOENT; |
||
84 | + for (i = 0; i < pdev->num_resources; i++) { |
||
85 | + printk(KERN_NOTICE "lantiq nor flash device: %.8llx at %.8llx\n", |
||
86 | + (unsigned long long)resource_size(&pdev->resource[i]), |
||
87 | + (unsigned long long)pdev->resource[i].start); |
||
88 | + |
||
89 | + if (!devm_request_mem_region(&pdev->dev, |
||
90 | + pdev->resource[i].start, |
||
91 | + resource_size(&pdev->resource[i]), |
||
92 | + dev_name(&pdev->dev))) { |
||
93 | + dev_err(&pdev->dev, "Could not reserve memory region\n"); |
||
94 | + return -ENOMEM; |
||
95 | + } |
||
96 | + |
||
97 | + ltq_mtd->map[i].name = ltq_map_name; |
||
98 | + ltq_mtd->map[i].bankwidth = 2; |
||
99 | + ltq_mtd->map[i].read = ltq_read16; |
||
100 | + ltq_mtd->map[i].write = ltq_write16; |
||
101 | + ltq_mtd->map[i].copy_from = ltq_copy_from; |
||
102 | + ltq_mtd->map[i].copy_to = ltq_copy_to; |
||
103 | + |
||
104 | + if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) |
||
105 | + ltq_mtd->map[i].phys = NO_XIP; |
||
106 | + else |
||
107 | + ltq_mtd->map[i].phys = pdev->resource[i].start; |
||
108 | + ltq_mtd->map[i].size = resource_size(&pdev->resource[i]); |
||
109 | + ltq_mtd->map[i].virt = devm_ioremap(&pdev->dev, pdev->resource[i].start, |
||
110 | + ltq_mtd->map[i].size); |
||
111 | + if (IS_ERR(ltq_mtd->map[i].virt)) |
||
112 | + return PTR_ERR(ltq_mtd->map[i].virt); |
||
113 | + |
||
114 | + if (ltq_mtd->map[i].virt == NULL) { |
||
115 | + dev_err(&pdev->dev, "Failed to ioremap flash region\n"); |
||
116 | + err = PTR_ERR(ltq_mtd->map[i].virt); |
||
117 | + goto err_out; |
||
118 | + } |
||
119 | + |
||
120 | + ltq_mtd->map[i].map_priv_1 = LTQ_NOR_PROBING; |
||
121 | + for (type = rom_probe_types; !ltq_mtd->mtd[i] && *type; type++) |
||
122 | + ltq_mtd->mtd[i] = do_map_probe(*type, <q_mtd->map[i]); |
||
123 | + ltq_mtd->map[i].map_priv_1 = LTQ_NOR_NORMAL; |
||
124 | + |
||
125 | + if (!ltq_mtd->mtd[i]) { |
||
126 | + dev_err(&pdev->dev, "probing failed\n"); |
||
127 | + return -ENXIO; |
||
128 | + } else { |
||
129 | + devices_found++; |
||
130 | + } |
||
131 | + |
||
132 | + ltq_mtd->mtd[i]->owner = THIS_MODULE; |
||
133 | + ltq_mtd->mtd[i]->dev.parent = &pdev->dev; |
||
134 | + |
||
135 | + cfi = ltq_mtd->map[i].fldrv_priv; |
||
136 | + cfi->addr_unlock1 ^= 1; |
||
137 | + cfi->addr_unlock2 ^= 1; |
||
138 | } |
||
139 | |||
140 | - ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), |
||
141 | - GFP_KERNEL); |
||
142 | - if (!ltq_mtd->map) |
||
143 | - return -ENOMEM; |
||
144 | + if (devices_found == 1) { |
||
145 | + ltq_mtd->cmtd = ltq_mtd->mtd[0]; |
||
146 | + } else if (devices_found > 1) { |
||
147 | + /* |
||
148 | + * We detected multiple devices. Concatenate them together. |
||
149 | + */ |
||
150 | + ltq_mtd->cmtd = mtd_concat_create(ltq_mtd->mtd, devices_found, dev_name(&pdev->dev)); |
||
151 | + if (ltq_mtd->cmtd == NULL) |
||
152 | + err = -ENXIO; |
||
153 | + } |
||
154 | |||
155 | - if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL)) |
||
156 | - ltq_mtd->map->phys = NO_XIP; |
||
157 | - else |
||
158 | - ltq_mtd->map->phys = ltq_mtd->res->start; |
||
159 | - ltq_mtd->res->start; |
||
160 | - ltq_mtd->map->size = resource_size(ltq_mtd->res); |
||
161 | - ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); |
||
162 | - if (IS_ERR(ltq_mtd->map->virt)) |
||
163 | - return PTR_ERR(ltq_mtd->map->virt); |
||
164 | - |
||
165 | - ltq_mtd->map->name = ltq_map_name; |
||
166 | - ltq_mtd->map->bankwidth = 2; |
||
167 | - ltq_mtd->map->read = ltq_read16; |
||
168 | - ltq_mtd->map->write = ltq_write16; |
||
169 | - ltq_mtd->map->copy_from = ltq_copy_from; |
||
170 | - ltq_mtd->map->copy_to = ltq_copy_to; |
||
171 | - |
||
172 | - ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; |
||
173 | - ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map); |
||
174 | - ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; |
||
175 | - |
||
176 | - if (!ltq_mtd->mtd) { |
||
177 | - dev_err(&pdev->dev, "probing failed\n"); |
||
178 | - return -ENXIO; |
||
179 | - } |
||
180 | - |
||
181 | - ltq_mtd->mtd->dev.parent = &pdev->dev; |
||
182 | - mtd_set_of_node(ltq_mtd->mtd, pdev->dev.of_node); |
||
183 | - |
||
184 | - cfi = ltq_mtd->map->fldrv_priv; |
||
185 | - cfi->addr_unlock1 ^= 1; |
||
186 | - cfi->addr_unlock2 ^= 1; |
||
187 | + ltq_mtd->cmtd->dev.parent = &pdev->dev; |
||
188 | + mtd_set_of_node(ltq_mtd->cmtd, pdev->dev.of_node); |
||
189 | |||
190 | - err = mtd_device_register(ltq_mtd->mtd, NULL, 0); |
||
191 | + err = mtd_device_register(ltq_mtd->cmtd, NULL, 0); |
||
192 | if (err) { |
||
193 | dev_err(&pdev->dev, "failed to add partitions\n"); |
||
194 | - goto err_destroy; |
||
195 | + goto err_out; |
||
196 | } |
||
197 | |||
198 | return 0; |
||
199 | |||
200 | -err_destroy: |
||
201 | - map_destroy(ltq_mtd->mtd); |
||
202 | +err_out: |
||
203 | + ltq_mtd_remove(pdev); |
||
204 | return err; |
||
205 | } |
||
206 | |||
207 | -static int |
||
208 | -ltq_mtd_remove(struct platform_device *pdev) |
||
209 | -{ |
||
210 | - struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); |
||
211 | - |
||
212 | - if (ltq_mtd && ltq_mtd->mtd) { |
||
213 | - mtd_device_unregister(ltq_mtd->mtd); |
||
214 | - map_destroy(ltq_mtd->mtd); |
||
215 | - } |
||
216 | - return 0; |
||
217 | -} |
||
218 | - |
||
219 | static const struct of_device_id ltq_mtd_match[] = { |
||
220 | { .compatible = "lantiq,nor" }, |
||
221 | {}, |