1/* 2 * CRISv32 kernel startup code. 3 * 4 * Copyright (C) 2003, Axis Communications AB 5 */ 6 7 8#define ASSEMBLER_MACROS_ONLY 9 10/* 11 * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so 12 * -traditional must not be used when assembling this file. 13 */ 14#include <asm/arch/hwregs/reg_rdwr.h> 15#include <asm/arch/hwregs/asm/mmu_defs_asm.h> 16#include <asm/arch/hwregs/asm/reg_map_asm.h> 17#include <asm/arch/hwregs/asm/config_defs_asm.h> 18#include <asm/arch/hwregs/asm/bif_core_defs_asm.h> 19 20#define CRAMFS_MAGIC 0x28cd3d45 21#define RAM_INIT_MAGIC 0x56902387 22#define COMMAND_LINE_MAGIC 0x87109563 23 24 ;; NOTE: R8 and R9 carry information from the decompressor (if the 25 ;; kernel was compressed). They must not be used in the code below 26 ;; until they are read! 27 28 ;; Exported symbols. 29 .global etrax_irv 30 .global romfs_start 31 .global romfs_length 32 .global romfs_in_flash 33 .global swapper_pg_dir 34 .global crisv32_nand_boot 35 .global crisv32_nand_cramfs_offset 36 37 ;; Dummy section to make it bootable with current VCS simulator 38#ifdef CONFIG_ETRAXFS_SIM 39 .section ".boot", "ax" 40 ba tstart 41 nop 42#endif 43 44 .text 45tstart: 46 ;; This is the entry point of the kernel. The CPU is currently in 47 ;; supervisor mode. 48 ;; 49 ;; 0x00000000 if flash. 50 ;; 0x40004000 if DRAM. 51 ;; 52 di 53 54 ;; Start clocks for used blocks. 55 move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 56 move.d [$r1], $r0 57 or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ 58 REG_STATE(config, rw_clk_ctrl, bif, yes) | \ 59 REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 60 move.d $r0, [$r1] 61 62 ;; Set up waitstates etc 63 move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0 64 move.d CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1 65 move.d $r1, [$r0] 66 move.d REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0 67 move.d CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1 68 move.d $r1, [$r0] 69 move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0 70 move.d CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1 71 move.d $r1, [$r0] 72 move.d REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0 73 move.d CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1 74 move.d $r1, [$r0] 75 76#ifdef CONFIG_ETRAXFS_SIM 77 ;; Set up minimal flash waitstates 78 move.d 0, $r10 79 move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11 80 move.d $r10, [$r11] 81#endif 82 83 ;; Setup and enable the MMU. Use same configuration for both the data 84 ;; and the instruction MMU. 85 ;; 86 ;; Note; 3 cycles is needed for a bank-select to take effect. Further; 87 ;; bank 1 is the instruction MMU, bank 2 is the data MMU. 88#ifndef CONFIG_ETRAXFS_SIM 89 move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ 90 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ 91 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 92#else 93 ;; Map the virtual DRAM to the RW eprom area at address 0. 94 ;; Also map 0xa for the hook calls, 95 move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ 96 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0) \ 97 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \ 98 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0 99#endif 100 101 ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00. 102 move.d REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4) \ 103 | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1 104 105 ;; Enable certain page protections and setup linear mapping 106 ;; for f,e,c,b,4,0. 107#ifndef CONFIG_ETRAXFS_SIM 108 move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ 109 | REG_STATE(mmu, rw_mm_cfg, acc, on) \ 110 | REG_STATE(mmu, rw_mm_cfg, ex, on) \ 111 | REG_STATE(mmu, rw_mm_cfg, inv, on) \ 112 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \ 113 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \ 114 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \ 115 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ 116 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ 117 | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \ 118 | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ 119 | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ 120 | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ 121 | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ 122 | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ 123 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ 124 | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ 125 | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ 126 | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ 127 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 128#else 129 move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ 130 | REG_STATE(mmu, rw_mm_cfg, acc, on) \ 131 | REG_STATE(mmu, rw_mm_cfg, ex, on) \ 132 | REG_STATE(mmu, rw_mm_cfg, inv, on) \ 133 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \ 134 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \ 135 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \ 136 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ 137 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ 138 | REG_STATE(mmu, rw_mm_cfg, seg_a, linear) \ 139 | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ 140 | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ 141 | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ 142 | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ 143 | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ 144 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ 145 | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ 146 | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ 147 | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ 148 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 149#endif 150 151 ;; Update instruction MMU. 152 move 1, $srs 153 nop 154 nop 155 nop 156 move $r0, $s2 ; kbase_hi. 157 move $r1, $s1 ; kbase_lo. 158 move $r2, $s0 ; mm_cfg, virtual memory configuration. 159 160 ;; Update data MMU. 161 move 2, $srs 162 nop 163 nop 164 nop 165 move $r0, $s2 ; kbase_hi. 166 move $r1, $s1 ; kbase_lo 167 move $r2, $s0 ; mm_cfg, virtual memory configuration. 168 169 ;; Enable data and instruction MMU. 170 move 0, $srs 171 moveq 0xf, $r0 ; IMMU, DMMU, DCache, Icache on 172 nop 173 nop 174 nop 175 move $r0, $s0 176 nop 177 nop 178 nop 179 180#ifdef CONFIG_SMP 181 ;; Read CPU ID 182 move 0, $srs 183 nop 184 nop 185 nop 186 move $s10, $r0 187 cmpq 0, $r0 188 beq master_cpu 189 nop 190slave_cpu: 191 ; A slave waits for cpu_now_booting to be equal to CPU ID. 192 move.d cpu_now_booting, $r1 193slave_wait: 194 cmp.d [$r1], $r0 195 bne slave_wait 196 nop 197 ; Time to boot-up. Get stack location provided by master CPU. 198 move.d smp_init_current_idle_thread, $r1 199 move.d [$r1], $sp 200 add.d 8192, $sp 201 move.d ebp_start, $r0 ; Defined in linker-script. 202 move $r0, $ebp 203 jsr smp_callin 204 nop 205master_cpu: 206#endif 207#ifndef CONFIG_ETRAXFS_SIM 208 ;; Check if starting from DRAM or flash. 209 lapcq ., $r0 210 and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. 211 cmp.d 0x10000, $r0 ; Arbitrary, something above this code. 212 blo _inflash0 213 nop 214#endif 215 216 jump _inram ; Jump to cached RAM. 217 nop 218 219 ;; Jumpgate. 220_inflash0: 221 jump _inflash 222 nop 223 224 ;; Put the following in a section so that storage for it can be 225 ;; reclaimed after init is finished. 226 .section ".init.text", "ax" 227 228_inflash: 229 230 ;; Initialize DRAM. 231 cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? 232 beq _dram_initialized 233 nop 234 235#include "../lib/dram_init.S" 236 237_dram_initialized: 238 ;; Copy the text and data section to DRAM. This depends on that the 239 ;; variables used below are correctly set up by the linker script. 240 ;; The calculated value stored in R4 is used below. 241 moveq 0, $r0 ; Source. 242 move.d text_start, $r1 ; Destination. 243 move.d __vmlinux_end, $r2 244 move.d $r2, $r4 245 sub.d $r1, $r4 2461: move.w [$r0+], $r3 247 move.w $r3, [$r1+] 248 cmp.d $r2, $r1 249 blo 1b 250 nop 251 252 ;; Keep CRAMFS in flash. 253 moveq 0, $r0 254 move.d romfs_length, $r1 255 move.d $r0, [$r1] 256 move.d [$r4], $r0 ; cramfs_super.magic 257 cmp.d CRAMFS_MAGIC, $r0 258 bne 1f 259 nop 260 261 addoq +4, $r4, $acr 262 move.d [$acr], $r0 263 move.d romfs_length, $r1 264 move.d $r0, [$r1] 265 add.d 0xf0000000, $r4 ; Add cached flash start in virtual memory. 266 move.d romfs_start, $r1 267 move.d $r4, [$r1] 2681: moveq 1, $r0 269 move.d romfs_in_flash, $r1 270 move.d $r0, [$r1] 271 272 jump _start_it ; Jump to cached code. 273 nop 274 275_inram: 276 ;; Check if booting from NAND flash (in that case we just remember the offset 277 ;; into the flash where cramfs should be). 278 move.d REG_ADDR(config, regi_config, r_bootsel), $r0 279 move.d [$r0], $r0 280 and.d REG_MASK(config, r_bootsel, boot_mode), $r0 281 cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 282 bne move_cramfs 283 moveq 1,$r0 284 move.d crisv32_nand_boot, $r1 285 move.d $r0, [$r1] 286 move.d crisv32_nand_cramfs_offset, $r1 287 move.d $r9, [$r1] 288 moveq 1, $r0 289 move.d romfs_in_flash, $r1 290 move.d $r0, [$r1] 291 jump _start_it 292 nop 293 294move_cramfs: 295 ;; Move the cramfs after BSS. 296 moveq 0, $r0 297 move.d romfs_length, $r1 298 move.d $r0, [$r1] 299 300#ifndef CONFIG_ETRAXFS_SIM 301 ;; The kernel could have been unpacked to DRAM by the loader, but 302 ;; the cramfs image could still be inte the flash immediately 303 ;; following the compressed kernel image. The loaded passes the address 304 ;; of the bute succeeding the last compressed byte in the flash in 305 ;; register R9 when starting the kernel. 306 cmp.d 0x0ffffff8, $r9 307 bhs _no_romfs_in_flash ; R9 points outside the flash area. 308 nop 309#else 310 ba _no_romfs_in_flash 311 nop 312#endif 313 move.d [$r9], $r0 ; cramfs_super.magic 314 cmp.d CRAMFS_MAGIC, $r0 315 bne _no_romfs_in_flash 316 nop 317 318 addoq +4, $r9, $acr 319 move.d [$acr], $r0 320 move.d romfs_length, $r1 321 move.d $r0, [$r1] 322 add.d 0xf0000000, $r9 ; Add cached flash start in virtual memory. 323 move.d romfs_start, $r1 324 move.d $r9, [$r1] 325 moveq 1, $r0 326 move.d romfs_in_flash, $r1 327 move.d $r0, [$r1] 328 329 jump _start_it ; Jump to cached code. 330 nop 331 332_no_romfs_in_flash: 333 ;; Look for cramfs. 334#ifndef CONFIG_ETRAXFS_SIM 335 move.d __vmlinux_end, $r0 336#else 337 move.d __end, $r0 338#endif 339 move.d [$r0], $r1 340 cmp.d CRAMFS_MAGIC, $r1 341 bne 2f 342 nop 343 344 addoq +4, $r0, $acr 345 move.d [$acr], $r2 346 move.d _end, $r1 347 move.d romfs_start, $r3 348 move.d $r1, [$r3] 349 move.d romfs_length, $r3 350 move.d $r2, [$r3] 351 352#ifndef CONFIG_ETRAXFS_SIM 353 add.d $r2, $r0 354 add.d $r2, $r1 355 356 lsrq 1, $r2 ; Size is in bytes, we copy words. 357 addq 1, $r2 3581: 359 move.w [$r0], $r3 360 move.w $r3, [$r1] 361 subq 2, $r0 362 subq 2, $r1 363 subq 1, $r2 364 bne 1b 365 nop 366#endif 367 3682: 369 moveq 0, $r0 370 move.d romfs_in_flash, $r1 371 move.d $r0, [$r1] 372 373 jump _start_it ; Jump to cached code. 374 nop 375 376_start_it: 377 378 ;; Check if kernel command line is supplied 379 cmp.d COMMAND_LINE_MAGIC, $r10 380 bne no_command_line 381 nop 382 383 move.d 256, $r13 384 move.d cris_command_line, $r10 385 or.d 0x80000000, $r11 ; Make it virtual 3861: 387 move.b [$r11+], $r12 388 move.b $r12, [$r10+] 389 subq 1, $r13 390 bne 1b 391 nop 392 393no_command_line: 394 395 ;; The kernel stack contains a task structure for each task. This 396 ;; the initial kernel stack is in the same page as the init_task, 397 ;; but starts at the top of the page, i.e. + 8192 bytes. 398 move.d init_thread_union + 8192, $sp 399 move.d ebp_start, $r0 ; Defined in linker-script. 400 move $r0, $ebp 401 move.d etrax_irv, $r1 ; Set the exception base register and pointer. 402 move.d $r0, [$r1] 403 404#ifndef CONFIG_ETRAXFS_SIM 405 ;; Clear the BSS region from _bss_start to _end. 406 move.d __bss_start, $r0 407 move.d _end, $r1 4081: clear.d [$r0+] 409 cmp.d $r1, $r0 410 blo 1b 411 nop 412#endif 413 414#ifdef CONFIG_ETRAXFS_SIM 415 /* Set the watchdog timeout to something big. Will be removed when */ 416 /* watchdog can be disabled with command line option */ 417 move.d 0x7fffffff, $r10 418 jsr CPU_WATCHDOG_TIMEOUT 419 nop 420#endif 421 422 ; Initialize registers to increase determinism 423 move.d __bss_start, $r0 424 movem [$r0], $r13 425 426 jump start_kernel ; Jump to start_kernel() in init/main.c. 427 nop 428 429 .data 430etrax_irv: 431 .dword 0 432romfs_start: 433 .dword 0 434romfs_length: 435 .dword 0 436romfs_in_flash: 437 .dword 0 438crisv32_nand_boot: 439 .dword 0 440crisv32_nand_cramfs_offset: 441 .dword 0 442 443swapper_pg_dir = 0xc0002000 444 445 .section ".init.data", "aw" 446 447#include "../lib/hw_settings.S" 448