| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1 | /* | 
| Mike Frysinger | 550d553 | 2008-02-02 15:55:37 +0800 | [diff] [blame] | 2 | * arch/blackfin/kernel/setup.c | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 3 | * | 
| Mike Frysinger | 550d553 | 2008-02-02 15:55:37 +0800 | [diff] [blame] | 4 | * Copyright 2004-2006 Analog Devices Inc. | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 5 | * | 
| Mike Frysinger | 550d553 | 2008-02-02 15:55:37 +0800 | [diff] [blame] | 6 | * Enter bugs at http://blackfin.uclinux.org/ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 7 | * | 
| Mike Frysinger | 550d553 | 2008-02-02 15:55:37 +0800 | [diff] [blame] | 8 | * Licensed under the GPL-2 or later. | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 9 | */ | 
|  | 10 |  | 
|  | 11 | #include <linux/delay.h> | 
|  | 12 | #include <linux/console.h> | 
|  | 13 | #include <linux/bootmem.h> | 
|  | 14 | #include <linux/seq_file.h> | 
|  | 15 | #include <linux/cpu.h> | 
|  | 16 | #include <linux/module.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 17 | #include <linux/tty.h> | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 18 | #include <linux/pfn.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 19 |  | 
|  | 20 | #include <linux/ext2_fs.h> | 
|  | 21 | #include <linux/cramfs_fs.h> | 
|  | 22 | #include <linux/romfs_fs.h> | 
|  | 23 |  | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 24 | #include <asm/cplb.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 25 | #include <asm/cacheflush.h> | 
|  | 26 | #include <asm/blackfin.h> | 
|  | 27 | #include <asm/cplbinit.h> | 
| Mike Frysinger | 1754a5d | 2007-11-23 11:28:11 +0800 | [diff] [blame] | 28 | #include <asm/div64.h> | 
| Bernd Schmidt | 7adfb58 | 2007-06-21 11:34:16 +0800 | [diff] [blame] | 29 | #include <asm/fixed_code.h> | 
| Robin Getz | ce3afa1 | 2007-10-09 17:28:36 +0800 | [diff] [blame] | 30 | #include <asm/early_printk.h> | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 31 |  | 
| Michael Hennerich | 6cda2e9 | 2008-02-02 15:10:51 +0800 | [diff] [blame] | 32 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 
|  | 33 |  | 
| Mike Frysinger | a9c59c2 | 2007-05-21 18:09:32 +0800 | [diff] [blame] | 34 | u16 _bfin_swrst; | 
| Mike Frysinger | d45118b | 2008-02-25 12:24:44 +0800 | [diff] [blame] | 35 | EXPORT_SYMBOL(_bfin_swrst); | 
| Mike Frysinger | a9c59c2 | 2007-05-21 18:09:32 +0800 | [diff] [blame] | 36 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 37 | unsigned long memory_start, memory_end, physical_mem_end; | 
| Mike Frysinger | 3132b58 | 2008-04-24 05:12:09 +0800 | [diff] [blame] | 38 | unsigned long _rambase, _ramstart, _ramend; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 39 | unsigned long reserved_mem_dcache_on; | 
|  | 40 | unsigned long reserved_mem_icache_on; | 
|  | 41 | EXPORT_SYMBOL(memory_start); | 
|  | 42 | EXPORT_SYMBOL(memory_end); | 
|  | 43 | EXPORT_SYMBOL(physical_mem_end); | 
|  | 44 | EXPORT_SYMBOL(_ramend); | 
| Vitja Makarov | 58c35bd | 2008-10-13 15:23:56 +0800 | [diff] [blame] | 45 | EXPORT_SYMBOL(reserved_mem_dcache_on); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 46 |  | 
|  | 47 | #ifdef CONFIG_MTD_UCLINUX | 
|  | 48 | unsigned long memory_mtd_end, memory_mtd_start, mtd_size; | 
|  | 49 | unsigned long _ebss; | 
|  | 50 | EXPORT_SYMBOL(memory_mtd_end); | 
|  | 51 | EXPORT_SYMBOL(memory_mtd_start); | 
|  | 52 | EXPORT_SYMBOL(mtd_size); | 
|  | 53 | #endif | 
|  | 54 |  | 
| Mike Frysinger | 5e10b4a | 2007-06-11 16:44:09 +0800 | [diff] [blame] | 55 | char __initdata command_line[COMMAND_LINE_SIZE]; | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 56 | void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat, | 
|  | 57 | *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 58 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 59 | /* boot memmap, for parsing "memmap=" */ | 
|  | 60 | #define BFIN_MEMMAP_MAX		128 /* number of entries in bfin_memmap */ | 
|  | 61 | #define BFIN_MEMMAP_RAM		1 | 
|  | 62 | #define BFIN_MEMMAP_RESERVED	2 | 
|  | 63 | struct bfin_memmap { | 
|  | 64 | int nr_map; | 
|  | 65 | struct bfin_memmap_entry { | 
|  | 66 | unsigned long long addr; /* start of memory segment */ | 
|  | 67 | unsigned long long size; | 
|  | 68 | unsigned long type; | 
|  | 69 | } map[BFIN_MEMMAP_MAX]; | 
|  | 70 | } bfin_memmap __initdata; | 
|  | 71 |  | 
|  | 72 | /* for memmap sanitization */ | 
|  | 73 | struct change_member { | 
|  | 74 | struct bfin_memmap_entry *pentry; /* pointer to original entry */ | 
|  | 75 | unsigned long long addr; /* address for this change point */ | 
|  | 76 | }; | 
|  | 77 | static struct change_member change_point_list[2*BFIN_MEMMAP_MAX] __initdata; | 
|  | 78 | static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata; | 
|  | 79 | static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata; | 
|  | 80 | static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata; | 
|  | 81 |  | 
| Graf Yang | 5b04f27 | 2008-10-08 17:32:57 +0800 | [diff] [blame] | 82 | void __init bfin_cache_init(void) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 83 | { | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 84 | #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) | 
| Graf Yang | 5b04f27 | 2008-10-08 17:32:57 +0800 | [diff] [blame] | 85 | generate_cplb_tables(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 86 | #endif | 
|  | 87 |  | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 88 | #ifdef CONFIG_BFIN_ICACHE | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 89 | bfin_icache_init(); | 
|  | 90 | printk(KERN_INFO "Instruction Cache Enabled\n"); | 
|  | 91 | #endif | 
|  | 92 |  | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 93 | #ifdef CONFIG_BFIN_DCACHE | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 94 | bfin_dcache_init(); | 
|  | 95 | printk(KERN_INFO "Data Cache Enabled" | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 96 | # if defined CONFIG_BFIN_WB | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 97 | " (write-back)" | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 98 | # elif defined CONFIG_BFIN_WT | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 99 | " (write-through)" | 
|  | 100 | # endif | 
|  | 101 | "\n"); | 
|  | 102 | #endif | 
|  | 103 | } | 
|  | 104 |  | 
| Graf Yang | 5b04f27 | 2008-10-08 17:32:57 +0800 | [diff] [blame] | 105 | void __init bfin_relocate_l1_mem(void) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 106 | { | 
|  | 107 | unsigned long l1_code_length; | 
|  | 108 | unsigned long l1_data_a_length; | 
|  | 109 | unsigned long l1_data_b_length; | 
| Sonic Zhang | 262c382 | 2008-07-19 15:42:41 +0800 | [diff] [blame] | 110 | unsigned long l2_length; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 111 |  | 
|  | 112 | l1_code_length = _etext_l1 - _stext_l1; | 
|  | 113 | if (l1_code_length > L1_CODE_LENGTH) | 
| Sonic Zhang | b85b82d | 2008-04-24 06:13:37 +0800 | [diff] [blame] | 114 | panic("L1 Instruction SRAM Overflow\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 115 | /* cannot complain as printk is not available as yet. | 
|  | 116 | * But we can continue booting and complain later! | 
|  | 117 | */ | 
|  | 118 |  | 
|  | 119 | /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */ | 
|  | 120 | dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length); | 
|  | 121 |  | 
|  | 122 | l1_data_a_length = _ebss_l1 - _sdata_l1; | 
|  | 123 | if (l1_data_a_length > L1_DATA_A_LENGTH) | 
| Sonic Zhang | b85b82d | 2008-04-24 06:13:37 +0800 | [diff] [blame] | 124 | panic("L1 Data SRAM Bank A Overflow\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 125 |  | 
|  | 126 | /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */ | 
|  | 127 | dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length); | 
|  | 128 |  | 
|  | 129 | l1_data_b_length = _ebss_b_l1 - _sdata_b_l1; | 
|  | 130 | if (l1_data_b_length > L1_DATA_B_LENGTH) | 
| Sonic Zhang | b85b82d | 2008-04-24 06:13:37 +0800 | [diff] [blame] | 131 | panic("L1 Data SRAM Bank B Overflow\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 132 |  | 
|  | 133 | /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */ | 
|  | 134 | dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length + | 
|  | 135 | l1_data_a_length, l1_data_b_length); | 
| Sonic Zhang | 262c382 | 2008-07-19 15:42:41 +0800 | [diff] [blame] | 136 |  | 
| Mike Frysinger | 07aa7be | 2008-08-13 16:16:11 +0800 | [diff] [blame] | 137 | if (L2_LENGTH != 0) { | 
|  | 138 | l2_length = _ebss_l2 - _stext_l2; | 
|  | 139 | if (l2_length > L2_LENGTH) | 
|  | 140 | panic("L2 SRAM Overflow\n"); | 
| Sonic Zhang | 262c382 | 2008-07-19 15:42:41 +0800 | [diff] [blame] | 141 |  | 
| Mike Frysinger | 07aa7be | 2008-08-13 16:16:11 +0800 | [diff] [blame] | 142 | /* Copy _stext_l2 to _edata_l2 to L2 SRAM */ | 
|  | 143 | dma_memcpy(_stext_l2, _l2_lma_start, l2_length); | 
|  | 144 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 145 | } | 
|  | 146 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 147 | /* add_memory_region to memmap */ | 
|  | 148 | static void __init add_memory_region(unsigned long long start, | 
|  | 149 | unsigned long long size, int type) | 
|  | 150 | { | 
|  | 151 | int i; | 
|  | 152 |  | 
|  | 153 | i = bfin_memmap.nr_map; | 
|  | 154 |  | 
|  | 155 | if (i == BFIN_MEMMAP_MAX) { | 
|  | 156 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | 
|  | 157 | return; | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | bfin_memmap.map[i].addr = start; | 
|  | 161 | bfin_memmap.map[i].size = size; | 
|  | 162 | bfin_memmap.map[i].type = type; | 
|  | 163 | bfin_memmap.nr_map++; | 
|  | 164 | } | 
|  | 165 |  | 
|  | 166 | /* | 
|  | 167 | * Sanitize the boot memmap, removing overlaps. | 
|  | 168 | */ | 
|  | 169 | static int __init sanitize_memmap(struct bfin_memmap_entry *map, int *pnr_map) | 
|  | 170 | { | 
|  | 171 | struct change_member *change_tmp; | 
|  | 172 | unsigned long current_type, last_type; | 
|  | 173 | unsigned long long last_addr; | 
|  | 174 | int chgidx, still_changing; | 
|  | 175 | int overlap_entries; | 
|  | 176 | int new_entry; | 
|  | 177 | int old_nr, new_nr, chg_nr; | 
|  | 178 | int i; | 
|  | 179 |  | 
|  | 180 | /* | 
|  | 181 | Visually we're performing the following (1,2,3,4 = memory types) | 
|  | 182 |  | 
|  | 183 | Sample memory map (w/overlaps): | 
|  | 184 | ____22__________________ | 
|  | 185 | ______________________4_ | 
|  | 186 | ____1111________________ | 
|  | 187 | _44_____________________ | 
|  | 188 | 11111111________________ | 
|  | 189 | ____________________33__ | 
|  | 190 | ___________44___________ | 
|  | 191 | __________33333_________ | 
|  | 192 | ______________22________ | 
|  | 193 | ___________________2222_ | 
|  | 194 | _________111111111______ | 
|  | 195 | _____________________11_ | 
|  | 196 | _________________4______ | 
|  | 197 |  | 
|  | 198 | Sanitized equivalent (no overlap): | 
|  | 199 | 1_______________________ | 
|  | 200 | _44_____________________ | 
|  | 201 | ___1____________________ | 
|  | 202 | ____22__________________ | 
|  | 203 | ______11________________ | 
|  | 204 | _________1______________ | 
|  | 205 | __________3_____________ | 
|  | 206 | ___________44___________ | 
|  | 207 | _____________33_________ | 
|  | 208 | _______________2________ | 
|  | 209 | ________________1_______ | 
|  | 210 | _________________4______ | 
|  | 211 | ___________________2____ | 
|  | 212 | ____________________33__ | 
|  | 213 | ______________________4_ | 
|  | 214 | */ | 
|  | 215 | /* if there's only one memory region, don't bother */ | 
|  | 216 | if (*pnr_map < 2) | 
|  | 217 | return -1; | 
|  | 218 |  | 
|  | 219 | old_nr = *pnr_map; | 
|  | 220 |  | 
|  | 221 | /* bail out if we find any unreasonable addresses in memmap */ | 
|  | 222 | for (i = 0; i < old_nr; i++) | 
|  | 223 | if (map[i].addr + map[i].size < map[i].addr) | 
|  | 224 | return -1; | 
|  | 225 |  | 
|  | 226 | /* create pointers for initial change-point information (for sorting) */ | 
|  | 227 | for (i = 0; i < 2*old_nr; i++) | 
|  | 228 | change_point[i] = &change_point_list[i]; | 
|  | 229 |  | 
|  | 230 | /* record all known change-points (starting and ending addresses), | 
|  | 231 | omitting those that are for empty memory regions */ | 
|  | 232 | chgidx = 0; | 
|  | 233 | for (i = 0; i < old_nr; i++)	{ | 
|  | 234 | if (map[i].size != 0) { | 
|  | 235 | change_point[chgidx]->addr = map[i].addr; | 
|  | 236 | change_point[chgidx++]->pentry = &map[i]; | 
|  | 237 | change_point[chgidx]->addr = map[i].addr + map[i].size; | 
|  | 238 | change_point[chgidx++]->pentry = &map[i]; | 
|  | 239 | } | 
|  | 240 | } | 
|  | 241 | chg_nr = chgidx;    	/* true number of change-points */ | 
|  | 242 |  | 
|  | 243 | /* sort change-point list by memory addresses (low -> high) */ | 
|  | 244 | still_changing = 1; | 
|  | 245 | while (still_changing)	{ | 
|  | 246 | still_changing = 0; | 
|  | 247 | for (i = 1; i < chg_nr; i++)  { | 
|  | 248 | /* if <current_addr> > <last_addr>, swap */ | 
|  | 249 | /* or, if current=<start_addr> & last=<end_addr>, swap */ | 
|  | 250 | if ((change_point[i]->addr < change_point[i-1]->addr) || | 
|  | 251 | ((change_point[i]->addr == change_point[i-1]->addr) && | 
|  | 252 | (change_point[i]->addr == change_point[i]->pentry->addr) && | 
|  | 253 | (change_point[i-1]->addr != change_point[i-1]->pentry->addr)) | 
|  | 254 | ) { | 
|  | 255 | change_tmp = change_point[i]; | 
|  | 256 | change_point[i] = change_point[i-1]; | 
|  | 257 | change_point[i-1] = change_tmp; | 
|  | 258 | still_changing = 1; | 
|  | 259 | } | 
|  | 260 | } | 
|  | 261 | } | 
|  | 262 |  | 
|  | 263 | /* create a new memmap, removing overlaps */ | 
|  | 264 | overlap_entries = 0;	 /* number of entries in the overlap table */ | 
|  | 265 | new_entry = 0;	 /* index for creating new memmap entries */ | 
|  | 266 | last_type = 0;		 /* start with undefined memory type */ | 
|  | 267 | last_addr = 0;		 /* start with 0 as last starting address */ | 
|  | 268 | /* loop through change-points, determining affect on the new memmap */ | 
|  | 269 | for (chgidx = 0; chgidx < chg_nr; chgidx++) { | 
|  | 270 | /* keep track of all overlapping memmap entries */ | 
|  | 271 | if (change_point[chgidx]->addr == change_point[chgidx]->pentry->addr) { | 
|  | 272 | /* add map entry to overlap list (> 1 entry implies an overlap) */ | 
|  | 273 | overlap_list[overlap_entries++] = change_point[chgidx]->pentry; | 
|  | 274 | } else { | 
|  | 275 | /* remove entry from list (order independent, so swap with last) */ | 
|  | 276 | for (i = 0; i < overlap_entries; i++) { | 
|  | 277 | if (overlap_list[i] == change_point[chgidx]->pentry) | 
|  | 278 | overlap_list[i] = overlap_list[overlap_entries-1]; | 
|  | 279 | } | 
|  | 280 | overlap_entries--; | 
|  | 281 | } | 
|  | 282 | /* if there are overlapping entries, decide which "type" to use */ | 
|  | 283 | /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ | 
|  | 284 | current_type = 0; | 
|  | 285 | for (i = 0; i < overlap_entries; i++) | 
|  | 286 | if (overlap_list[i]->type > current_type) | 
|  | 287 | current_type = overlap_list[i]->type; | 
|  | 288 | /* continue building up new memmap based on this information */ | 
|  | 289 | if (current_type != last_type)	{ | 
|  | 290 | if (last_type != 0) { | 
|  | 291 | new_map[new_entry].size = | 
|  | 292 | change_point[chgidx]->addr - last_addr; | 
|  | 293 | /* move forward only if the new size was non-zero */ | 
|  | 294 | if (new_map[new_entry].size != 0) | 
|  | 295 | if (++new_entry >= BFIN_MEMMAP_MAX) | 
|  | 296 | break; 	/* no more space left for new entries */ | 
|  | 297 | } | 
|  | 298 | if (current_type != 0) { | 
|  | 299 | new_map[new_entry].addr = change_point[chgidx]->addr; | 
|  | 300 | new_map[new_entry].type = current_type; | 
|  | 301 | last_addr = change_point[chgidx]->addr; | 
|  | 302 | } | 
|  | 303 | last_type = current_type; | 
|  | 304 | } | 
|  | 305 | } | 
|  | 306 | new_nr = new_entry;   /* retain count for new entries */ | 
|  | 307 |  | 
|  | 308 | /* copy new  mapping into original location */ | 
|  | 309 | memcpy(map, new_map, new_nr*sizeof(struct bfin_memmap_entry)); | 
|  | 310 | *pnr_map = new_nr; | 
|  | 311 |  | 
|  | 312 | return 0; | 
|  | 313 | } | 
|  | 314 |  | 
|  | 315 | static void __init print_memory_map(char *who) | 
|  | 316 | { | 
|  | 317 | int i; | 
|  | 318 |  | 
|  | 319 | for (i = 0; i < bfin_memmap.nr_map; i++) { | 
|  | 320 | printk(KERN_DEBUG " %s: %016Lx - %016Lx ", who, | 
|  | 321 | bfin_memmap.map[i].addr, | 
|  | 322 | bfin_memmap.map[i].addr + bfin_memmap.map[i].size); | 
|  | 323 | switch (bfin_memmap.map[i].type) { | 
|  | 324 | case BFIN_MEMMAP_RAM: | 
|  | 325 | printk("(usable)\n"); | 
|  | 326 | break; | 
|  | 327 | case BFIN_MEMMAP_RESERVED: | 
|  | 328 | printk("(reserved)\n"); | 
|  | 329 | break; | 
|  | 330 | default:	printk("type %lu\n", bfin_memmap.map[i].type); | 
|  | 331 | break; | 
|  | 332 | } | 
|  | 333 | } | 
|  | 334 | } | 
|  | 335 |  | 
|  | 336 | static __init int parse_memmap(char *arg) | 
|  | 337 | { | 
|  | 338 | unsigned long long start_at, mem_size; | 
|  | 339 |  | 
|  | 340 | if (!arg) | 
|  | 341 | return -EINVAL; | 
|  | 342 |  | 
|  | 343 | mem_size = memparse(arg, &arg); | 
|  | 344 | if (*arg == '@') { | 
|  | 345 | start_at = memparse(arg+1, &arg); | 
|  | 346 | add_memory_region(start_at, mem_size, BFIN_MEMMAP_RAM); | 
|  | 347 | } else if (*arg == '$') { | 
|  | 348 | start_at = memparse(arg+1, &arg); | 
|  | 349 | add_memory_region(start_at, mem_size, BFIN_MEMMAP_RESERVED); | 
|  | 350 | } | 
|  | 351 |  | 
|  | 352 | return 0; | 
|  | 353 | } | 
|  | 354 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 355 | /* | 
|  | 356 | * Initial parsing of the command line.  Currently, we support: | 
|  | 357 | *  - Controlling the linux memory size: mem=xxx[KMG] | 
|  | 358 | *  - Controlling the physical memory size: max_mem=xxx[KMG][$][#] | 
|  | 359 | *       $ -> reserved memory is dcacheable | 
|  | 360 | *       # -> reserved memory is icacheable | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 361 | *  - "memmap=XXX[KkmM][@][$]XXX[KkmM]" defines a memory region | 
|  | 362 | *       @ from <start> to <start>+<mem>, type RAM | 
|  | 363 | *       $ from <start> to <start>+<mem>, type RESERVED | 
|  | 364 | * | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 365 | */ | 
|  | 366 | static __init void parse_cmdline_early(char *cmdline_p) | 
|  | 367 | { | 
|  | 368 | char c = ' ', *to = cmdline_p; | 
|  | 369 | unsigned int memsize; | 
|  | 370 | for (;;) { | 
|  | 371 | if (c == ' ') { | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 372 | if (!memcmp(to, "mem=", 4)) { | 
|  | 373 | to += 4; | 
|  | 374 | memsize = memparse(to, &to); | 
|  | 375 | if (memsize) | 
|  | 376 | _ramend = memsize; | 
|  | 377 |  | 
|  | 378 | } else if (!memcmp(to, "max_mem=", 8)) { | 
|  | 379 | to += 8; | 
|  | 380 | memsize = memparse(to, &to); | 
|  | 381 | if (memsize) { | 
|  | 382 | physical_mem_end = memsize; | 
|  | 383 | if (*to != ' ') { | 
|  | 384 | if (*to == '$' | 
|  | 385 | || *(to + 1) == '$') | 
|  | 386 | reserved_mem_dcache_on = | 
|  | 387 | 1; | 
|  | 388 | if (*to == '#' | 
|  | 389 | || *(to + 1) == '#') | 
|  | 390 | reserved_mem_icache_on = | 
|  | 391 | 1; | 
|  | 392 | } | 
|  | 393 | } | 
| Robin Getz | ce3afa1 | 2007-10-09 17:28:36 +0800 | [diff] [blame] | 394 | } else if (!memcmp(to, "earlyprintk=", 12)) { | 
|  | 395 | to += 12; | 
|  | 396 | setup_early_printk(to); | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 397 | } else if (!memcmp(to, "memmap=", 7)) { | 
|  | 398 | to += 7; | 
|  | 399 | parse_memmap(to); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 400 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 401 | } | 
|  | 402 | c = *(to++); | 
|  | 403 | if (!c) | 
|  | 404 | break; | 
|  | 405 | } | 
|  | 406 | } | 
|  | 407 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 408 | /* | 
|  | 409 | * Setup memory defaults from user config. | 
|  | 410 | * The physical memory layout looks like: | 
|  | 411 | * | 
|  | 412 | *  [_rambase, _ramstart]:		kernel image | 
|  | 413 | *  [memory_start, memory_end]:		dynamic memory managed by kernel | 
|  | 414 | *  [memory_end, _ramend]:		reserved memory | 
| Bryan Wu | 3094c98 | 2008-10-10 21:22:01 +0800 | [diff] [blame] | 415 | *  	[memory_mtd_start(memory_end), | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 416 | *  		memory_mtd_start + mtd_size]:	rootfs (if any) | 
|  | 417 | *	[_ramend - DMA_UNCACHED_REGION, | 
|  | 418 | *		_ramend]:			uncached DMA region | 
|  | 419 | *  [_ramend, physical_mem_end]:	memory not managed by kernel | 
|  | 420 | * | 
|  | 421 | */ | 
|  | 422 | static __init void  memory_setup(void) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 423 | { | 
| Mike Frysinger | c0eab3b | 2008-02-02 15:36:11 +0800 | [diff] [blame] | 424 | #ifdef CONFIG_MTD_UCLINUX | 
|  | 425 | unsigned long mtd_phys = 0; | 
|  | 426 | #endif | 
|  | 427 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 428 | _rambase = (unsigned long)_stext; | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 429 | _ramstart = (unsigned long)_end; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 430 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 431 | if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) { | 
|  | 432 | console_init(); | 
|  | 433 | panic("DMA region exceeds memory limit: %lu.\n", | 
|  | 434 | _ramend - _ramstart); | 
| Mike Frysinger | 1aafd90 | 2007-07-25 11:19:14 +0800 | [diff] [blame] | 435 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 436 | memory_end = _ramend - DMA_UNCACHED_REGION; | 
|  | 437 |  | 
| Bernd Schmidt | b97b8a9 | 2008-01-27 18:39:16 +0800 | [diff] [blame] | 438 | #ifdef CONFIG_MPU | 
|  | 439 | /* Round up to multiple of 4MB.  */ | 
|  | 440 | memory_start = (_ramstart + 0x3fffff) & ~0x3fffff; | 
|  | 441 | #else | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 442 | memory_start = PAGE_ALIGN(_ramstart); | 
| Bernd Schmidt | b97b8a9 | 2008-01-27 18:39:16 +0800 | [diff] [blame] | 443 | #endif | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 444 |  | 
|  | 445 | #if defined(CONFIG_MTD_UCLINUX) | 
|  | 446 | /* generic memory mapped MTD driver */ | 
|  | 447 | memory_mtd_end = memory_end; | 
|  | 448 |  | 
|  | 449 | mtd_phys = _ramstart; | 
|  | 450 | mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8))); | 
|  | 451 |  | 
|  | 452 | # if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS) | 
|  | 453 | if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC) | 
|  | 454 | mtd_size = | 
|  | 455 | PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10); | 
|  | 456 | # endif | 
|  | 457 |  | 
|  | 458 | # if defined(CONFIG_CRAMFS) | 
|  | 459 | if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC) | 
|  | 460 | mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4))); | 
|  | 461 | # endif | 
|  | 462 |  | 
|  | 463 | # if defined(CONFIG_ROMFS_FS) | 
|  | 464 | if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0 | 
|  | 465 | && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) | 
|  | 466 | mtd_size = | 
|  | 467 | PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 468 | #  if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 469 | /* Due to a Hardware Anomaly we need to limit the size of usable | 
|  | 470 | * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on | 
|  | 471 | * 05000263 - Hardware loop corrupted when taking an ICPLB exception | 
|  | 472 | */ | 
|  | 473 | #   if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) | 
|  | 474 | if (memory_end >= 56 * 1024 * 1024) | 
|  | 475 | memory_end = 56 * 1024 * 1024; | 
|  | 476 | #   else | 
|  | 477 | if (memory_end >= 60 * 1024 * 1024) | 
|  | 478 | memory_end = 60 * 1024 * 1024; | 
|  | 479 | #   endif				/* CONFIG_DEBUG_HUNT_FOR_ZERO */ | 
|  | 480 | #  endif				/* ANOMALY_05000263 */ | 
|  | 481 | # endif				/* CONFIG_ROMFS_FS */ | 
|  | 482 |  | 
|  | 483 | memory_end -= mtd_size; | 
|  | 484 |  | 
|  | 485 | if (mtd_size == 0) { | 
|  | 486 | console_init(); | 
|  | 487 | panic("Don't boot kernel without rootfs attached.\n"); | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | /* Relocate MTD image to the top of memory after the uncached memory area */ | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 491 | dma_memcpy((char *)memory_end, _end, mtd_size); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 492 |  | 
|  | 493 | memory_mtd_start = memory_end; | 
|  | 494 | _ebss = memory_mtd_start;	/* define _ebss for compatible */ | 
|  | 495 | #endif				/* CONFIG_MTD_UCLINUX */ | 
|  | 496 |  | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 497 | #if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 498 | /* Due to a Hardware Anomaly we need to limit the size of usable | 
|  | 499 | * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on | 
|  | 500 | * 05000263 - Hardware loop corrupted when taking an ICPLB exception | 
|  | 501 | */ | 
|  | 502 | #if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO)) | 
|  | 503 | if (memory_end >= 56 * 1024 * 1024) | 
|  | 504 | memory_end = 56 * 1024 * 1024; | 
|  | 505 | #else | 
|  | 506 | if (memory_end >= 60 * 1024 * 1024) | 
|  | 507 | memory_end = 60 * 1024 * 1024; | 
|  | 508 | #endif				/* CONFIG_DEBUG_HUNT_FOR_ZERO */ | 
|  | 509 | printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20); | 
|  | 510 | #endif				/* ANOMALY_05000263 */ | 
|  | 511 |  | 
| Bernd Schmidt | b97b8a9 | 2008-01-27 18:39:16 +0800 | [diff] [blame] | 512 | #ifdef CONFIG_MPU | 
|  | 513 | page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32; | 
|  | 514 | page_mask_order = get_order(3 * page_mask_nelts * sizeof(long)); | 
|  | 515 | #endif | 
|  | 516 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 517 | #if !defined(CONFIG_MTD_UCLINUX) | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 518 | /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/ | 
|  | 519 | memory_end -= SIZE_4K; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 520 | #endif | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 521 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 522 | init_mm.start_code = (unsigned long)_stext; | 
|  | 523 | init_mm.end_code = (unsigned long)_etext; | 
|  | 524 | init_mm.end_data = (unsigned long)_edata; | 
|  | 525 | init_mm.brk = (unsigned long)0; | 
|  | 526 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 527 | printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); | 
|  | 528 | printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); | 
|  | 529 |  | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 530 | printk(KERN_INFO "Memory map:\n" | 
| Mike Frysinger | 8929ecf8 | 2008-02-22 16:35:20 +0800 | [diff] [blame] | 531 | KERN_INFO "  fixedcode = 0x%p-0x%p\n" | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 532 | KERN_INFO "  text      = 0x%p-0x%p\n" | 
|  | 533 | KERN_INFO "  rodata    = 0x%p-0x%p\n" | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 534 | KERN_INFO "  bss       = 0x%p-0x%p\n" | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 535 | KERN_INFO "  data      = 0x%p-0x%p\n" | 
|  | 536 | KERN_INFO "    stack   = 0x%p-0x%p\n" | 
|  | 537 | KERN_INFO "  init      = 0x%p-0x%p\n" | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 538 | KERN_INFO "  available = 0x%p-0x%p\n" | 
|  | 539 | #ifdef CONFIG_MTD_UCLINUX | 
|  | 540 | KERN_INFO "  rootfs    = 0x%p-0x%p\n" | 
|  | 541 | #endif | 
|  | 542 | #if DMA_UNCACHED_REGION > 0 | 
|  | 543 | KERN_INFO "  DMA Zone  = 0x%p-0x%p\n" | 
|  | 544 | #endif | 
| Mike Frysinger | 8929ecf8 | 2008-02-22 16:35:20 +0800 | [diff] [blame] | 545 | , (void *)FIXED_CODE_START, (void *)FIXED_CODE_END, | 
|  | 546 | _stext, _etext, | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 547 | __start_rodata, __end_rodata, | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 548 | __bss_start, __bss_stop, | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 549 | _sdata, _edata, | 
|  | 550 | (void *)&init_thread_union, | 
|  | 551 | (void *)((int)(&init_thread_union) + 0x2000), | 
| Mike Frysinger | b7627ac | 2008-02-02 15:53:17 +0800 | [diff] [blame] | 552 | __init_begin, __init_end, | 
|  | 553 | (void *)_ramstart, (void *)memory_end | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 554 | #ifdef CONFIG_MTD_UCLINUX | 
|  | 555 | , (void *)memory_mtd_start, (void *)(memory_mtd_start + mtd_size) | 
|  | 556 | #endif | 
|  | 557 | #if DMA_UNCACHED_REGION > 0 | 
|  | 558 | , (void *)(_ramend - DMA_UNCACHED_REGION), (void *)(_ramend) | 
|  | 559 | #endif | 
|  | 560 | ); | 
|  | 561 | } | 
|  | 562 |  | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 563 | /* | 
|  | 564 | * Find the lowest, highest page frame number we have available | 
|  | 565 | */ | 
|  | 566 | void __init find_min_max_pfn(void) | 
|  | 567 | { | 
|  | 568 | int i; | 
|  | 569 |  | 
|  | 570 | max_pfn = 0; | 
|  | 571 | min_low_pfn = memory_end; | 
|  | 572 |  | 
|  | 573 | for (i = 0; i < bfin_memmap.nr_map; i++) { | 
|  | 574 | unsigned long start, end; | 
|  | 575 | /* RAM? */ | 
|  | 576 | if (bfin_memmap.map[i].type != BFIN_MEMMAP_RAM) | 
|  | 577 | continue; | 
|  | 578 | start = PFN_UP(bfin_memmap.map[i].addr); | 
|  | 579 | end = PFN_DOWN(bfin_memmap.map[i].addr + | 
|  | 580 | bfin_memmap.map[i].size); | 
|  | 581 | if (start >= end) | 
|  | 582 | continue; | 
|  | 583 | if (end > max_pfn) | 
|  | 584 | max_pfn = end; | 
|  | 585 | if (start < min_low_pfn) | 
|  | 586 | min_low_pfn = start; | 
|  | 587 | } | 
|  | 588 | } | 
|  | 589 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 590 | static __init void setup_bootmem_allocator(void) | 
|  | 591 | { | 
|  | 592 | int bootmap_size; | 
|  | 593 | int i; | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 594 | unsigned long start_pfn, end_pfn; | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 595 | unsigned long curr_pfn, last_pfn, size; | 
|  | 596 |  | 
|  | 597 | /* mark memory between memory_start and memory_end usable */ | 
|  | 598 | add_memory_region(memory_start, | 
|  | 599 | memory_end - memory_start, BFIN_MEMMAP_RAM); | 
|  | 600 | /* sanity check for overlap */ | 
|  | 601 | sanitize_memmap(bfin_memmap.map, &bfin_memmap.nr_map); | 
|  | 602 | print_memory_map("boot memmap"); | 
|  | 603 |  | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 604 | /* intialize globals in linux/bootmem.h */ | 
|  | 605 | find_min_max_pfn(); | 
|  | 606 | /* pfn of the last usable page frame */ | 
|  | 607 | if (max_pfn > memory_end >> PAGE_SHIFT) | 
|  | 608 | max_pfn = memory_end >> PAGE_SHIFT; | 
|  | 609 | /* pfn of last page frame directly mapped by kernel */ | 
|  | 610 | max_low_pfn = max_pfn; | 
|  | 611 | /* pfn of the first usable page frame after kernel image*/ | 
|  | 612 | if (min_low_pfn < memory_start >> PAGE_SHIFT) | 
|  | 613 | min_low_pfn = memory_start >> PAGE_SHIFT; | 
|  | 614 |  | 
|  | 615 | start_pfn = PAGE_OFFSET >> PAGE_SHIFT; | 
|  | 616 | end_pfn = memory_end >> PAGE_SHIFT; | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 617 |  | 
|  | 618 | /* | 
|  | 619 | * give all the memory to the bootmap allocator,  tell it to put the | 
|  | 620 | * boot mem_map at the start of memory. | 
|  | 621 | */ | 
|  | 622 | bootmap_size = init_bootmem_node(NODE_DATA(0), | 
|  | 623 | memory_start >> PAGE_SHIFT,	/* map goes here */ | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 624 | start_pfn, end_pfn); | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 625 |  | 
|  | 626 | /* register the memmap regions with the bootmem allocator */ | 
|  | 627 | for (i = 0; i < bfin_memmap.nr_map; i++) { | 
|  | 628 | /* | 
|  | 629 | * Reserve usable memory | 
|  | 630 | */ | 
|  | 631 | if (bfin_memmap.map[i].type != BFIN_MEMMAP_RAM) | 
|  | 632 | continue; | 
|  | 633 | /* | 
|  | 634 | * We are rounding up the start address of usable memory: | 
|  | 635 | */ | 
|  | 636 | curr_pfn = PFN_UP(bfin_memmap.map[i].addr); | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 637 | if (curr_pfn >= end_pfn) | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 638 | continue; | 
|  | 639 | /* | 
|  | 640 | * ... and at the end of the usable range downwards: | 
|  | 641 | */ | 
|  | 642 | last_pfn = PFN_DOWN(bfin_memmap.map[i].addr + | 
|  | 643 | bfin_memmap.map[i].size); | 
|  | 644 |  | 
| Yi Li | 2e8d796 | 2008-03-26 07:08:12 +0800 | [diff] [blame] | 645 | if (last_pfn > end_pfn) | 
|  | 646 | last_pfn = end_pfn; | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 647 |  | 
|  | 648 | /* | 
|  | 649 | * .. finally, did all the rounding and playing | 
|  | 650 | * around just make the area go away? | 
|  | 651 | */ | 
|  | 652 | if (last_pfn <= curr_pfn) | 
|  | 653 | continue; | 
|  | 654 |  | 
|  | 655 | size = last_pfn - curr_pfn; | 
|  | 656 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); | 
|  | 657 | } | 
|  | 658 |  | 
|  | 659 | /* reserve memory before memory_start, including bootmap */ | 
|  | 660 | reserve_bootmem(PAGE_OFFSET, | 
|  | 661 | memory_start + bootmap_size + PAGE_SIZE - 1 - PAGE_OFFSET, | 
|  | 662 | BOOTMEM_DEFAULT); | 
|  | 663 | } | 
|  | 664 |  | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 665 | #define EBSZ_TO_MEG(ebsz) \ | 
|  | 666 | ({ \ | 
|  | 667 | int meg = 0; \ | 
|  | 668 | switch (ebsz & 0xf) { \ | 
|  | 669 | case 0x1: meg =  16; break; \ | 
|  | 670 | case 0x3: meg =  32; break; \ | 
|  | 671 | case 0x5: meg =  64; break; \ | 
|  | 672 | case 0x7: meg = 128; break; \ | 
|  | 673 | case 0x9: meg = 256; break; \ | 
|  | 674 | case 0xb: meg = 512; break; \ | 
|  | 675 | } \ | 
|  | 676 | meg; \ | 
|  | 677 | }) | 
|  | 678 | static inline int __init get_mem_size(void) | 
|  | 679 | { | 
| Michael Hennerich | 99d95bb | 2008-07-14 17:04:14 +0800 | [diff] [blame] | 680 | #if defined(EBIU_SDBCTL) | 
|  | 681 | # if defined(BF561_FAMILY) | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 682 | int ret = 0; | 
|  | 683 | u32 sdbctl = bfin_read_EBIU_SDBCTL(); | 
|  | 684 | ret += EBSZ_TO_MEG(sdbctl >>  0); | 
|  | 685 | ret += EBSZ_TO_MEG(sdbctl >>  8); | 
|  | 686 | ret += EBSZ_TO_MEG(sdbctl >> 16); | 
|  | 687 | ret += EBSZ_TO_MEG(sdbctl >> 24); | 
|  | 688 | return ret; | 
| Michael Hennerich | 99d95bb | 2008-07-14 17:04:14 +0800 | [diff] [blame] | 689 | # else | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 690 | return EBSZ_TO_MEG(bfin_read_EBIU_SDBCTL()); | 
| Michael Hennerich | 99d95bb | 2008-07-14 17:04:14 +0800 | [diff] [blame] | 691 | # endif | 
|  | 692 | #elif defined(EBIU_DDRCTL1) | 
| Michael Hennerich | 1e78042 | 2008-04-25 04:31:23 +0800 | [diff] [blame] | 693 | u32 ddrctl = bfin_read_EBIU_DDRCTL1(); | 
|  | 694 | int ret = 0; | 
|  | 695 | switch (ddrctl & 0xc0000) { | 
|  | 696 | case DEVSZ_64:  ret = 64 / 8; | 
|  | 697 | case DEVSZ_128: ret = 128 / 8; | 
|  | 698 | case DEVSZ_256: ret = 256 / 8; | 
|  | 699 | case DEVSZ_512: ret = 512 / 8; | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 700 | } | 
| Michael Hennerich | 1e78042 | 2008-04-25 04:31:23 +0800 | [diff] [blame] | 701 | switch (ddrctl & 0x30000) { | 
|  | 702 | case DEVWD_4:  ret *= 2; | 
|  | 703 | case DEVWD_8:  ret *= 2; | 
|  | 704 | case DEVWD_16: break; | 
|  | 705 | } | 
| Mike Frysinger | b1b154e | 2008-07-26 18:02:05 +0800 | [diff] [blame] | 706 | if ((ddrctl & 0xc000) == 0x4000) | 
|  | 707 | ret *= 2; | 
| Michael Hennerich | 1e78042 | 2008-04-25 04:31:23 +0800 | [diff] [blame] | 708 | return ret; | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 709 | #endif | 
|  | 710 | BUG(); | 
|  | 711 | } | 
|  | 712 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 713 | void __init setup_arch(char **cmdline_p) | 
|  | 714 | { | 
| Mike Frysinger | 9f8e895 | 2008-04-24 06:20:11 +0800 | [diff] [blame] | 715 | unsigned long sclk, cclk; | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 716 |  | 
|  | 717 | #ifdef CONFIG_DUMMY_CONSOLE | 
|  | 718 | conswitchp = &dummy_con; | 
|  | 719 | #endif | 
|  | 720 |  | 
|  | 721 | #if defined(CONFIG_CMDLINE_BOOL) | 
|  | 722 | strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); | 
|  | 723 | command_line[sizeof(command_line) - 1] = 0; | 
|  | 724 | #endif | 
|  | 725 |  | 
|  | 726 | /* Keep a copy of command line */ | 
|  | 727 | *cmdline_p = &command_line[0]; | 
|  | 728 | memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); | 
|  | 729 | boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; | 
|  | 730 |  | 
|  | 731 | /* setup memory defaults from the user config */ | 
|  | 732 | physical_mem_end = 0; | 
| Mike Frysinger | a086ee2 | 2008-04-25 02:04:05 +0800 | [diff] [blame] | 733 | _ramend = get_mem_size() * 1024 * 1024; | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 734 |  | 
|  | 735 | memset(&bfin_memmap, 0, sizeof(bfin_memmap)); | 
|  | 736 |  | 
|  | 737 | parse_cmdline_early(&command_line[0]); | 
|  | 738 |  | 
|  | 739 | if (physical_mem_end == 0) | 
|  | 740 | physical_mem_end = _ramend; | 
|  | 741 |  | 
|  | 742 | memory_setup(); | 
|  | 743 |  | 
| Mike Frysinger | 7e64aca | 2008-08-06 17:17:10 +0800 | [diff] [blame] | 744 | /* Initialize Async memory banks */ | 
|  | 745 | bfin_write_EBIU_AMBCTL0(AMBCTL0VAL); | 
|  | 746 | bfin_write_EBIU_AMBCTL1(AMBCTL1VAL); | 
|  | 747 | bfin_write_EBIU_AMGCTL(AMGCTLVAL); | 
|  | 748 | #ifdef CONFIG_EBIU_MBSCTLVAL | 
|  | 749 | bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTLVAL); | 
|  | 750 | bfin_write_EBIU_MODE(CONFIG_EBIU_MODEVAL); | 
|  | 751 | bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTLVAL); | 
|  | 752 | #endif | 
|  | 753 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 754 | cclk = get_cclk(); | 
|  | 755 | sclk = get_sclk(); | 
|  | 756 |  | 
|  | 757 | #if !defined(CONFIG_BFIN_KERNEL_CLOCK) | 
|  | 758 | if (ANOMALY_05000273 && cclk == sclk) | 
|  | 759 | panic("ANOMALY 05000273, SCLK can not be same as CCLK"); | 
|  | 760 | #endif | 
|  | 761 |  | 
|  | 762 | #ifdef BF561_FAMILY | 
|  | 763 | if (ANOMALY_05000266) { | 
|  | 764 | bfin_read_IMDMA_D0_IRQ_STATUS(); | 
|  | 765 | bfin_read_IMDMA_D1_IRQ_STATUS(); | 
|  | 766 | } | 
|  | 767 | #endif | 
|  | 768 | printk(KERN_INFO "Hardware Trace "); | 
|  | 769 | if (bfin_read_TBUFCTL() & 0x1) | 
|  | 770 | printk("Active "); | 
|  | 771 | else | 
|  | 772 | printk("Off "); | 
|  | 773 | if (bfin_read_TBUFCTL() & 0x2) | 
|  | 774 | printk("and Enabled\n"); | 
|  | 775 | else | 
|  | 776 | printk("and Disabled\n"); | 
|  | 777 |  | 
|  | 778 | #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) | 
|  | 779 | /* we need to initialize the Flashrom device here since we might | 
|  | 780 | * do things with flash early on in the boot | 
|  | 781 | */ | 
|  | 782 | flash_probe(); | 
|  | 783 | #endif | 
|  | 784 |  | 
| Robin Getz | 7728ec3 | 2007-10-29 18:12:15 +0800 | [diff] [blame] | 785 | _bfin_swrst = bfin_read_SWRST(); | 
|  | 786 |  | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 787 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT | 
|  | 788 | bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT); | 
|  | 789 | #endif | 
|  | 790 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET | 
|  | 791 | bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT); | 
|  | 792 | #endif | 
| Robin Getz | 2d20098 | 2008-07-26 19:41:40 +0800 | [diff] [blame] | 793 |  | 
| Robin Getz | 0c7a6b2 | 2008-10-08 16:27:12 +0800 | [diff] [blame] | 794 | if (_bfin_swrst & RESET_DOUBLE) { | 
|  | 795 | printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n"); | 
|  | 796 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | 
|  | 797 | /* We assume the crashing kernel, and the current symbol table match */ | 
|  | 798 | printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", | 
|  | 799 | (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx); | 
|  | 800 | printk(KERN_NOTICE "   DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr); | 
|  | 801 | printk(KERN_NOTICE "   ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr); | 
|  | 802 | #endif | 
|  | 803 | printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", | 
|  | 804 | init_retx); | 
|  | 805 | } else if (_bfin_swrst & RESET_WDOG) | 
| Robin Getz | 7728ec3 | 2007-10-29 18:12:15 +0800 | [diff] [blame] | 806 | printk(KERN_INFO "Recovering from Watchdog event\n"); | 
|  | 807 | else if (_bfin_swrst & RESET_SOFTWARE) | 
|  | 808 | printk(KERN_NOTICE "Reset caused by Software reset\n"); | 
|  | 809 |  | 
| Mike Frysinger | 550d553 | 2008-02-02 15:55:37 +0800 | [diff] [blame] | 810 | printk(KERN_INFO "Blackfin support (C) 2004-2008 Analog Devices, Inc.\n"); | 
| Jie Zhang | de3025f | 2007-06-25 18:04:12 +0800 | [diff] [blame] | 811 | if (bfin_compiled_revid() == 0xffff) | 
|  | 812 | printk(KERN_INFO "Compiled for ADSP-%s Rev any\n", CPU); | 
|  | 813 | else if (bfin_compiled_revid() == -1) | 
|  | 814 | printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU); | 
|  | 815 | else | 
|  | 816 | printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid()); | 
| Robin Getz | e482cad | 2008-10-10 18:21:45 +0800 | [diff] [blame] | 817 |  | 
|  | 818 | if (unlikely(CPUID != bfin_cpuid())) | 
|  | 819 | printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n", | 
|  | 820 | CPU, bfin_cpuid(), bfin_revid()); | 
|  | 821 | else { | 
|  | 822 | if (bfin_revid() != bfin_compiled_revid()) { | 
|  | 823 | if (bfin_compiled_revid() == -1) | 
|  | 824 | printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n", | 
|  | 825 | bfin_revid()); | 
|  | 826 | else if (bfin_compiled_revid() != 0xffff) | 
|  | 827 | printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", | 
|  | 828 | bfin_compiled_revid(), bfin_revid()); | 
|  | 829 | } | 
|  | 830 | if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX) | 
|  | 831 | printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", | 
|  | 832 | CPU, bfin_revid()); | 
| Jie Zhang | de3025f | 2007-06-25 18:04:12 +0800 | [diff] [blame] | 833 | } | 
| Mike Frysinger | 0c0497c | 2008-10-09 17:32:28 +0800 | [diff] [blame] | 834 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 835 | printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); | 
|  | 836 |  | 
| Mike Frysinger | b5c0e2e | 2007-09-12 17:31:59 +0800 | [diff] [blame] | 837 | printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n", | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 838 | cclk / 1000000,  sclk / 1000000); | 
|  | 839 |  | 
| Mike Frysinger | 1aafd90 | 2007-07-25 11:19:14 +0800 | [diff] [blame] | 840 | if (ANOMALY_05000273 && (cclk >> 1) <= sclk) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 841 | printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n"); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 842 |  | 
| Yi Li | 856783b | 2008-02-09 02:26:01 +0800 | [diff] [blame] | 843 | setup_bootmem_allocator(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 844 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 845 | paging_init(); | 
|  | 846 |  | 
| Bernd Schmidt | 7adfb58 | 2007-06-21 11:34:16 +0800 | [diff] [blame] | 847 | /* Copy atomic sequences to their fixed location, and sanity check that | 
|  | 848 | these locations are the ones that we advertise to userspace.  */ | 
|  | 849 | memcpy((void *)FIXED_CODE_START, &fixed_code_start, | 
|  | 850 | FIXED_CODE_END - FIXED_CODE_START); | 
|  | 851 | BUG_ON((char *)&sigreturn_stub - (char *)&fixed_code_start | 
|  | 852 | != SIGRETURN_STUB - FIXED_CODE_START); | 
|  | 853 | BUG_ON((char *)&atomic_xchg32 - (char *)&fixed_code_start | 
|  | 854 | != ATOMIC_XCHG32 - FIXED_CODE_START); | 
|  | 855 | BUG_ON((char *)&atomic_cas32 - (char *)&fixed_code_start | 
|  | 856 | != ATOMIC_CAS32 - FIXED_CODE_START); | 
|  | 857 | BUG_ON((char *)&atomic_add32 - (char *)&fixed_code_start | 
|  | 858 | != ATOMIC_ADD32 - FIXED_CODE_START); | 
|  | 859 | BUG_ON((char *)&atomic_sub32 - (char *)&fixed_code_start | 
|  | 860 | != ATOMIC_SUB32 - FIXED_CODE_START); | 
|  | 861 | BUG_ON((char *)&atomic_ior32 - (char *)&fixed_code_start | 
|  | 862 | != ATOMIC_IOR32 - FIXED_CODE_START); | 
|  | 863 | BUG_ON((char *)&atomic_and32 - (char *)&fixed_code_start | 
|  | 864 | != ATOMIC_AND32 - FIXED_CODE_START); | 
|  | 865 | BUG_ON((char *)&atomic_xor32 - (char *)&fixed_code_start | 
|  | 866 | != ATOMIC_XOR32 - FIXED_CODE_START); | 
| Robin Getz | 9f336a5 | 2007-10-29 18:23:28 +0800 | [diff] [blame] | 867 | BUG_ON((char *)&safe_user_instruction - (char *)&fixed_code_start | 
|  | 868 | != SAFE_USER_INSTRUCTION - FIXED_CODE_START); | 
| Bernd Schmidt | 29440a2 | 2007-07-12 16:25:29 +0800 | [diff] [blame] | 869 |  | 
| Bernd Schmidt | 8be80ed | 2007-07-25 14:44:49 +0800 | [diff] [blame] | 870 | init_exception_vectors(); | 
| Graf Yang | 5b04f27 | 2008-10-08 17:32:57 +0800 | [diff] [blame] | 871 | bfin_cache_init(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 872 | } | 
|  | 873 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 874 | static int __init topology_init(void) | 
|  | 875 | { | 
| Michael Hennerich | 6cda2e9 | 2008-02-02 15:10:51 +0800 | [diff] [blame] | 876 | int cpu; | 
|  | 877 |  | 
|  | 878 | for_each_possible_cpu(cpu) { | 
|  | 879 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 
|  | 880 |  | 
|  | 881 | register_cpu(c, cpu); | 
|  | 882 | } | 
|  | 883 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 884 | return 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 885 | } | 
|  | 886 |  | 
|  | 887 | subsys_initcall(topology_init); | 
|  | 888 |  | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 889 | /* Get the voltage input multiplier */ | 
|  | 890 | static u_long cached_vco_pll_ctl, cached_vco; | 
| Mike Frysinger | 52a0781 | 2007-06-11 15:31:30 +0800 | [diff] [blame] | 891 | static u_long get_vco(void) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 892 | { | 
|  | 893 | u_long msel; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 894 |  | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 895 | u_long pll_ctl = bfin_read_PLL_CTL(); | 
|  | 896 | if (pll_ctl == cached_vco_pll_ctl) | 
|  | 897 | return cached_vco; | 
|  | 898 | else | 
|  | 899 | cached_vco_pll_ctl = pll_ctl; | 
|  | 900 |  | 
|  | 901 | msel = (pll_ctl >> 9) & 0x3F; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 902 | if (0 == msel) | 
|  | 903 | msel = 64; | 
|  | 904 |  | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 905 | cached_vco = CONFIG_CLKIN_HZ; | 
|  | 906 | cached_vco >>= (1 & pll_ctl);	/* DF bit */ | 
|  | 907 | cached_vco *= msel; | 
|  | 908 | return cached_vco; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 909 | } | 
|  | 910 |  | 
| Mike Frysinger | 2f6cf7b | 2007-10-21 22:59:49 +0800 | [diff] [blame] | 911 | /* Get the Core clock */ | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 912 | static u_long cached_cclk_pll_div, cached_cclk; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 913 | u_long get_cclk(void) | 
|  | 914 | { | 
|  | 915 | u_long csel, ssel; | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 916 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 917 | if (bfin_read_PLL_STAT() & 0x1) | 
|  | 918 | return CONFIG_CLKIN_HZ; | 
|  | 919 |  | 
|  | 920 | ssel = bfin_read_PLL_DIV(); | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 921 | if (ssel == cached_cclk_pll_div) | 
|  | 922 | return cached_cclk; | 
|  | 923 | else | 
|  | 924 | cached_cclk_pll_div = ssel; | 
|  | 925 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 926 | csel = ((ssel >> 4) & 0x03); | 
|  | 927 | ssel &= 0xf; | 
|  | 928 | if (ssel && ssel < (1 << csel))	/* SCLK > CCLK */ | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 929 | cached_cclk = get_vco() / ssel; | 
|  | 930 | else | 
|  | 931 | cached_cclk = get_vco() >> csel; | 
|  | 932 | return cached_cclk; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 933 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 934 | EXPORT_SYMBOL(get_cclk); | 
|  | 935 |  | 
|  | 936 | /* Get the System clock */ | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 937 | static u_long cached_sclk_pll_div, cached_sclk; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 938 | u_long get_sclk(void) | 
|  | 939 | { | 
|  | 940 | u_long ssel; | 
|  | 941 |  | 
|  | 942 | if (bfin_read_PLL_STAT() & 0x1) | 
|  | 943 | return CONFIG_CLKIN_HZ; | 
|  | 944 |  | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 945 | ssel = bfin_read_PLL_DIV(); | 
|  | 946 | if (ssel == cached_sclk_pll_div) | 
|  | 947 | return cached_sclk; | 
|  | 948 | else | 
|  | 949 | cached_sclk_pll_div = ssel; | 
|  | 950 |  | 
|  | 951 | ssel &= 0xf; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 952 | if (0 == ssel) { | 
|  | 953 | printk(KERN_WARNING "Invalid System Clock\n"); | 
|  | 954 | ssel = 1; | 
|  | 955 | } | 
|  | 956 |  | 
| Mike Frysinger | 3a2521f | 2008-07-26 18:52:56 +0800 | [diff] [blame] | 957 | cached_sclk = get_vco() / ssel; | 
|  | 958 | return cached_sclk; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 959 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 960 | EXPORT_SYMBOL(get_sclk); | 
|  | 961 |  | 
| Mike Frysinger | 2f6cf7b | 2007-10-21 22:59:49 +0800 | [diff] [blame] | 962 | unsigned long sclk_to_usecs(unsigned long sclk) | 
|  | 963 | { | 
| Mike Frysinger | 1754a5d | 2007-11-23 11:28:11 +0800 | [diff] [blame] | 964 | u64 tmp = USEC_PER_SEC * (u64)sclk; | 
|  | 965 | do_div(tmp, get_sclk()); | 
|  | 966 | return tmp; | 
| Mike Frysinger | 2f6cf7b | 2007-10-21 22:59:49 +0800 | [diff] [blame] | 967 | } | 
|  | 968 | EXPORT_SYMBOL(sclk_to_usecs); | 
|  | 969 |  | 
|  | 970 | unsigned long usecs_to_sclk(unsigned long usecs) | 
|  | 971 | { | 
| Mike Frysinger | 1754a5d | 2007-11-23 11:28:11 +0800 | [diff] [blame] | 972 | u64 tmp = get_sclk() * (u64)usecs; | 
|  | 973 | do_div(tmp, USEC_PER_SEC); | 
|  | 974 | return tmp; | 
| Mike Frysinger | 2f6cf7b | 2007-10-21 22:59:49 +0800 | [diff] [blame] | 975 | } | 
|  | 976 | EXPORT_SYMBOL(usecs_to_sclk); | 
|  | 977 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 978 | /* | 
|  | 979 | *	Get CPU information for use by the procfs. | 
|  | 980 | */ | 
|  | 981 | static int show_cpuinfo(struct seq_file *m, void *v) | 
|  | 982 | { | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 983 | char *cpu, *mmu, *fpu, *vendor, *cache; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 984 | uint32_t revid; | 
|  | 985 |  | 
|  | 986 | u_long cclk = 0, sclk = 0; | 
| Robin Getz | 9de3a0b | 2008-07-26 19:39:19 +0800 | [diff] [blame] | 987 | u_int icache_size = BFIN_ICACHESIZE / 1024, dcache_size = 0, dsup_banks = 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 988 |  | 
|  | 989 | cpu = CPU; | 
|  | 990 | mmu = "none"; | 
|  | 991 | fpu = "none"; | 
|  | 992 | revid = bfin_revid(); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 993 |  | 
|  | 994 | cclk = get_cclk(); | 
|  | 995 | sclk = get_sclk(); | 
|  | 996 |  | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 997 | switch (bfin_read_CHIPID() & CHIPID_MANUFACTURE) { | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 998 | case 0xca: | 
|  | 999 | vendor = "Analog Devices"; | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1000 | break; | 
|  | 1001 | default: | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1002 | vendor = "unknown"; | 
|  | 1003 | break; | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1004 | } | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1005 |  | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1006 | seq_printf(m, "processor\t: %d\n" | 
| Robin Getz | e482cad | 2008-10-10 18:21:45 +0800 | [diff] [blame] | 1007 | "vendor_id\t: %s\n", | 
| Graf Yang | 55f2fea | 2008-10-09 15:37:47 +0800 | [diff] [blame] | 1008 | *(unsigned int *)v, | 
| Robin Getz | e482cad | 2008-10-10 18:21:45 +0800 | [diff] [blame] | 1009 | vendor); | 
|  | 1010 |  | 
|  | 1011 | if (CPUID == bfin_cpuid()) | 
|  | 1012 | seq_printf(m, "cpu family\t: 0x%04x\n", CPUID); | 
|  | 1013 | else | 
|  | 1014 | seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n", | 
|  | 1015 | CPUID, bfin_cpuid()); | 
|  | 1016 |  | 
|  | 1017 | seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" | 
|  | 1018 | "stepping\t: %d\n", | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1019 | cpu, cclk/1000000, sclk/1000000, | 
| Robin Getz | 253bcf4 | 2008-04-24 05:57:13 +0800 | [diff] [blame] | 1020 | #ifdef CONFIG_MPU | 
|  | 1021 | "mpu on", | 
|  | 1022 | #else | 
|  | 1023 | "mpu off", | 
|  | 1024 | #endif | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1025 | revid); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1026 |  | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1027 | seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n", | 
|  | 1028 | cclk/1000000, cclk%1000000, | 
|  | 1029 | sclk/1000000, sclk%1000000); | 
|  | 1030 | seq_printf(m, "bogomips\t: %lu.%02lu\n" | 
|  | 1031 | "Calibration\t: %lu loops\n", | 
|  | 1032 | (loops_per_jiffy * HZ) / 500000, | 
|  | 1033 | ((loops_per_jiffy * HZ) / 5000) % 100, | 
|  | 1034 | (loops_per_jiffy * HZ)); | 
|  | 1035 |  | 
|  | 1036 | /* Check Cache configutation */ | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 1037 | switch (bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) { | 
|  | 1038 | case ACACHE_BSRAM: | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1039 | cache = "dbank-A/B\t: cache/sram"; | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 1040 | dcache_size = 16; | 
|  | 1041 | dsup_banks = 1; | 
|  | 1042 | break; | 
|  | 1043 | case ACACHE_BCACHE: | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1044 | cache = "dbank-A/B\t: cache/cache"; | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 1045 | dcache_size = 32; | 
|  | 1046 | dsup_banks = 2; | 
|  | 1047 | break; | 
|  | 1048 | case ASRAM_BSRAM: | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1049 | cache = "dbank-A/B\t: sram/sram"; | 
| Mike Frysinger | 1f83b8f | 2007-07-12 22:58:21 +0800 | [diff] [blame] | 1050 | dcache_size = 0; | 
|  | 1051 | dsup_banks = 0; | 
|  | 1052 | break; | 
|  | 1053 | default: | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1054 | cache = "unknown"; | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1055 | dcache_size = 0; | 
|  | 1056 | dsup_banks = 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1057 | break; | 
|  | 1058 | } | 
|  | 1059 |  | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1060 | /* Is it turned on? */ | 
| Robin Getz | 2d20098 | 2008-07-26 19:41:40 +0800 | [diff] [blame] | 1061 | if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE)) | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1062 | dcache_size = 0; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1063 |  | 
| Graf Yang | 55f2fea | 2008-10-09 15:37:47 +0800 | [diff] [blame] | 1064 | if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) != (IMC | ENICPLB)) | 
| Robin Getz | 9de3a0b | 2008-07-26 19:39:19 +0800 | [diff] [blame] | 1065 | icache_size = 0; | 
|  | 1066 |  | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1067 | seq_printf(m, "cache size\t: %d KB(L1 icache) " | 
|  | 1068 | "%d KB(L1 dcache-%s) %d KB(L2 cache)\n", | 
| Robin Getz | 9de3a0b | 2008-07-26 19:39:19 +0800 | [diff] [blame] | 1069 | icache_size, dcache_size, | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1070 | #if defined CONFIG_BFIN_WB | 
|  | 1071 | "wb" | 
|  | 1072 | #elif defined CONFIG_BFIN_WT | 
|  | 1073 | "wt" | 
|  | 1074 | #endif | 
| Mike Frysinger | da27abb | 2007-10-22 10:55:35 +0800 | [diff] [blame] | 1075 | "", 0); | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1076 |  | 
|  | 1077 | seq_printf(m, "%s\n", cache); | 
|  | 1078 |  | 
| Robin Getz | 9de3a0b | 2008-07-26 19:39:19 +0800 | [diff] [blame] | 1079 | if (icache_size) | 
|  | 1080 | seq_printf(m, "icache setup\t: %d Sub-banks/%d Ways, %d Lines/Way\n", | 
|  | 1081 | BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES); | 
|  | 1082 | else | 
|  | 1083 | seq_printf(m, "icache setup\t: off\n"); | 
|  | 1084 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1085 | seq_printf(m, | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1086 | "dcache setup\t: %d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", | 
| Robin Getz | 3bebca2 | 2007-10-10 23:55:26 +0800 | [diff] [blame] | 1087 | dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS, | 
|  | 1088 | BFIN_DLINES); | 
|  | 1089 | #ifdef CONFIG_BFIN_ICACHE_LOCK | 
| Mike Frysinger | 0e06b50 | 2008-08-14 14:29:57 +0800 | [diff] [blame] | 1090 | switch ((bfin_read_IMEM_CONTROL() >> 3) & WAYALL_L) { | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1091 | case WAY0_L: | 
|  | 1092 | seq_printf(m, "Way0 Locked-Down\n"); | 
|  | 1093 | break; | 
|  | 1094 | case WAY1_L: | 
|  | 1095 | seq_printf(m, "Way1 Locked-Down\n"); | 
|  | 1096 | break; | 
|  | 1097 | case WAY01_L: | 
|  | 1098 | seq_printf(m, "Way0,Way1 Locked-Down\n"); | 
|  | 1099 | break; | 
|  | 1100 | case WAY2_L: | 
|  | 1101 | seq_printf(m, "Way2 Locked-Down\n"); | 
|  | 1102 | break; | 
|  | 1103 | case WAY02_L: | 
|  | 1104 | seq_printf(m, "Way0,Way2 Locked-Down\n"); | 
|  | 1105 | break; | 
|  | 1106 | case WAY12_L: | 
|  | 1107 | seq_printf(m, "Way1,Way2 Locked-Down\n"); | 
|  | 1108 | break; | 
|  | 1109 | case WAY012_L: | 
|  | 1110 | seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n"); | 
|  | 1111 | break; | 
|  | 1112 | case WAY3_L: | 
|  | 1113 | seq_printf(m, "Way3 Locked-Down\n"); | 
|  | 1114 | break; | 
|  | 1115 | case WAY03_L: | 
|  | 1116 | seq_printf(m, "Way0,Way3 Locked-Down\n"); | 
|  | 1117 | break; | 
|  | 1118 | case WAY13_L: | 
|  | 1119 | seq_printf(m, "Way1,Way3 Locked-Down\n"); | 
|  | 1120 | break; | 
|  | 1121 | case WAY013_L: | 
|  | 1122 | seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n"); | 
|  | 1123 | break; | 
|  | 1124 | case WAY32_L: | 
|  | 1125 | seq_printf(m, "Way3,Way2 Locked-Down\n"); | 
|  | 1126 | break; | 
|  | 1127 | case WAY320_L: | 
|  | 1128 | seq_printf(m, "Way3,Way2,Way0 Locked-Down\n"); | 
|  | 1129 | break; | 
|  | 1130 | case WAY321_L: | 
|  | 1131 | seq_printf(m, "Way3,Way2,Way1 Locked-Down\n"); | 
|  | 1132 | break; | 
|  | 1133 | case WAYALL_L: | 
|  | 1134 | seq_printf(m, "All Ways are locked\n"); | 
|  | 1135 | break; | 
|  | 1136 | default: | 
|  | 1137 | seq_printf(m, "No Ways are locked\n"); | 
|  | 1138 | } | 
|  | 1139 | #endif | 
| Mike Frysinger | 066954a | 2007-10-21 22:36:06 +0800 | [diff] [blame] | 1140 | seq_printf(m, "board name\t: %s\n", bfin_board_name); | 
| Robin Getz | 73b0c0b | 2007-10-21 17:03:31 +0800 | [diff] [blame] | 1141 | seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n", | 
|  | 1142 | physical_mem_end >> 10, (void *)0, (void *)physical_mem_end); | 
|  | 1143 | seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n", | 
|  | 1144 | ((int)memory_end - (int)_stext) >> 10, | 
|  | 1145 | _stext, | 
|  | 1146 | (void *)memory_end); | 
|  | 1147 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1148 | return 0; | 
|  | 1149 | } | 
|  | 1150 |  | 
|  | 1151 | static void *c_start(struct seq_file *m, loff_t *pos) | 
|  | 1152 | { | 
| Graf Yang | 55f2fea | 2008-10-09 15:37:47 +0800 | [diff] [blame] | 1153 | if (*pos == 0) | 
|  | 1154 | *pos = first_cpu(cpu_online_map); | 
|  | 1155 | if (*pos >= num_online_cpus()) | 
|  | 1156 | return NULL; | 
|  | 1157 |  | 
|  | 1158 | return pos; | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1159 | } | 
|  | 1160 |  | 
|  | 1161 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | 
|  | 1162 | { | 
| Graf Yang | 55f2fea | 2008-10-09 15:37:47 +0800 | [diff] [blame] | 1163 | *pos = next_cpu(*pos, cpu_online_map); | 
|  | 1164 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1165 | return c_start(m, pos); | 
|  | 1166 | } | 
|  | 1167 |  | 
|  | 1168 | static void c_stop(struct seq_file *m, void *v) | 
|  | 1169 | { | 
|  | 1170 | } | 
|  | 1171 |  | 
| Jan Engelhardt | 03a4482 | 2008-02-08 04:21:19 -0800 | [diff] [blame] | 1172 | const struct seq_operations cpuinfo_op = { | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1173 | .start = c_start, | 
|  | 1174 | .next = c_next, | 
|  | 1175 | .stop = c_stop, | 
|  | 1176 | .show = show_cpuinfo, | 
|  | 1177 | }; | 
|  | 1178 |  | 
| Mike Frysinger | 5e10b4a | 2007-06-11 16:44:09 +0800 | [diff] [blame] | 1179 | void __init cmdline_init(const char *r0) | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1180 | { | 
|  | 1181 | if (r0) | 
| Mike Frysinger | 52a0781 | 2007-06-11 15:31:30 +0800 | [diff] [blame] | 1182 | strncpy(command_line, r0, COMMAND_LINE_SIZE); | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 1183 | } |