blob: 54a3102ab19a8868cbd18c2d1ce5cf9c92111ea6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/****************************************************************************/
2
3/*
4 * nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards.
5 *
6 * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
7 * (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
8 *
Luiz Capitulinoe2602b32005-11-29 14:30:03 +00009 * $Id: nettel.c,v 1.12 2005/11/29 14:30:00 gleixner Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11
12/****************************************************************************/
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/mtd/mtd.h>
19#include <linux/mtd/map.h>
20#include <linux/mtd/partitions.h>
21#include <linux/mtd/cfi.h>
22#include <linux/reboot.h>
23#include <asm/io.h>
24
25/****************************************************************************/
26
27#define INTEL_BUSWIDTH 1
28#define AMD_WINDOW_MAXSIZE 0x00200000
29#define AMD_BUSWIDTH 1
30
31/*
32 * PAR masks and shifts, assuming 64K pages.
33 */
34#define SC520_PAR_ADDR_MASK 0x00003fff
35#define SC520_PAR_ADDR_SHIFT 16
36#define SC520_PAR_TO_ADDR(par) \
37 (((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT)
38
39#define SC520_PAR_SIZE_MASK 0x01ffc000
40#define SC520_PAR_SIZE_SHIFT 2
41#define SC520_PAR_TO_SIZE(par) \
42 ((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024))
43
44#define SC520_PAR(cs, addr, size) \
45 ((cs) | \
46 ((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \
47 (((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK))
48
49#define SC520_PAR_BOOTCS 0x8a000000
50#define SC520_PAR_ROMCS1 0xaa000000
51#define SC520_PAR_ROMCS2 0xca000000 /* Cache disabled, 64K page */
52
53static void *nettel_mmcrp = NULL;
54
55#ifdef CONFIG_MTD_CFI_INTELEXT
56static struct mtd_info *intel_mtd;
57#endif
58static struct mtd_info *amd_mtd;
59
60/****************************************************************************/
61
62/****************************************************************************/
63
64#ifdef CONFIG_MTD_CFI_INTELEXT
65static struct map_info nettel_intel_map = {
66 .name = "SnapGear Intel",
67 .size = 0,
68 .bankwidth = INTEL_BUSWIDTH,
69};
70
71static struct mtd_partition nettel_intel_partitions[] = {
72 {
73 .name = "SnapGear kernel",
74 .offset = 0,
75 .size = 0x000e0000
76 },
77 {
78 .name = "SnapGear filesystem",
79 .offset = 0x00100000,
80 },
81 {
82 .name = "SnapGear config",
83 .offset = 0x000e0000,
84 .size = 0x00020000
85 },
86 {
87 .name = "SnapGear Intel",
88 .offset = 0
89 },
90 {
91 .name = "SnapGear BIOS Config",
92 .offset = 0x007e0000,
93 .size = 0x00020000
94 },
95 {
96 .name = "SnapGear BIOS",
97 .offset = 0x007e0000,
98 .size = 0x00020000
99 },
100};
101#endif
102
103static struct map_info nettel_amd_map = {
104 .name = "SnapGear AMD",
105 .size = AMD_WINDOW_MAXSIZE,
106 .bankwidth = AMD_BUSWIDTH,
107};
108
109static struct mtd_partition nettel_amd_partitions[] = {
110 {
111 .name = "SnapGear BIOS config",
112 .offset = 0x000e0000,
113 .size = 0x00010000
114 },
115 {
116 .name = "SnapGear BIOS",
117 .offset = 0x000f0000,
118 .size = 0x00010000
119 },
120 {
121 .name = "SnapGear AMD",
122 .offset = 0
123 },
124 {
125 .name = "SnapGear high BIOS",
126 .offset = 0x001f0000,
127 .size = 0x00010000
128 }
129};
130
Tobias Klauser87d10f32006-03-31 02:29:45 -0800131#define NUM_AMD_PARTITIONS ARRAY_SIZE(nettel_amd_partitions)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133/****************************************************************************/
134
135#ifdef CONFIG_MTD_CFI_INTELEXT
136
137/*
138 * Set the Intel flash back to read mode since some old boot
139 * loaders don't.
140 */
141static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
142{
143 struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
144 unsigned long b;
Thomas Gleixner69f34c92005-11-07 11:15:40 +0000145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 /* Make sure all FLASH chips are put back into read mode */
147 for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
148 cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
149 cfi->device_type, NULL);
150 }
151 return(NOTIFY_OK);
152}
153
154static struct notifier_block nettel_notifier_block = {
155 nettel_reboot_notifier, NULL, 0
156};
157
158/*
159 * Erase the configuration file system.
160 * Used to support the software reset button.
161 */
162static void nettel_erasecallback(struct erase_info *done)
163{
164 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
165 wake_up(wait_q);
166}
167
168static struct erase_info nettel_erase;
169
170int nettel_eraseconfig(void)
171{
172 struct mtd_info *mtd;
173 DECLARE_WAITQUEUE(wait, current);
174 wait_queue_head_t wait_q;
175 int ret;
176
177 init_waitqueue_head(&wait_q);
178 mtd = get_mtd_device(NULL, 2);
179 if (mtd) {
180 nettel_erase.mtd = mtd;
181 nettel_erase.callback = nettel_erasecallback;
182 nettel_erase.callback = NULL;
183 nettel_erase.addr = 0;
184 nettel_erase.len = mtd->size;
185 nettel_erase.priv = (u_long) &wait_q;
186 nettel_erase.priv = 0;
187
188 set_current_state(TASK_INTERRUPTIBLE);
189 add_wait_queue(&wait_q, &wait);
190
191 ret = MTD_ERASE(mtd, &nettel_erase);
192 if (ret) {
193 set_current_state(TASK_RUNNING);
194 remove_wait_queue(&wait_q, &wait);
195 put_mtd_device(mtd);
196 return(ret);
197 }
198
199 schedule(); /* Wait for erase to finish. */
200 remove_wait_queue(&wait_q, &wait);
Thomas Gleixner69f34c92005-11-07 11:15:40 +0000201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 put_mtd_device(mtd);
203 }
204
205 return(0);
206}
207
208#else
209
210int nettel_eraseconfig(void)
211{
212 return(0);
213}
214
215#endif
216
217/****************************************************************************/
218
219int __init nettel_init(void)
220{
221 volatile unsigned long *amdpar;
222 unsigned long amdaddr, maxsize;
223 int num_amd_partitions=0;
224#ifdef CONFIG_MTD_CFI_INTELEXT
225 volatile unsigned long *intel0par, *intel1par;
226 unsigned long orig_bootcspar, orig_romcs1par;
227 unsigned long intel0addr, intel0size;
228 unsigned long intel1addr, intel1size;
229 int intelboot, intel0cs, intel1cs;
230 int num_intel_partitions;
231#endif
232 int rc = 0;
233
234 nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096);
235 if (nettel_mmcrp == NULL) {
236 printk("SNAPGEAR: failed to disable MMCR cache??\n");
237 return(-EIO);
238 }
239
240 /* Set CPU clock to be 33.000MHz */
241 *((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01;
242
243 amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4);
244
245#ifdef CONFIG_MTD_CFI_INTELEXT
246 intelboot = 0;
247 intel0cs = SC520_PAR_ROMCS1;
248 intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0);
249 intel1cs = SC520_PAR_ROMCS2;
250 intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc);
251
252 /*
253 * Save the CS settings then ensure ROMCS1 and ROMCS2 are off,
254 * otherwise they might clash with where we try to map BOOTCS.
255 */
256 orig_bootcspar = *amdpar;
257 orig_romcs1par = *intel0par;
258 *intel0par = 0;
259 *intel1par = 0;
260#endif
261
262 /*
263 * The first thing to do is determine if we have a separate
264 * boot FLASH device. Typically this is a small (1 to 2MB)
265 * AMD FLASH part. It seems that device size is about the
266 * only way to tell if this is the case...
267 */
268 amdaddr = 0x20000000;
269 maxsize = AMD_WINDOW_MAXSIZE;
270
271 *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
272 __asm__ ("wbinvd");
273
274 nettel_amd_map.phys = amdaddr;
275 nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
276 if (!nettel_amd_map.virt) {
277 printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
278 return(-EIO);
279 }
280 simple_map_init(&nettel_amd_map);
281
282 if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
283 printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
284 amd_mtd->size>>10);
285
286 amd_mtd->owner = THIS_MODULE;
287
288 /* The high BIOS partition is only present for 2MB units */
289 num_amd_partitions = NUM_AMD_PARTITIONS;
290 if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
291 num_amd_partitions--;
292 /* Don't add the partition until after the primary INTEL's */
293
294#ifdef CONFIG_MTD_CFI_INTELEXT
295 /*
296 * Map the Intel flash into memory after the AMD
297 * It has to start on a multiple of maxsize.
298 */
299 maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
300 if (maxsize < (32 * 1024 * 1024))
301 maxsize = (32 * 1024 * 1024);
302 intel0addr = amdaddr + maxsize;
303#endif
304 } else {
305#ifdef CONFIG_MTD_CFI_INTELEXT
306 /* INTEL boot FLASH */
307 intelboot++;
308
309 if (!orig_romcs1par) {
310 intel0cs = SC520_PAR_BOOTCS;
311 intel0par = (volatile unsigned long *)
312 (nettel_mmcrp + 0xc4);
313 intel1cs = SC520_PAR_ROMCS1;
314 intel1par = (volatile unsigned long *)
315 (nettel_mmcrp + 0xc0);
316
317 intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
318 maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
319 } else {
320 /* Kernel base is on ROMCS1, not BOOTCS */
321 intel0cs = SC520_PAR_ROMCS1;
322 intel0par = (volatile unsigned long *)
323 (nettel_mmcrp + 0xc0);
324 intel1cs = SC520_PAR_BOOTCS;
325 intel1par = (volatile unsigned long *)
326 (nettel_mmcrp + 0xc4);
327
328 intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
329 maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
330 }
331
332 /* Destroy useless AMD MTD mapping */
333 amd_mtd = NULL;
334 iounmap(nettel_amd_map.virt);
335 nettel_amd_map.virt = NULL;
336#else
337 /* Only AMD flash supported */
338 return(-ENXIO);
339#endif
340 }
341
342#ifdef CONFIG_MTD_CFI_INTELEXT
343 /*
344 * We have determined the INTEL FLASH configuration, so lets
345 * go ahead and probe for them now.
346 */
347
348 /* Set PAR to the maximum size */
349 if (maxsize < (32 * 1024 * 1024))
350 maxsize = (32 * 1024 * 1024);
351 *intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
352
353 /* Turn other PAR off so the first probe doesn't find it */
354 *intel1par = 0;
355
356 /* Probe for the the size of the first Intel flash */
357 nettel_intel_map.size = maxsize;
358 nettel_intel_map.phys = intel0addr;
359 nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
360 if (!nettel_intel_map.virt) {
361 printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
362 return(-EIO);
363 }
364 simple_map_init(&nettel_intel_map);
365
366 intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
367 if (!intel_mtd) {
368 iounmap(nettel_intel_map.virt);
369 return(-ENXIO);
370 }
371
372 /* Set PAR to the detected size */
373 intel0size = intel_mtd->size;
374 *intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
375
376 /*
377 * Map second Intel FLASH right after first. Set its size to the
378 * same maxsize used for the first Intel FLASH.
379 */
380 intel1addr = intel0addr + intel0size;
381 *intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
382 __asm__ ("wbinvd");
383
384 maxsize += intel0size;
385
386 /* Delete the old map and probe again to do both chips */
387 map_destroy(intel_mtd);
388 intel_mtd = NULL;
389 iounmap(nettel_intel_map.virt);
390
391 nettel_intel_map.size = maxsize;
392 nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
393 if (!nettel_intel_map.virt) {
394 printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
395 return(-EIO);
396 }
397
398 intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
399 if (! intel_mtd) {
400 iounmap((void *) nettel_intel_map.virt);
401 return(-ENXIO);
402 }
403
404 intel1size = intel_mtd->size - intel0size;
405 if (intel1size > 0) {
406 *intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
407 __asm__ ("wbinvd");
408 } else {
409 *intel1par = 0;
410 }
411
412 printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
413 (intel_mtd->size >> 10));
414
415 intel_mtd->owner = THIS_MODULE;
416
417#ifndef CONFIG_BLK_DEV_INITRD
418 ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
419#endif
420
421 num_intel_partitions = sizeof(nettel_intel_partitions) /
422 sizeof(nettel_intel_partitions[0]);
423
424 if (intelboot) {
425 /*
426 * Adjust offset and size of last boot partition.
427 * Must allow for BIOS region at end of FLASH.
428 */
429 nettel_intel_partitions[1].size = (intel0size + intel1size) -
430 (1024*1024 + intel_mtd->erasesize);
431 nettel_intel_partitions[3].size = intel0size + intel1size;
Thomas Gleixner69f34c92005-11-07 11:15:40 +0000432 nettel_intel_partitions[4].offset =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 (intel0size + intel1size) - intel_mtd->erasesize;
434 nettel_intel_partitions[4].size = intel_mtd->erasesize;
435 nettel_intel_partitions[5].offset =
436 nettel_intel_partitions[4].offset;
437 nettel_intel_partitions[5].size =
438 nettel_intel_partitions[4].size;
439 } else {
440 /* No BIOS regions when AMD boot */
441 num_intel_partitions -= 2;
442 }
443 rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
444 num_intel_partitions);
445#endif
446
447 if (amd_mtd) {
448 rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
449 num_amd_partitions);
450 }
451
452#ifdef CONFIG_MTD_CFI_INTELEXT
453 register_reboot_notifier(&nettel_notifier_block);
454#endif
455
456 return(rc);
457}
458
459/****************************************************************************/
460
461void __exit nettel_cleanup(void)
462{
463#ifdef CONFIG_MTD_CFI_INTELEXT
464 unregister_reboot_notifier(&nettel_notifier_block);
465#endif
466 if (amd_mtd) {
467 del_mtd_partitions(amd_mtd);
468 map_destroy(amd_mtd);
469 }
470 if (nettel_amd_map.virt) {
471 iounmap(nettel_amd_map.virt);
472 nettel_amd_map.virt = NULL;
473 }
474#ifdef CONFIG_MTD_CFI_INTELEXT
475 if (intel_mtd) {
476 del_mtd_partitions(intel_mtd);
477 map_destroy(intel_mtd);
478 }
479 if (nettel_intel_map.virt) {
480 iounmap(nettel_intel_map.virt);
Luiz Capitulinoe2602b32005-11-29 14:30:03 +0000481 nettel_intel_map.virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 }
483#endif
484}
485
486/****************************************************************************/
487
488module_init(nettel_init);
489module_exit(nettel_cleanup);
490
491MODULE_LICENSE("GPL");
492MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
493MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
494
495/****************************************************************************/