aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/maps
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-09-23 13:51:25 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-09-23 13:51:25 -0400
commit0bac5111cc00b70460dd8ba8340522e1f0d79f05 (patch)
treea4acd567a75ba775f28aed81993bd4b82aa61e5a /drivers/mtd/maps
parent59d8235be2ab38ddaffbe9137385095a5e8b0a77 (diff)
[MTD] map driver for NOR flash on the Intel Vermilion Range chipset
The Vermilion Range Expansion Bus supports four chip selects, each of which has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device is a 256MiB memory region containing the address spaces for all four of the chip selects, with start addresses hardcoded on 64MiB boundaries. This map driver only supports NOR flash on chip select 0. The buswidth (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing and Control Register for Chip Select 0 (EXP_TIMING_CS0). Signed-off-by: Andy Lowe <alowe@mvista.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/maps')
-rw-r--r--drivers/mtd/maps/Kconfig7
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/intel_vr_nor.c298
3 files changed, 306 insertions, 0 deletions
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 7559950e42d0..c2624b2655ac 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -581,6 +581,13 @@ config MTD_SHARP_SL
581 help 581 help
582 This enables access to the flash chip on the Sharp SL Series of PDAs. 582 This enables access to the flash chip on the Sharp SL Series of PDAs.
583 583
584config MTD_INTEL_VR_NOR
585 tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
586 depends on PCI
587 help
588 Map driver for a NOR flash bank located on the Expansion Bus of the
589 Intel Vermilion Range chipset.
590
584config MTD_PLATRAM 591config MTD_PLATRAM
585 tristate "Map driver for platform device RAM (mtd-ram)" 592 tristate "Map driver for platform device RAM (mtd-ram)"
586 select MTD_RAM 593 select MTD_RAM
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 1313eee61afc..316382a1401b 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
68obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o 68obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
69obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o 69obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
70obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o 70obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o
71obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c
new file mode 100644
index 000000000000..1e7814ae212a
--- /dev/null
+++ b/drivers/mtd/maps/intel_vr_nor.c
@@ -0,0 +1,298 @@
1/*
2 * drivers/mtd/maps/intel_vr_nor.c
3 *
4 * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel
5 * Vermilion Range chipset.
6 *
7 * The Vermilion Range Expansion Bus supports four chip selects, each of which
8 * has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device
9 * is a 256MiB memory region containing the address spaces for all four of the
10 * chip selects, with start addresses hardcoded on 64MiB boundaries.
11 *
12 * This map driver only supports NOR flash on chip select 0. The buswidth
13 * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing
14 * and Control Register for Chip Select 0 (EXP_TIMING_CS0). This driver does
15 * not modify the value in the EXP_TIMING_CS0 register except to enable writing
16 * and disable boot acceleration. The timing parameters in the register are
17 * assumed to have been properly initialized by the BIOS. The reset default
18 * timing parameters are maximally conservative (slow), so access to the flash
19 * will be slower than it should be if the BIOS has not initialized the timing
20 * parameters.
21 *
22 * Author: Andy Lowe <alowe@mvista.com>
23 *
24 * 2006 (c) MontaVista Software, Inc. This file is licensed under
25 * the terms of the GNU General Public License version 2. This program
26 * is licensed "as is" without any warranty of any kind, whether express
27 * or implied.
28 */
29
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/pci.h>
33#include <linux/init.h>
34#include <linux/mtd/mtd.h>
35#include <linux/mtd/map.h>
36#include <linux/mtd/partitions.h>
37#include <linux/mtd/cfi.h>
38#include <linux/mtd/flashchip.h>
39
40#define DRV_NAME "vr_nor"
41
42struct vr_nor_mtd {
43 void __iomem *csr_base;
44 struct map_info map;
45 struct mtd_info *info;
46 int nr_parts;
47 struct pci_dev *dev;
48};
49
50/* Expansion Bus Configuration and Status Registers are in BAR 0 */
51#define EXP_CSR_MBAR 0
52/* Expansion Bus Memory Window is BAR 1 */
53#define EXP_WIN_MBAR 1
54/* Maximum address space for Chip Select 0 is 64MiB */
55#define CS0_SIZE 0x04000000
56/* Chip Select 0 is at offset 0 in the Memory Window */
57#define CS0_START 0x0
58/* Chip Select 0 Timing Register is at offset 0 in CSR */
59#define EXP_TIMING_CS0 0x00
60#define TIMING_CS_EN (1 << 31) /* Chip Select Enable */
61#define TIMING_BOOT_ACCEL_DIS (1 << 8) /* Boot Acceleration Disable */
62#define TIMING_WR_EN (1 << 1) /* Write Enable */
63#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */
64#define TIMING_MASK 0x3FFF0000
65
66static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
67{
68 if (p->nr_parts > 0) {
69#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
70 del_mtd_partitions(p->info);
71#endif
72 } else
73 del_mtd_device(p->info);
74}
75
76static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
77{
78 int err = 0;
79#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
80 struct mtd_partition *parts;
81 static const char *part_probes[] = { "cmdlinepart", NULL };
82#endif
83
84 /* register the flash bank */
85#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
86 /* partition the flash bank */
87 p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0);
88 if (p->nr_parts > 0)
89 err = add_mtd_partitions(p->info, parts, p->nr_parts);
90#endif
91 if (p->nr_parts <= 0)
92 err = add_mtd_device(p->info);
93
94 return err;
95}
96
97static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
98{
99 map_destroy(p->info);
100}
101
102static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
103{
104 static const char *probe_types[] =
105 { "cfi_probe", "jedec_probe", NULL };
106 const char **type;
107
108 for (type = probe_types; !p->info && *type; type++)
109 p->info = do_map_probe(*type, &p->map);
110 if (!p->info)
111 return -ENODEV;
112
113 p->info->owner = THIS_MODULE;
114
115 return 0;
116}
117
118static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
119{
120 unsigned int exp_timing_cs0;
121
122 /* write-protect the flash bank */
123 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
124 exp_timing_cs0 &= ~TIMING_WR_EN;
125 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
126
127 /* unmap the flash window */
128 iounmap(p->map.virt);
129
130 /* unmap the csr window */
131 iounmap(p->csr_base);
132}
133
134/*
135 * Initialize the map_info structure and map the flash.
136 * Returns 0 on success, nonzero otherwise.
137 */
138static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
139{
140 unsigned long csr_phys, csr_len;
141 unsigned long win_phys, win_len;
142 unsigned int exp_timing_cs0;
143 int err;
144
145 csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR);
146 csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR);
147 win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR);
148 win_len = pci_resource_len(p->dev, EXP_WIN_MBAR);
149
150 if (!csr_phys || !csr_len || !win_phys || !win_len)
151 return -ENODEV;
152
153 if (win_len < (CS0_START + CS0_SIZE))
154 return -ENXIO;
155
156 p->csr_base = ioremap_nocache(csr_phys, csr_len);
157 if (!p->csr_base)
158 return -ENOMEM;
159
160 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
161 if (!(exp_timing_cs0 & TIMING_CS_EN)) {
162 dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
163 "is disabled.\n");
164 err = -ENODEV;
165 goto release;
166 }
167 if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) {
168 dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
169 "is configured for maximally slow access times.\n");
170 }
171 p->map.name = DRV_NAME;
172 p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2;
173 p->map.phys = win_phys + CS0_START;
174 p->map.size = CS0_SIZE;
175 p->map.virt = ioremap_nocache(p->map.phys, p->map.size);
176 if (!p->map.virt) {
177 err = -ENOMEM;
178 goto release;
179 }
180 simple_map_init(&p->map);
181
182 /* Enable writes to flash bank */
183 exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN;
184 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
185
186 return 0;
187
188 release:
189 iounmap(p->csr_base);
190 return err;
191}
192
193static struct pci_device_id vr_nor_pci_ids[] = {
194 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)},
195 {0,}
196};
197
198static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
199{
200 struct vr_nor_mtd *p = pci_get_drvdata(dev);
201
202 pci_set_drvdata(dev, NULL);
203 vr_nor_destroy_partitions(p);
204 vr_nor_destroy_mtd_setup(p);
205 vr_nor_destroy_maps(p);
206 kfree(p);
207 pci_release_regions(dev);
208 pci_disable_device(dev);
209}
210
211static int __devinit
212vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
213{
214 struct vr_nor_mtd *p = NULL;
215 unsigned int exp_timing_cs0;
216 int err;
217
218 err = pci_enable_device(dev);
219 if (err)
220 goto out;
221
222 err = pci_request_regions(dev, DRV_NAME);
223 if (err)
224 goto disable_dev;
225
226 p = kzalloc(sizeof(*p), GFP_KERNEL);
227 err = -ENOMEM;
228 if (!p)
229 goto release;
230
231 p->dev = dev;
232
233 err = vr_nor_init_maps(p);
234 if (err)
235 goto release;
236
237 err = vr_nor_mtd_setup(p);
238 if (err)
239 goto destroy_maps;
240
241 err = vr_nor_init_partitions(p);
242 if (err)
243 goto destroy_mtd_setup;
244
245 pci_set_drvdata(dev, p);
246
247 return 0;
248
249 destroy_mtd_setup:
250 map_destroy(p->info);
251
252 destroy_maps:
253 /* write-protect the flash bank */
254 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
255 exp_timing_cs0 &= ~TIMING_WR_EN;
256 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
257
258 /* unmap the flash window */
259 iounmap(p->map.virt);
260
261 /* unmap the csr window */
262 iounmap(p->csr_base);
263
264 release:
265 kfree(p);
266 pci_release_regions(dev);
267
268 disable_dev:
269 pci_disable_device(dev);
270
271 out:
272 return err;
273}
274
275static struct pci_driver vr_nor_pci_driver = {
276 .name = DRV_NAME,
277 .probe = vr_nor_pci_probe,
278 .remove = __devexit_p(vr_nor_pci_remove),
279 .id_table = vr_nor_pci_ids,
280};
281
282static int __init vr_nor_mtd_init(void)
283{
284 return pci_register_driver(&vr_nor_pci_driver);
285}
286
287static void __exit vr_nor_mtd_exit(void)
288{
289 pci_unregister_driver(&vr_nor_pci_driver);
290}
291
292module_init(vr_nor_mtd_init);
293module_exit(vr_nor_mtd_exit);
294
295MODULE_AUTHOR("Andy Lowe");
296MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
297MODULE_LICENSE("GPL");
298MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids);