diff options
Diffstat (limited to 'arch/blackfin/kernel/setup.c')
-rw-r--r-- | arch/blackfin/kernel/setup.c | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c new file mode 100644 index 000000000000..342bb8dd56ac --- /dev/null +++ b/arch/blackfin/kernel/setup.c | |||
@@ -0,0 +1,902 @@ | |||
1 | /* | ||
2 | * File: arch/blackfin/kernel/setup.c | ||
3 | * Based on: | ||
4 | * Author: | ||
5 | * | ||
6 | * Created: | ||
7 | * Description: | ||
8 | * | ||
9 | * Modified: | ||
10 | * Copyright 2004-2006 Analog Devices Inc. | ||
11 | * | ||
12 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, see the file COPYING, or write | ||
26 | * to the Free Software Foundation, Inc., | ||
27 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
28 | */ | ||
29 | |||
30 | #include <linux/delay.h> | ||
31 | #include <linux/console.h> | ||
32 | #include <linux/bootmem.h> | ||
33 | #include <linux/seq_file.h> | ||
34 | #include <linux/cpu.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/console.h> | ||
37 | #include <linux/tty.h> | ||
38 | |||
39 | #include <linux/ext2_fs.h> | ||
40 | #include <linux/cramfs_fs.h> | ||
41 | #include <linux/romfs_fs.h> | ||
42 | |||
43 | #include <asm/cacheflush.h> | ||
44 | #include <asm/blackfin.h> | ||
45 | #include <asm/cplbinit.h> | ||
46 | |||
47 | unsigned long memory_start, memory_end, physical_mem_end; | ||
48 | unsigned long reserved_mem_dcache_on; | ||
49 | unsigned long reserved_mem_icache_on; | ||
50 | EXPORT_SYMBOL(memory_start); | ||
51 | EXPORT_SYMBOL(memory_end); | ||
52 | EXPORT_SYMBOL(physical_mem_end); | ||
53 | EXPORT_SYMBOL(_ramend); | ||
54 | |||
55 | #ifdef CONFIG_MTD_UCLINUX | ||
56 | unsigned long memory_mtd_end, memory_mtd_start, mtd_size; | ||
57 | unsigned long _ebss; | ||
58 | EXPORT_SYMBOL(memory_mtd_end); | ||
59 | EXPORT_SYMBOL(memory_mtd_start); | ||
60 | EXPORT_SYMBOL(mtd_size); | ||
61 | #endif | ||
62 | |||
63 | char command_line[COMMAND_LINE_SIZE]; | ||
64 | |||
65 | #if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) | ||
66 | static void generate_cpl_tables(void); | ||
67 | #endif | ||
68 | |||
69 | void __init bf53x_cache_init(void) | ||
70 | { | ||
71 | #if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) | ||
72 | generate_cpl_tables(); | ||
73 | #endif | ||
74 | |||
75 | #ifdef CONFIG_BLKFIN_CACHE | ||
76 | bfin_icache_init(); | ||
77 | printk(KERN_INFO "Instruction Cache Enabled\n"); | ||
78 | #endif | ||
79 | |||
80 | #ifdef CONFIG_BLKFIN_DCACHE | ||
81 | bfin_dcache_init(); | ||
82 | printk(KERN_INFO "Data Cache Enabled" | ||
83 | # if defined CONFIG_BLKFIN_WB | ||
84 | " (write-back)" | ||
85 | # elif defined CONFIG_BLKFIN_WT | ||
86 | " (write-through)" | ||
87 | # endif | ||
88 | "\n"); | ||
89 | #endif | ||
90 | } | ||
91 | |||
92 | void bf53x_relocate_l1_mem(void) | ||
93 | { | ||
94 | unsigned long l1_code_length; | ||
95 | unsigned long l1_data_a_length; | ||
96 | unsigned long l1_data_b_length; | ||
97 | |||
98 | l1_code_length = _etext_l1 - _stext_l1; | ||
99 | if (l1_code_length > L1_CODE_LENGTH) | ||
100 | l1_code_length = L1_CODE_LENGTH; | ||
101 | /* cannot complain as printk is not available as yet. | ||
102 | * But we can continue booting and complain later! | ||
103 | */ | ||
104 | |||
105 | /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */ | ||
106 | dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length); | ||
107 | |||
108 | l1_data_a_length = _ebss_l1 - _sdata_l1; | ||
109 | if (l1_data_a_length > L1_DATA_A_LENGTH) | ||
110 | l1_data_a_length = L1_DATA_A_LENGTH; | ||
111 | |||
112 | /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */ | ||
113 | dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length); | ||
114 | |||
115 | l1_data_b_length = _ebss_b_l1 - _sdata_b_l1; | ||
116 | if (l1_data_b_length > L1_DATA_B_LENGTH) | ||
117 | l1_data_b_length = L1_DATA_B_LENGTH; | ||
118 | |||
119 | /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */ | ||
120 | dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length + | ||
121 | l1_data_a_length, l1_data_b_length); | ||
122 | |||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Initial parsing of the command line. Currently, we support: | ||
127 | * - Controlling the linux memory size: mem=xxx[KMG] | ||
128 | * - Controlling the physical memory size: max_mem=xxx[KMG][$][#] | ||
129 | * $ -> reserved memory is dcacheable | ||
130 | * # -> reserved memory is icacheable | ||
131 | */ | ||
132 | static __init void parse_cmdline_early(char *cmdline_p) | ||
133 | { | ||
134 | char c = ' ', *to = cmdline_p; | ||
135 | unsigned int memsize; | ||
136 | for (;;) { | ||
137 | if (c == ' ') { | ||
138 | |||
139 | if (!memcmp(to, "mem=", 4)) { | ||
140 | to += 4; | ||
141 | memsize = memparse(to, &to); | ||
142 | if (memsize) | ||
143 | _ramend = memsize; | ||
144 | |||
145 | } else if (!memcmp(to, "max_mem=", 8)) { | ||
146 | to += 8; | ||
147 | memsize = memparse(to, &to); | ||
148 | if (memsize) { | ||
149 | physical_mem_end = memsize; | ||
150 | if (*to != ' ') { | ||
151 | if (*to == '$' | ||
152 | || *(to + 1) == '$') | ||
153 | reserved_mem_dcache_on = | ||
154 | 1; | ||
155 | if (*to == '#' | ||
156 | || *(to + 1) == '#') | ||
157 | reserved_mem_icache_on = | ||
158 | 1; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | } | ||
164 | c = *(to++); | ||
165 | if (!c) | ||
166 | break; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void __init setup_arch(char **cmdline_p) | ||
171 | { | ||
172 | int bootmap_size; | ||
173 | unsigned long l1_length, sclk, cclk; | ||
174 | #ifdef CONFIG_MTD_UCLINUX | ||
175 | unsigned long mtd_phys = 0; | ||
176 | #endif | ||
177 | |||
178 | cclk = get_cclk(); | ||
179 | sclk = get_sclk(); | ||
180 | |||
181 | #if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273) | ||
182 | if (cclk == sclk) | ||
183 | panic("ANOMALY 05000273, SCLK can not be same as CCLK"); | ||
184 | #endif | ||
185 | |||
186 | #if defined(ANOMALY_05000266) | ||
187 | bfin_read_IMDMA_D0_IRQ_STATUS(); | ||
188 | bfin_read_IMDMA_D1_IRQ_STATUS(); | ||
189 | #endif | ||
190 | |||
191 | #ifdef DEBUG_SERIAL_EARLY_INIT | ||
192 | bfin_console_init(); /* early console registration */ | ||
193 | /* this give a chance to get printk() working before crash. */ | ||
194 | #endif | ||
195 | |||
196 | #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) | ||
197 | /* we need to initialize the Flashrom device here since we might | ||
198 | * do things with flash early on in the boot | ||
199 | */ | ||
200 | flash_probe(); | ||
201 | #endif | ||
202 | |||
203 | #if defined(CONFIG_CMDLINE_BOOL) | ||
204 | memset(command_line, 0, sizeof(command_line)); | ||
205 | strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); | ||
206 | command_line[sizeof(command_line) - 1] = 0; | ||
207 | #endif | ||
208 | |||
209 | /* Keep a copy of command line */ | ||
210 | *cmdline_p = &command_line[0]; | ||
211 | memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); | ||
212 | boot_command_line[COMMAND_LINE_SIZE - 1] = 0; | ||
213 | |||
214 | /* setup memory defaults from the user config */ | ||
215 | physical_mem_end = 0; | ||
216 | _ramend = CONFIG_MEM_SIZE * 1024 * 1024; | ||
217 | |||
218 | parse_cmdline_early(&command_line[0]); | ||
219 | |||
220 | if (physical_mem_end == 0) | ||
221 | physical_mem_end = _ramend; | ||
222 | |||
223 | /* by now the stack is part of the init task */ | ||
224 | memory_end = _ramend - DMA_UNCACHED_REGION; | ||
225 | |||
226 | _ramstart = (unsigned long)__bss_stop; | ||
227 | memory_start = PAGE_ALIGN(_ramstart); | ||
228 | |||
229 | #if defined(CONFIG_MTD_UCLINUX) | ||
230 | /* generic memory mapped MTD driver */ | ||
231 | memory_mtd_end = memory_end; | ||
232 | |||
233 | mtd_phys = _ramstart; | ||
234 | mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8))); | ||
235 | |||
236 | # if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS) | ||
237 | if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC) | ||
238 | mtd_size = | ||
239 | PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10); | ||
240 | # endif | ||
241 | |||
242 | # if defined(CONFIG_CRAMFS) | ||
243 | if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC) | ||
244 | mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4))); | ||
245 | # endif | ||
246 | |||
247 | # if defined(CONFIG_ROMFS_FS) | ||
248 | if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0 | ||
249 | && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) | ||
250 | mtd_size = | ||
251 | PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); | ||
252 | # if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) | ||
253 | /* Due to a Hardware Anomaly we need to limit the size of usable | ||
254 | * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on | ||
255 | * 05000263 - Hardware loop corrupted when taking an ICPLB exception | ||
256 | */ | ||
257 | # if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) | ||
258 | if (memory_end >= 56 * 1024 * 1024) | ||
259 | memory_end = 56 * 1024 * 1024; | ||
260 | # else | ||
261 | if (memory_end >= 60 * 1024 * 1024) | ||
262 | memory_end = 60 * 1024 * 1024; | ||
263 | # endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */ | ||
264 | # endif /* ANOMALY_05000263 */ | ||
265 | # endif /* CONFIG_ROMFS_FS */ | ||
266 | |||
267 | memory_end -= mtd_size; | ||
268 | |||
269 | if (mtd_size == 0) { | ||
270 | console_init(); | ||
271 | panic("Don't boot kernel without rootfs attached.\n"); | ||
272 | } | ||
273 | |||
274 | /* Relocate MTD image to the top of memory after the uncached memory area */ | ||
275 | dma_memcpy((char *)memory_end, __bss_stop, mtd_size); | ||
276 | |||
277 | memory_mtd_start = memory_end; | ||
278 | _ebss = memory_mtd_start; /* define _ebss for compatible */ | ||
279 | #endif /* CONFIG_MTD_UCLINUX */ | ||
280 | |||
281 | #if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) | ||
282 | /* Due to a Hardware Anomaly we need to limit the size of usable | ||
283 | * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on | ||
284 | * 05000263 - Hardware loop corrupted when taking an ICPLB exception | ||
285 | */ | ||
286 | #if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) | ||
287 | if (memory_end >= 56 * 1024 * 1024) | ||
288 | memory_end = 56 * 1024 * 1024; | ||
289 | #else | ||
290 | if (memory_end >= 60 * 1024 * 1024) | ||
291 | memory_end = 60 * 1024 * 1024; | ||
292 | #endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */ | ||
293 | printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20); | ||
294 | #endif /* ANOMALY_05000263 */ | ||
295 | |||
296 | #if !defined(CONFIG_MTD_UCLINUX) | ||
297 | memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/ | ||
298 | #endif | ||
299 | init_mm.start_code = (unsigned long)_stext; | ||
300 | init_mm.end_code = (unsigned long)_etext; | ||
301 | init_mm.end_data = (unsigned long)_edata; | ||
302 | init_mm.brk = (unsigned long)0; | ||
303 | |||
304 | init_leds(); | ||
305 | |||
306 | printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n"); | ||
307 | printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid()); | ||
308 | if (bfin_revid() != bfin_compiled_revid()) | ||
309 | printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", | ||
310 | bfin_compiled_revid(), bfin_revid()); | ||
311 | if (bfin_revid() < SUPPORTED_REVID) | ||
312 | printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", | ||
313 | CPU, bfin_revid()); | ||
314 | printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); | ||
315 | |||
316 | printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n", | ||
317 | cclk / 1000000, sclk / 1000000); | ||
318 | |||
319 | #if defined(ANOMALY_05000273) | ||
320 | if ((cclk >> 1) <= sclk) | ||
321 | printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n"); | ||
322 | #endif | ||
323 | |||
324 | printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); | ||
325 | printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); | ||
326 | |||
327 | printk(KERN_INFO "Memory map:\n" | ||
328 | KERN_INFO " text = 0x%p-0x%p\n" | ||
329 | KERN_INFO " init = 0x%p-0x%p\n" | ||
330 | KERN_INFO " data = 0x%p-0x%p\n" | ||
331 | KERN_INFO " stack = 0x%p-0x%p\n" | ||
332 | KERN_INFO " bss = 0x%p-0x%p\n" | ||
333 | KERN_INFO " available = 0x%p-0x%p\n" | ||
334 | #ifdef CONFIG_MTD_UCLINUX | ||
335 | KERN_INFO " rootfs = 0x%p-0x%p\n" | ||
336 | #endif | ||
337 | #if DMA_UNCACHED_REGION > 0 | ||
338 | KERN_INFO " DMA Zone = 0x%p-0x%p\n" | ||
339 | #endif | ||
340 | , _stext, _etext, | ||
341 | __init_begin, __init_end, | ||
342 | _sdata, _edata, | ||
343 | (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000), | ||
344 | __bss_start, __bss_stop, | ||
345 | (void*)_ramstart, (void*)memory_end | ||
346 | #ifdef CONFIG_MTD_UCLINUX | ||
347 | , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size) | ||
348 | #endif | ||
349 | #if DMA_UNCACHED_REGION > 0 | ||
350 | , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend) | ||
351 | #endif | ||
352 | ); | ||
353 | |||
354 | /* | ||
355 | * give all the memory to the bootmap allocator, tell it to put the | ||
356 | * boot mem_map at the start of memory | ||
357 | */ | ||
358 | bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */ | ||
359 | PAGE_OFFSET >> PAGE_SHIFT, | ||
360 | memory_end >> PAGE_SHIFT); | ||
361 | /* | ||
362 | * free the usable memory, we have to make sure we do not free | ||
363 | * the bootmem bitmap so we then reserve it after freeing it :-) | ||
364 | */ | ||
365 | free_bootmem(memory_start, memory_end - memory_start); | ||
366 | |||
367 | reserve_bootmem(memory_start, bootmap_size); | ||
368 | /* | ||
369 | * get kmalloc into gear | ||
370 | */ | ||
371 | paging_init(); | ||
372 | |||
373 | /* check the size of the l1 area */ | ||
374 | l1_length = _etext_l1 - _stext_l1; | ||
375 | if (l1_length > L1_CODE_LENGTH) | ||
376 | panic("L1 memory overflow\n"); | ||
377 | |||
378 | l1_length = _ebss_l1 - _sdata_l1; | ||
379 | if (l1_length > L1_DATA_A_LENGTH) | ||
380 | panic("L1 memory overflow\n"); | ||
381 | |||
382 | bf53x_cache_init(); | ||
383 | |||
384 | #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) | ||
385 | # if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP) | ||
386 | /* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */ | ||
387 | bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN)); | ||
388 | bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN); | ||
389 | SSYNC(); | ||
390 | # endif | ||
391 | # if defined (CONFIG_BFIN561_EZKIT) | ||
392 | bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12)); | ||
393 | SSYNC(); | ||
394 | # endif /* defined (CONFIG_BFIN561_EZKIT) */ | ||
395 | #endif | ||
396 | |||
397 | printk(KERN_INFO "Hardware Trace Enabled\n"); | ||
398 | bfin_write_TBUFCTL(0x03); | ||
399 | } | ||
400 | |||
401 | #if defined(CONFIG_BF561) | ||
402 | static struct cpu cpu[2]; | ||
403 | #else | ||
404 | static struct cpu cpu[1]; | ||
405 | #endif | ||
406 | static int __init topology_init(void) | ||
407 | { | ||
408 | #if defined (CONFIG_BF561) | ||
409 | register_cpu(&cpu[0], 0); | ||
410 | register_cpu(&cpu[1], 1); | ||
411 | return 0; | ||
412 | #else | ||
413 | return register_cpu(cpu, 0); | ||
414 | #endif | ||
415 | } | ||
416 | |||
417 | subsys_initcall(topology_init); | ||
418 | |||
419 | #if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) | ||
420 | u16 lock_kernel_check(u32 start, u32 end) | ||
421 | { | ||
422 | if ((start <= (u32) _stext && end >= (u32) _end) | ||
423 | || (start >= (u32) _stext && end <= (u32) _end)) | ||
424 | return IN_KERNEL; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static unsigned short __init | ||
429 | fill_cplbtab(struct cplb_tab *table, | ||
430 | unsigned long start, unsigned long end, | ||
431 | unsigned long block_size, unsigned long cplb_data) | ||
432 | { | ||
433 | int i; | ||
434 | |||
435 | switch (block_size) { | ||
436 | case SIZE_4M: | ||
437 | i = 3; | ||
438 | break; | ||
439 | case SIZE_1M: | ||
440 | i = 2; | ||
441 | break; | ||
442 | case SIZE_4K: | ||
443 | i = 1; | ||
444 | break; | ||
445 | case SIZE_1K: | ||
446 | default: | ||
447 | i = 0; | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | cplb_data = (cplb_data & ~(3 << 16)) | (i << 16); | ||
452 | |||
453 | while ((start < end) && (table->pos < table->size)) { | ||
454 | |||
455 | table->tab[table->pos++] = start; | ||
456 | |||
457 | if (lock_kernel_check(start, start + block_size) == IN_KERNEL) | ||
458 | table->tab[table->pos++] = | ||
459 | cplb_data | CPLB_LOCK | CPLB_DIRTY; | ||
460 | else | ||
461 | table->tab[table->pos++] = cplb_data; | ||
462 | |||
463 | start += block_size; | ||
464 | } | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static unsigned short __init | ||
469 | close_cplbtab(struct cplb_tab *table) | ||
470 | { | ||
471 | |||
472 | while (table->pos < table->size) { | ||
473 | |||
474 | table->tab[table->pos++] = 0; | ||
475 | table->tab[table->pos++] = 0; /* !CPLB_VALID */ | ||
476 | } | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static void __init generate_cpl_tables(void) | ||
481 | { | ||
482 | |||
483 | u16 i, j, process; | ||
484 | u32 a_start, a_end, as, ae, as_1m; | ||
485 | |||
486 | struct cplb_tab *t_i = NULL; | ||
487 | struct cplb_tab *t_d = NULL; | ||
488 | struct s_cplb cplb; | ||
489 | |||
490 | cplb.init_i.size = MAX_CPLBS; | ||
491 | cplb.init_d.size = MAX_CPLBS; | ||
492 | cplb.switch_i.size = MAX_SWITCH_I_CPLBS; | ||
493 | cplb.switch_d.size = MAX_SWITCH_D_CPLBS; | ||
494 | |||
495 | cplb.init_i.pos = 0; | ||
496 | cplb.init_d.pos = 0; | ||
497 | cplb.switch_i.pos = 0; | ||
498 | cplb.switch_d.pos = 0; | ||
499 | |||
500 | cplb.init_i.tab = icplb_table; | ||
501 | cplb.init_d.tab = dcplb_table; | ||
502 | cplb.switch_i.tab = ipdt_table; | ||
503 | cplb.switch_d.tab = dpdt_table; | ||
504 | |||
505 | cplb_data[SDRAM_KERN].end = memory_end; | ||
506 | |||
507 | #ifdef CONFIG_MTD_UCLINUX | ||
508 | cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start; | ||
509 | cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size; | ||
510 | cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0; | ||
511 | # if defined(CONFIG_ROMFS_FS) | ||
512 | cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB; | ||
513 | |||
514 | /* | ||
515 | * The ROMFS_FS size is often not multiple of 1MB. | ||
516 | * This can cause multiple CPLB sets covering the same memory area. | ||
517 | * This will then cause multiple CPLB hit exceptions. | ||
518 | * Workaround: We ensure a contiguous memory area by extending the kernel | ||
519 | * memory section over the mtd section. | ||
520 | * For ROMFS_FS memory must be covered with ICPLBs anyways. | ||
521 | * So there is no difference between kernel and mtd memory setup. | ||
522 | */ | ||
523 | |||
524 | cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;; | ||
525 | cplb_data[SDRAM_RAM_MTD].valid = 0; | ||
526 | |||
527 | # endif | ||
528 | #else | ||
529 | cplb_data[SDRAM_RAM_MTD].valid = 0; | ||
530 | #endif | ||
531 | |||
532 | cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION; | ||
533 | cplb_data[SDRAM_DMAZ].end = _ramend; | ||
534 | |||
535 | cplb_data[RES_MEM].start = _ramend; | ||
536 | cplb_data[RES_MEM].end = physical_mem_end; | ||
537 | |||
538 | if (reserved_mem_dcache_on) | ||
539 | cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC; | ||
540 | else | ||
541 | cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL; | ||
542 | |||
543 | if (reserved_mem_icache_on) | ||
544 | cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC; | ||
545 | else | ||
546 | cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL; | ||
547 | |||
548 | for (i = ZERO_P; i <= L2_MEM; i++) { | ||
549 | |||
550 | if (cplb_data[i].valid) { | ||
551 | |||
552 | as_1m = cplb_data[i].start % SIZE_1M; | ||
553 | |||
554 | /* We need to make sure all sections are properly 1M aligned | ||
555 | * However between Kernel Memory and the Kernel mtd section, depending on the | ||
556 | * rootfs size, there can be overlapping memory areas. | ||
557 | */ | ||
558 | |||
559 | if (as_1m && i!=L1I_MEM && i!=L1D_MEM) { | ||
560 | #ifdef CONFIG_MTD_UCLINUX | ||
561 | if (i == SDRAM_RAM_MTD) { | ||
562 | if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start) | ||
563 | cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M; | ||
564 | else | ||
565 | cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)); | ||
566 | } else | ||
567 | #endif | ||
568 | printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n", | ||
569 | cplb_data[i].name, cplb_data[i].start); | ||
570 | } | ||
571 | |||
572 | as = cplb_data[i].start % SIZE_4M; | ||
573 | ae = cplb_data[i].end % SIZE_4M; | ||
574 | |||
575 | if (as) | ||
576 | a_start = cplb_data[i].start + (SIZE_4M - (as)); | ||
577 | else | ||
578 | a_start = cplb_data[i].start; | ||
579 | |||
580 | a_end = cplb_data[i].end - ae; | ||
581 | |||
582 | for (j = INITIAL_T; j <= SWITCH_T; j++) { | ||
583 | |||
584 | switch (j) { | ||
585 | case INITIAL_T: | ||
586 | if (cplb_data[i].attr & INITIAL_T) { | ||
587 | t_i = &cplb.init_i; | ||
588 | t_d = &cplb.init_d; | ||
589 | process = 1; | ||
590 | } else | ||
591 | process = 0; | ||
592 | break; | ||
593 | case SWITCH_T: | ||
594 | if (cplb_data[i].attr & SWITCH_T) { | ||
595 | t_i = &cplb.switch_i; | ||
596 | t_d = &cplb.switch_d; | ||
597 | process = 1; | ||
598 | } else | ||
599 | process = 0; | ||
600 | break; | ||
601 | default: | ||
602 | process = 0; | ||
603 | break; | ||
604 | } | ||
605 | |||
606 | if (process) { | ||
607 | if (cplb_data[i].attr & I_CPLB) { | ||
608 | |||
609 | if (cplb_data[i].psize) { | ||
610 | fill_cplbtab(t_i, | ||
611 | cplb_data[i].start, | ||
612 | cplb_data[i].end, | ||
613 | cplb_data[i].psize, | ||
614 | cplb_data[i].i_conf); | ||
615 | } else { | ||
616 | /*icplb_table */ | ||
617 | #if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) | ||
618 | if (i == SDRAM_KERN) { | ||
619 | fill_cplbtab(t_i, | ||
620 | cplb_data[i].start, | ||
621 | cplb_data[i].end, | ||
622 | SIZE_4M, | ||
623 | cplb_data[i].i_conf); | ||
624 | } else | ||
625 | #endif | ||
626 | { | ||
627 | fill_cplbtab(t_i, | ||
628 | cplb_data[i].start, | ||
629 | a_start, | ||
630 | SIZE_1M, | ||
631 | cplb_data[i].i_conf); | ||
632 | fill_cplbtab(t_i, | ||
633 | a_start, | ||
634 | a_end, | ||
635 | SIZE_4M, | ||
636 | cplb_data[i].i_conf); | ||
637 | fill_cplbtab(t_i, a_end, | ||
638 | cplb_data[i].end, | ||
639 | SIZE_1M, | ||
640 | cplb_data[i].i_conf); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | } | ||
645 | if (cplb_data[i].attr & D_CPLB) { | ||
646 | |||
647 | if (cplb_data[i].psize) { | ||
648 | fill_cplbtab(t_d, | ||
649 | cplb_data[i].start, | ||
650 | cplb_data[i].end, | ||
651 | cplb_data[i].psize, | ||
652 | cplb_data[i].d_conf); | ||
653 | } else { | ||
654 | /*dcplb_table*/ | ||
655 | fill_cplbtab(t_d, | ||
656 | cplb_data[i].start, | ||
657 | a_start, SIZE_1M, | ||
658 | cplb_data[i].d_conf); | ||
659 | fill_cplbtab(t_d, a_start, | ||
660 | a_end, SIZE_4M, | ||
661 | cplb_data[i].d_conf); | ||
662 | fill_cplbtab(t_d, a_end, | ||
663 | cplb_data[i].end, | ||
664 | SIZE_1M, | ||
665 | cplb_data[i].d_conf); | ||
666 | |||
667 | } | ||
668 | |||
669 | } | ||
670 | } | ||
671 | } | ||
672 | |||
673 | } | ||
674 | } | ||
675 | |||
676 | /* close tables */ | ||
677 | |||
678 | close_cplbtab(&cplb.init_i); | ||
679 | close_cplbtab(&cplb.init_d); | ||
680 | |||
681 | cplb.init_i.tab[cplb.init_i.pos] = -1; | ||
682 | cplb.init_d.tab[cplb.init_d.pos] = -1; | ||
683 | cplb.switch_i.tab[cplb.switch_i.pos] = -1; | ||
684 | cplb.switch_d.tab[cplb.switch_d.pos] = -1; | ||
685 | |||
686 | } | ||
687 | |||
688 | #endif | ||
689 | |||
690 | static inline u_long get_vco(void) | ||
691 | { | ||
692 | u_long msel; | ||
693 | u_long vco; | ||
694 | |||
695 | msel = (bfin_read_PLL_CTL() >> 9) & 0x3F; | ||
696 | if (0 == msel) | ||
697 | msel = 64; | ||
698 | |||
699 | vco = CONFIG_CLKIN_HZ; | ||
700 | vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */ | ||
701 | vco = msel * vco; | ||
702 | return vco; | ||
703 | } | ||
704 | |||
705 | /*Get the Core clock*/ | ||
706 | u_long get_cclk(void) | ||
707 | { | ||
708 | u_long csel, ssel; | ||
709 | if (bfin_read_PLL_STAT() & 0x1) | ||
710 | return CONFIG_CLKIN_HZ; | ||
711 | |||
712 | ssel = bfin_read_PLL_DIV(); | ||
713 | csel = ((ssel >> 4) & 0x03); | ||
714 | ssel &= 0xf; | ||
715 | if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */ | ||
716 | return get_vco() / ssel; | ||
717 | return get_vco() >> csel; | ||
718 | } | ||
719 | |||
720 | EXPORT_SYMBOL(get_cclk); | ||
721 | |||
722 | /* Get the System clock */ | ||
723 | u_long get_sclk(void) | ||
724 | { | ||
725 | u_long ssel; | ||
726 | |||
727 | if (bfin_read_PLL_STAT() & 0x1) | ||
728 | return CONFIG_CLKIN_HZ; | ||
729 | |||
730 | ssel = (bfin_read_PLL_DIV() & 0xf); | ||
731 | if (0 == ssel) { | ||
732 | printk(KERN_WARNING "Invalid System Clock\n"); | ||
733 | ssel = 1; | ||
734 | } | ||
735 | |||
736 | return get_vco() / ssel; | ||
737 | } | ||
738 | |||
739 | EXPORT_SYMBOL(get_sclk); | ||
740 | |||
741 | /* | ||
742 | * Get CPU information for use by the procfs. | ||
743 | */ | ||
744 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
745 | { | ||
746 | char *cpu, *mmu, *fpu, *name; | ||
747 | uint32_t revid; | ||
748 | |||
749 | u_long cclk = 0, sclk = 0; | ||
750 | u_int dcache_size = 0, dsup_banks = 0; | ||
751 | |||
752 | cpu = CPU; | ||
753 | mmu = "none"; | ||
754 | fpu = "none"; | ||
755 | revid = bfin_revid(); | ||
756 | name = bfin_board_name; | ||
757 | |||
758 | cclk = get_cclk(); | ||
759 | sclk = get_sclk(); | ||
760 | |||
761 | seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n" | ||
762 | "MMU:\t\t%s\n" | ||
763 | "FPU:\t\t%s\n" | ||
764 | "Core Clock:\t%9lu Hz\n" | ||
765 | "System Clock:\t%9lu Hz\n" | ||
766 | "BogoMips:\t%lu.%02lu\n" | ||
767 | "Calibration:\t%lu loops\n", | ||
768 | cpu, revid, mmu, fpu, | ||
769 | cclk, | ||
770 | sclk, | ||
771 | (loops_per_jiffy * HZ) / 500000, | ||
772 | ((loops_per_jiffy * HZ) / 5000) % 100, | ||
773 | (loops_per_jiffy * HZ)); | ||
774 | seq_printf(m, "Board Name:\t%s\n", name); | ||
775 | seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20); | ||
776 | seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20); | ||
777 | if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC)) | ||
778 | seq_printf(m, "I-CACHE:\tON\n"); | ||
779 | else | ||
780 | seq_printf(m, "I-CACHE:\tOFF\n"); | ||
781 | if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)) | ||
782 | seq_printf(m, "D-CACHE:\tON" | ||
783 | #if defined CONFIG_BLKFIN_WB | ||
784 | " (write-back)" | ||
785 | #elif defined CONFIG_BLKFIN_WT | ||
786 | " (write-through)" | ||
787 | #endif | ||
788 | "\n"); | ||
789 | else | ||
790 | seq_printf(m, "D-CACHE:\tOFF\n"); | ||
791 | |||
792 | |||
793 | switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) { | ||
794 | case ACACHE_BSRAM: | ||
795 | seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n"); | ||
796 | dcache_size = 16; | ||
797 | dsup_banks = 1; | ||
798 | break; | ||
799 | case ACACHE_BCACHE: | ||
800 | seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n"); | ||
801 | dcache_size = 32; | ||
802 | dsup_banks = 2; | ||
803 | break; | ||
804 | case ASRAM_BSRAM: | ||
805 | seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n"); | ||
806 | dcache_size = 0; | ||
807 | dsup_banks = 0; | ||
808 | break; | ||
809 | default: | ||
810 | break; | ||
811 | } | ||
812 | |||
813 | |||
814 | seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024); | ||
815 | seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size); | ||
816 | seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n", | ||
817 | BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES); | ||
818 | seq_printf(m, | ||
819 | "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", | ||
820 | dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS, | ||
821 | BLKFIN_DLINES); | ||
822 | #ifdef CONFIG_BLKFIN_CACHE_LOCK | ||
823 | switch (read_iloc()) { | ||
824 | case WAY0_L: | ||
825 | seq_printf(m, "Way0 Locked-Down\n"); | ||
826 | break; | ||
827 | case WAY1_L: | ||
828 | seq_printf(m, "Way1 Locked-Down\n"); | ||
829 | break; | ||
830 | case WAY01_L: | ||
831 | seq_printf(m, "Way0,Way1 Locked-Down\n"); | ||
832 | break; | ||
833 | case WAY2_L: | ||
834 | seq_printf(m, "Way2 Locked-Down\n"); | ||
835 | break; | ||
836 | case WAY02_L: | ||
837 | seq_printf(m, "Way0,Way2 Locked-Down\n"); | ||
838 | break; | ||
839 | case WAY12_L: | ||
840 | seq_printf(m, "Way1,Way2 Locked-Down\n"); | ||
841 | break; | ||
842 | case WAY012_L: | ||
843 | seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n"); | ||
844 | break; | ||
845 | case WAY3_L: | ||
846 | seq_printf(m, "Way3 Locked-Down\n"); | ||
847 | break; | ||
848 | case WAY03_L: | ||
849 | seq_printf(m, "Way0,Way3 Locked-Down\n"); | ||
850 | break; | ||
851 | case WAY13_L: | ||
852 | seq_printf(m, "Way1,Way3 Locked-Down\n"); | ||
853 | break; | ||
854 | case WAY013_L: | ||
855 | seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n"); | ||
856 | break; | ||
857 | case WAY32_L: | ||
858 | seq_printf(m, "Way3,Way2 Locked-Down\n"); | ||
859 | break; | ||
860 | case WAY320_L: | ||
861 | seq_printf(m, "Way3,Way2,Way0 Locked-Down\n"); | ||
862 | break; | ||
863 | case WAY321_L: | ||
864 | seq_printf(m, "Way3,Way2,Way1 Locked-Down\n"); | ||
865 | break; | ||
866 | case WAYALL_L: | ||
867 | seq_printf(m, "All Ways are locked\n"); | ||
868 | break; | ||
869 | default: | ||
870 | seq_printf(m, "No Ways are locked\n"); | ||
871 | } | ||
872 | #endif | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
877 | { | ||
878 | return *pos < NR_CPUS ? ((void *)0x12345678) : NULL; | ||
879 | } | ||
880 | |||
881 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
882 | { | ||
883 | ++*pos; | ||
884 | return c_start(m, pos); | ||
885 | } | ||
886 | |||
887 | static void c_stop(struct seq_file *m, void *v) | ||
888 | { | ||
889 | } | ||
890 | |||
891 | struct seq_operations cpuinfo_op = { | ||
892 | .start = c_start, | ||
893 | .next = c_next, | ||
894 | .stop = c_stop, | ||
895 | .show = show_cpuinfo, | ||
896 | }; | ||
897 | |||
898 | void cmdline_init(unsigned long r0) | ||
899 | { | ||
900 | if (r0) | ||
901 | strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE); | ||
902 | } | ||