2 * Normal mappings of chips in physical memory for OF devices
4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/slab.h>
18 #include <linux/device.h>
19 #include <linux/mtd/mtd.h>
20 #include <linux/mtd/map.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/mtd/physmap.h>
25 #include <asm/of_device.h>
26 #include <asm/of_platform.h>
28 struct physmap_flash_info
{
32 #ifdef CONFIG_MTD_PARTITIONS
34 struct mtd_partition
*parts
;
38 static const char *rom_probe_types
[] = { "cfi_probe", "jedec_probe", "map_rom", NULL
};
39 #ifdef CONFIG_MTD_PARTITIONS
40 static const char *part_probe_types
[] = { "cmdlinepart", "RedBoot", NULL
};
43 #ifdef CONFIG_MTD_PARTITIONS
44 static int parse_flash_partitions(struct device_node
*node
,
45 struct mtd_partition
**parts
)
47 int i
, plen
, retval
= -ENOMEM
;
51 part
= get_property(node
, "partitions", &plen
);
55 retval
= plen
/ (2 * sizeof(u32
));
56 *parts
= kzalloc(retval
* sizeof(struct mtd_partition
), GFP_KERNEL
);
58 printk(KERN_ERR
"Can't allocate the flash partition data!\n");
62 name
= get_property(node
, "partition-names", &plen
);
64 for (i
= 0; i
< retval
; i
++) {
65 (*parts
)[i
].offset
= *part
++;
66 (*parts
)[i
].size
= *part
& ~1;
67 if (*part
++ & 1) /* bit 0 set signifies read only partition */
68 (*parts
)[i
].mask_flags
= MTD_WRITEABLE
;
70 if (name
!= NULL
&& plen
> 0) {
71 int len
= strlen(name
) + 1;
73 (*parts
)[i
].name
= (char *)name
;
77 (*parts
)[i
].name
= "unnamed";
84 static int of_physmap_remove(struct of_device
*dev
)
86 struct physmap_flash_info
*info
;
88 info
= dev_get_drvdata(&dev
->dev
);
91 dev_set_drvdata(&dev
->dev
, NULL
);
93 if (info
->mtd
!= NULL
) {
94 #ifdef CONFIG_MTD_PARTITIONS
96 del_mtd_partitions(info
->mtd
);
99 del_mtd_device(info
->mtd
);
102 del_mtd_device(info
->mtd
);
104 map_destroy(info
->mtd
);
107 if (info
->map
.virt
!= NULL
)
108 iounmap(info
->map
.virt
);
110 if (info
->res
!= NULL
) {
111 release_resource(info
->res
);
118 static int __devinit
of_physmap_probe(struct of_device
*dev
, const struct of_device_id
*match
)
120 struct device_node
*dp
= dev
->node
;
122 struct physmap_flash_info
*info
;
123 const char **probe_type
;
124 const char *of_probe
;
129 if (of_address_to_resource(dp
, 0, &res
)) {
130 dev_err(&dev
->dev
, "Can't get the flash mapping!\n");
135 dev_dbg(&dev
->dev
, "physmap flash device: %.8llx at %.8llx\n",
136 (unsigned long long)res
.end
- res
.start
+ 1,
137 (unsigned long long)res
.start
);
139 info
= kzalloc(sizeof(struct physmap_flash_info
), GFP_KERNEL
);
144 memset(info
, 0, sizeof(*info
));
146 dev_set_drvdata(&dev
->dev
, info
);
148 info
->res
= request_mem_region(res
.start
, res
.end
- res
.start
+ 1,
150 if (info
->res
== NULL
) {
151 dev_err(&dev
->dev
, "Could not reserve memory region\n");
156 width
= get_property(dp
, "bank-width", NULL
);
158 dev_err(&dev
->dev
, "Can't get the flash bank width!\n");
163 info
->map
.name
= dev
->dev
.bus_id
;
164 info
->map
.phys
= res
.start
;
165 info
->map
.size
= res
.end
- res
.start
+ 1;
166 info
->map
.bankwidth
= *width
;
168 info
->map
.virt
= ioremap(info
->map
.phys
, info
->map
.size
);
169 if (info
->map
.virt
== NULL
) {
170 dev_err(&dev
->dev
, "Failed to ioremap flash region\n");
175 simple_map_init(&info
->map
);
177 of_probe
= get_property(dp
, "probe-type", NULL
);
178 if (of_probe
== NULL
) {
179 probe_type
= rom_probe_types
;
180 for (; info
->mtd
== NULL
&& *probe_type
!= NULL
; probe_type
++)
181 info
->mtd
= do_map_probe(*probe_type
, &info
->map
);
182 } else if (!strcmp(of_probe
, "CFI"))
183 info
->mtd
= do_map_probe("cfi_probe", &info
->map
);
184 else if (!strcmp(of_probe
, "JEDEC"))
185 info
->mtd
= do_map_probe("jedec_probe", &info
->map
);
187 if (strcmp(of_probe
, "ROM"))
188 dev_dbg(&dev
->dev
, "map_probe: don't know probe type "
189 "'%s', mapping as rom\n");
190 info
->mtd
= do_map_probe("mtd_rom", &info
->map
);
192 if (info
->mtd
== NULL
) {
193 dev_err(&dev
->dev
, "map_probe failed\n");
197 info
->mtd
->owner
= THIS_MODULE
;
199 #ifdef CONFIG_MTD_PARTITIONS
200 err
= parse_mtd_partitions(info
->mtd
, part_probe_types
, &info
->parts
, 0);
202 add_mtd_partitions(info
->mtd
, info
->parts
, err
);
203 } else if ((err
= parse_flash_partitions(dp
, &info
->parts
)) > 0) {
204 dev_info(&dev
->dev
, "Using OF partition information\n");
205 add_mtd_partitions(info
->mtd
, info
->parts
, err
);
206 info
->nr_parts
= err
;
210 add_mtd_device(info
->mtd
);
214 of_physmap_remove(dev
);
222 static struct of_device_id of_physmap_match
[] = {
225 .compatible
= "direct-mapped"
230 MODULE_DEVICE_TABLE(of
, of_physmap_match
);
233 static struct of_platform_driver of_physmap_flash_driver
= {
234 .name
= "physmap-flash",
235 .match_table
= of_physmap_match
,
236 .probe
= of_physmap_probe
,
237 .remove
= of_physmap_remove
,
240 static int __init
of_physmap_init(void)
242 return of_register_platform_driver(&of_physmap_flash_driver
);
245 static void __exit
of_physmap_exit(void)
247 of_unregister_platform_driver(&of_physmap_flash_driver
);
250 module_init(of_physmap_init
);
251 module_exit(of_physmap_exit
);
253 MODULE_LICENSE("GPL");
254 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
255 MODULE_DESCRIPTION("Configurable MTD map driver for OF");