aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Roese <sr@denx.de>2008-02-01 09:26:54 -0500
committerDavid Woodhouse <dwmw2@infradead.org>2008-02-03 06:16:02 -0500
commitdf66e7167ac756baf14d2b8ea7a2cfa056600a93 (patch)
treeddebde50194d44dff8466039c8fa12c878018c43
parent1c45f60406e61a06631416264e49eb5afd9fc324 (diff)
[MTD] physmap.c: Add support for multiple resources
This patch extends the physmap mapping driver to support multiple resources for non-identical NOR chips that will be concatenated together when selected. This is needed for example for Intel 48F4400 512MBit chips, since they consist of 2 single different NOR chips with different geometries. The first (lower) one has botton boot sectors and the 2nd (upper) has top boot sectors. This currently isn't handled correctly by calling the physmap driver once with only one resource covering both chips in one memory region. The same geometrie is used for both chips. With this patch the following resource structure can be used to describe the 48F4400 chip correctly: static struct resource board_nor_resource[] = { [0] = { .start = 0xf8000000, .end = 0xfbffffff, .flags = IORESOURCE_MEM, }, [1] = { .start = 0xfc000000, .end = 0xffffffff, .flags = IORESOURCE_MEM, } }; Signed-off-by: Stefan Roese <sr@denx.de> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--drivers/mtd/maps/physmap.c162
1 files changed, 104 insertions, 58 deletions
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 28c5ffd75233..5a83ae7e14f9 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -20,11 +20,15 @@
20#include <linux/mtd/map.h> 20#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h> 21#include <linux/mtd/partitions.h>
22#include <linux/mtd/physmap.h> 22#include <linux/mtd/physmap.h>
23#include <linux/mtd/concat.h>
23#include <asm/io.h> 24#include <asm/io.h>
24 25
26#define MAX_RESOURCES 4
27
25struct physmap_flash_info { 28struct physmap_flash_info {
26 struct mtd_info *mtd; 29 struct mtd_info *mtd[MAX_RESOURCES];
27 struct map_info map; 30 struct mtd_info *cmtd;
31 struct map_info map[MAX_RESOURCES];
28 struct resource *res; 32 struct resource *res;
29#ifdef CONFIG_MTD_PARTITIONS 33#ifdef CONFIG_MTD_PARTITIONS
30 int nr_parts; 34 int nr_parts;
@@ -32,11 +36,11 @@ struct physmap_flash_info {
32#endif 36#endif
33}; 37};
34 38
35
36static int physmap_flash_remove(struct platform_device *dev) 39static int physmap_flash_remove(struct platform_device *dev)
37{ 40{
38 struct physmap_flash_info *info; 41 struct physmap_flash_info *info;
39 struct physmap_flash_data *physmap_data; 42 struct physmap_flash_data *physmap_data;
43 int i;
40 44
41 info = platform_get_drvdata(dev); 45 info = platform_get_drvdata(dev);
42 if (info == NULL) 46 if (info == NULL)
@@ -45,24 +49,33 @@ static int physmap_flash_remove(struct platform_device *dev)
45 49
46 physmap_data = dev->dev.platform_data; 50 physmap_data = dev->dev.platform_data;
47 51
48 if (info->mtd != NULL) { 52#ifdef CONFIG_MTD_CONCAT
53 if (info->cmtd != info->mtd[0]) {
54 del_mtd_device(info->cmtd);
55 mtd_concat_destroy(info->cmtd);
56 }
57#endif
58
59 for (i = 0; i < MAX_RESOURCES; i++) {
60 if (info->mtd[i] != NULL) {
49#ifdef CONFIG_MTD_PARTITIONS 61#ifdef CONFIG_MTD_PARTITIONS
50 if (info->nr_parts) { 62 if (info->nr_parts) {
51 del_mtd_partitions(info->mtd); 63 del_mtd_partitions(info->mtd[i]);
52 kfree(info->parts); 64 kfree(info->parts);
53 } else if (physmap_data->nr_parts) { 65 } else if (physmap_data->nr_parts) {
54 del_mtd_partitions(info->mtd); 66 del_mtd_partitions(info->mtd[i]);
55 } else { 67 } else {
56 del_mtd_device(info->mtd); 68 del_mtd_device(info->mtd[i]);
57 } 69 }
58#else 70#else
59 del_mtd_device(info->mtd); 71 del_mtd_device(info->mtd[i]);
60#endif 72#endif
61 map_destroy(info->mtd); 73 map_destroy(info->mtd[i]);
62 } 74 }
63 75
64 if (info->map.virt != NULL) 76 if (info->map[i].virt != NULL)
65 iounmap(info->map.virt); 77 iounmap(info->map[i].virt);
78 }
66 79
67 if (info->res != NULL) { 80 if (info->res != NULL) {
68 release_resource(info->res); 81 release_resource(info->res);
@@ -82,16 +95,14 @@ static int physmap_flash_probe(struct platform_device *dev)
82 struct physmap_flash_data *physmap_data; 95 struct physmap_flash_data *physmap_data;
83 struct physmap_flash_info *info; 96 struct physmap_flash_info *info;
84 const char **probe_type; 97 const char **probe_type;
85 int err; 98 int err = 0;
99 int i;
100 int devices_found = 0;
86 101
87 physmap_data = dev->dev.platform_data; 102 physmap_data = dev->dev.platform_data;
88 if (physmap_data == NULL) 103 if (physmap_data == NULL)
89 return -ENODEV; 104 return -ENODEV;
90 105
91 printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
92 (unsigned long long)(dev->resource->end - dev->resource->start + 1),
93 (unsigned long long)dev->resource->start);
94
95 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); 106 info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
96 if (info == NULL) { 107 if (info == NULL) {
97 err = -ENOMEM; 108 err = -ENOMEM;
@@ -100,56 +111,83 @@ static int physmap_flash_probe(struct platform_device *dev)
100 111
101 platform_set_drvdata(dev, info); 112 platform_set_drvdata(dev, info);
102 113
103 info->res = request_mem_region(dev->resource->start, 114 for (i = 0; i < dev->num_resources; i++) {
104 dev->resource->end - dev->resource->start + 1, 115 printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
105 dev->dev.bus_id); 116 (unsigned long long)(dev->resource[i].end - dev->resource[i].start + 1),
106 if (info->res == NULL) { 117 (unsigned long long)dev->resource[i].start);
107 dev_err(&dev->dev, "Could not reserve memory region\n"); 118
108 err = -ENOMEM; 119 info->res = request_mem_region(dev->resource[i].start,
109 goto err_out; 120 dev->resource[i].end - dev->resource[i].start + 1,
110 } 121 dev->dev.bus_id);
122 if (info->res == NULL) {
123 dev_err(&dev->dev, "Could not reserve memory region\n");
124 err = -ENOMEM;
125 goto err_out;
126 }
111 127
112 info->map.name = dev->dev.bus_id; 128 info->map[i].name = dev->dev.bus_id;
113 info->map.phys = dev->resource->start; 129 info->map[i].phys = dev->resource[i].start;
114 info->map.size = dev->resource->end - dev->resource->start + 1; 130 info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
115 info->map.bankwidth = physmap_data->width; 131 info->map[i].bankwidth = physmap_data->width;
116 info->map.set_vpp = physmap_data->set_vpp; 132 info->map[i].set_vpp = physmap_data->set_vpp;
133
134 info->map[i].virt = ioremap(info->map[i].phys, info->map[i].size);
135 if (info->map[i].virt == NULL) {
136 dev_err(&dev->dev, "Failed to ioremap flash region\n");
137 err = EIO;
138 goto err_out;
139 }
117 140
118 info->map.virt = ioremap(info->map.phys, info->map.size); 141 simple_map_init(&info->map[i]);
119 if (info->map.virt == NULL) {
120 dev_err(&dev->dev, "Failed to ioremap flash region\n");
121 err = EIO;
122 goto err_out;
123 }
124 142
125 simple_map_init(&info->map); 143 probe_type = rom_probe_types;
144 for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++)
145 info->mtd[i] = do_map_probe(*probe_type, &info->map[i]);
146 if (info->mtd[i] == NULL) {
147 dev_err(&dev->dev, "map_probe failed\n");
148 err = -ENXIO;
149 goto err_out;
150 } else {
151 devices_found++;
152 }
153 info->mtd[i]->owner = THIS_MODULE;
154 }
126 155
127 probe_type = rom_probe_types; 156 if (devices_found == 1) {
128 for (; info->mtd == NULL && *probe_type != NULL; probe_type++) 157 info->cmtd = info->mtd[0];
129 info->mtd = do_map_probe(*probe_type, &info->map); 158 } else if (devices_found > 1) {
130 if (info->mtd == NULL) { 159 /*
131 dev_err(&dev->dev, "map_probe failed\n"); 160 * We detected multiple devices. Concatenate them together.
161 */
162#ifdef CONFIG_MTD_CONCAT
163 info->cmtd = mtd_concat_create(info->mtd, devices_found, dev->dev.bus_id);
164 if (info->cmtd == NULL)
165 err = -ENXIO;
166#else
167 printk(KERN_ERR "physmap-flash: multiple devices "
168 "found but MTD concat support disabled.\n");
132 err = -ENXIO; 169 err = -ENXIO;
133 goto err_out; 170#endif
134 } 171 }
135 info->mtd->owner = THIS_MODULE; 172 if (err)
173 goto err_out;
136 174
137#ifdef CONFIG_MTD_PARTITIONS 175#ifdef CONFIG_MTD_PARTITIONS
138 err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); 176 err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0);
139 if (err > 0) { 177 if (err > 0) {
140 add_mtd_partitions(info->mtd, info->parts, err); 178 add_mtd_partitions(info->cmtd, info->parts, err);
141 return 0; 179 return 0;
142 } 180 }
143 181
144 if (physmap_data->nr_parts) { 182 if (physmap_data->nr_parts) {
145 printk(KERN_NOTICE "Using physmap partition information\n"); 183 printk(KERN_NOTICE "Using physmap partition information\n");
146 add_mtd_partitions(info->mtd, physmap_data->parts, 184 add_mtd_partitions(info->cmtd, physmap_data->parts,
147 physmap_data->nr_parts); 185 physmap_data->nr_parts);
148 return 0; 186 return 0;
149 } 187 }
150#endif 188#endif
151 189
152 add_mtd_device(info->mtd); 190 add_mtd_device(info->cmtd);
153 return 0; 191 return 0;
154 192
155err_out: 193err_out:
@@ -162,9 +200,11 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
162{ 200{
163 struct physmap_flash_info *info = platform_get_drvdata(dev); 201 struct physmap_flash_info *info = platform_get_drvdata(dev);
164 int ret = 0; 202 int ret = 0;
203 int i;
165 204
166 if (info) 205 if (info)
167 ret = info->mtd->suspend(info->mtd); 206 for (i = 0; i < MAX_RESOURCES; i++)
207 ret |= info->mtd[i].suspend(info->mtd[i]);
168 208
169 return ret; 209 return ret;
170} 210}
@@ -172,16 +212,22 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state
172static int physmap_flash_resume(struct platform_device *dev) 212static int physmap_flash_resume(struct platform_device *dev)
173{ 213{
174 struct physmap_flash_info *info = platform_get_drvdata(dev); 214 struct physmap_flash_info *info = platform_get_drvdata(dev);
215 int i;
216
175 if (info) 217 if (info)
176 info->mtd->resume(info->mtd); 218 for (i = 0; i < MAX_RESOURCES; i++)
219 info->mtd[i].resume(info->mtd[i]);
177 return 0; 220 return 0;
178} 221}
179 222
180static void physmap_flash_shutdown(struct platform_device *dev) 223static void physmap_flash_shutdown(struct platform_device *dev)
181{ 224{
182 struct physmap_flash_info *info = platform_get_drvdata(dev); 225 struct physmap_flash_info *info = platform_get_drvdata(dev);
183 if (info && info->mtd->suspend(info->mtd) == 0) 226 int i;
184 info->mtd->resume(info->mtd); 227
228 for (i = 0; i < MAX_RESOURCES; i++)
229 if (info && info->mtd[i].suspend(info->mtd[i]) == 0)
230 info->mtd[i].resume(info->mtd[i]);
185} 231}
186#endif 232#endif
187 233