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