1/* head.S: kernel entry point for FR-V kernel 2 * 3 * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/init.h> 13#include <linux/threads.h> 14#include <linux/linkage.h> 15#include <asm/thread_info.h> 16#include <asm/ptrace.h> 17#include <asm/page.h> 18#include <asm/spr-regs.h> 19#include <asm/mb86943a.h> 20#include <asm/cache.h> 21#include "head.inc" 22 23############################################################################### 24# 25# void _boot(unsigned long magic, char *command_line) __attribute__((noreturn)) 26# 27# - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel 28# command line string 29# 30############################################################################### 31 __HEAD 32 .balign 4 33 34 .globl _boot, __head_reference 35 .type _boot,@function 36_boot: 37__head_reference: 38 sethi.p %hi(LED_ADDR),gr30 39 setlo %lo(LED_ADDR),gr30 40 41 LEDS 0x0000 42 43 # calculate reference address for PC-relative stuff 44 call 0f 450: movsg lr,gr26 46 addi gr26,#__head_reference-0b,gr26 47 48 # invalidate and disable both of the caches and turn off the memory access checking 49 dcef @(gr0,gr0),1 50 bar 51 52 sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4 53 setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4 54 movsg hsr0,gr5 55 and gr4,gr5,gr5 56 movgs gr5,hsr0 57 movsg hsr0,gr5 58 59 LEDS 0x0001 60 61 icei @(gr0,gr0),1 62 dcei @(gr0,gr0),1 63 bar 64 65 # turn the instruction cache back on 66 sethi.p %hi(HSR0_ICE),gr4 67 setlo %lo(HSR0_ICE),gr4 68 movsg hsr0,gr5 69 or gr4,gr5,gr5 70 movgs gr5,hsr0 71 movsg hsr0,gr5 72 73 bar 74 75 LEDS 0x0002 76 77 # retrieve the parameters (including command line) before we overwrite them 78 sethi.p %hi(0xdead1eaf),gr7 79 setlo %lo(0xdead1eaf),gr7 80 subcc gr7,gr8,gr0,icc0 81 bne icc0,#0,__head_no_parameters 82 83 sethi.p %hi(redboot_command_line-1),gr6 84 setlo %lo(redboot_command_line-1),gr6 85 sethi.p %hi(__head_reference),gr4 86 setlo %lo(__head_reference),gr4 87 sub gr6,gr4,gr6 88 add.p gr6,gr26,gr6 89 subi gr9,#1,gr9 90 setlos.p #511,gr4 91 setlos #1,gr5 92 93__head_copy_cmdline: 94 ldubu.p @(gr9,gr5),gr16 95 subicc gr4,#1,gr4,icc0 96 stbu.p gr16,@(gr6,gr5) 97 subicc gr16,#0,gr0,icc1 98 bls icc0,#0,__head_end_cmdline 99 bne icc1,#1,__head_copy_cmdline 100__head_end_cmdline: 101 stbu gr0,@(gr6,gr5) 102__head_no_parameters: 103 104############################################################################### 105# 106# we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux) 107# - note that we're going to have to run entirely out of the icache whilst 108# fiddling with the SDRAM controller registers 109# 110############################################################################### 111#ifdef CONFIG_MMU 112 call __head_fr451_describe_sdram 113 114#else 115 movsg psr,gr5 116 srli gr5,#28,gr5 117 subicc gr5,#3,gr0,icc0 118 beq icc0,#0,__head_fr551_sdram 119 120 call __head_fr401_describe_sdram 121 bra __head_do_sdram 122 123__head_fr551_sdram: 124 call __head_fr555_describe_sdram 125 LEDS 0x000d 126 127__head_do_sdram: 128#endif 129 130 # preload the registers with invalid values in case any DBR/DARS are marked not present 131 sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value 132 setlo %lo(0xfe000000),gr17 133 or.p gr17,gr0,gr20 134 or gr17,gr0,gr21 135 or.p gr17,gr0,gr22 136 or gr17,gr0,gr23 137 138 # consult the SDRAM controller CS address registers 139 cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0 140 cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1 141 cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2 142 cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3 143 144 sll gr20,gr15,gr20 ; shift values up for FR551 145 sll gr21,gr15,gr21 146 sll gr22,gr15,gr22 147 sll gr23,gr15,gr23 148 149 LEDS 0x0003 150 151 # assume the lowest valid CS line to be the SDRAM base and get its address 152 subcc gr20,gr17,gr0,icc0 153 subcc.p gr21,gr17,gr0,icc1 154 subcc gr22,gr17,gr0,icc2 155 subcc.p gr23,gr17,gr0,icc3 156 ckne icc0,cc4 ; T if DBR0 != 0xfe000000 157 ckne icc1,cc5 158 ckne icc2,cc6 159 ckne icc3,cc7 160 cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base 161 cor gr22,gr0,gr24, cc6,#1 162 cor gr21,gr0,gr24, cc5,#1 163 cor gr20,gr0,gr24, cc4,#1 164 165 # calculate the displacement required to get the SDRAM into the right place in memory 166 sethi.p %hi(__sdram_base),gr16 167 setlo %lo(__sdram_base),gr16 168 sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx 169 170 # calculate the new values to go in the controller regs 171 cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta 172 cadd gr21,gr16,gr21, cc5,#1 173 cadd.p gr22,gr16,gr22, cc6,#1 174 cadd gr23,gr16,gr23, cc7,#1 175 176 srl gr20,gr15,gr20 ; shift values down for FR551 177 srl gr21,gr15,gr21 178 srl gr22,gr15,gr22 179 srl gr23,gr15,gr23 180 181 # work out the address at which the reg updater resides and lock it into icache 182 # also work out the address the updater will jump to when finished 183 sethi.p %hi(__head_move_sdram-__head_reference),gr18 184 setlo %lo(__head_move_sdram-__head_reference),gr18 185 sethi.p %hi(__head_sdram_moved-__head_reference),gr19 186 setlo %lo(__head_sdram_moved-__head_reference),gr19 187 add.p gr18,gr26,gr18 188 add gr19,gr26,gr19 189 add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx) 190 add gr18,gr5,gr4 ; two cachelines probably required 191 192 icpl gr18,gr0,#1 ; load and lock the cachelines 193 icpl gr4,gr0,#1 194 LEDS 0x0004 195 membar 196 bar 197 jmpl @(gr18,gr0) 198 199 .balign L1_CACHE_BYTES 200__head_move_sdram: 201 cst gr20,@(gr14,gr0 ), cc4,#1 202 cst gr21,@(gr14,gr11), cc5,#1 203 cst gr22,@(gr14,gr12), cc6,#1 204 cst gr23,@(gr14,gr13), cc7,#1 205 cld @(gr14,gr0 ),gr20, cc4,#1 206 cld @(gr14,gr11),gr21, cc5,#1 207 cld @(gr14,gr12),gr22, cc4,#1 208 cld @(gr14,gr13),gr23, cc7,#1 209 bar 210 membar 211 jmpl @(gr19,gr0) 212 213 .balign L1_CACHE_BYTES 214__head_sdram_moved: 215 icul gr18 216 add gr18,gr5,gr4 217 icul gr4 218 icei @(gr0,gr0),1 219 dcei @(gr0,gr0),1 220 221 LEDS 0x0005 222 223 # recalculate reference address 224 call 0f 2250: movsg lr,gr26 226 addi gr26,#__head_reference-0b,gr26 227 228 229############################################################################### 230# 231# move the kernel image down to the bottom of the SDRAM 232# 233############################################################################### 234 sethi.p %hi(__kernel_image_size_no_bss+15),gr4 235 setlo %lo(__kernel_image_size_no_bss+15),gr4 236 srli.p gr4,#4,gr4 ; count 237 or gr26,gr26,gr16 ; source 238 239 sethi.p %hi(__sdram_base),gr17 ; destination 240 setlo %lo(__sdram_base),gr17 241 242 setlos #8,gr5 243 sub.p gr16,gr5,gr16 ; adjust src for LDDU 244 sub gr17,gr5,gr17 ; adjust dst for LDDU 245 246 sethi.p %hi(__head_move_kernel-__head_reference),gr18 247 setlo %lo(__head_move_kernel-__head_reference),gr18 248 sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19 249 setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19 250 add gr18,gr26,gr18 251 icpl gr18,gr0,#1 252 jmpl @(gr18,gr0) 253 254 .balign 32 255__head_move_kernel: 256 lddu @(gr16,gr5),gr10 257 lddu @(gr16,gr5),gr12 258 stdu.p gr10,@(gr17,gr5) 259 subicc gr4,#1,gr4,icc0 260 stdu.p gr12,@(gr17,gr5) 261 bhi icc0,#0,__head_move_kernel 262 jmpl @(gr19,gr0) 263 264 .balign 32 265__head_kernel_moved: 266 icul gr18 267 icei @(gr0,gr0),1 268 dcei @(gr0,gr0),1 269 270 LEDS 0x0006 271 272 # recalculate reference address 273 call 0f 2740: movsg lr,gr26 275 addi gr26,#__head_reference-0b,gr26 276 277 278############################################################################### 279# 280# rearrange the iomem map and set the protection registers 281# 282############################################################################### 283 284#ifdef CONFIG_MMU 285 LEDS 0x3301 286 call __head_fr451_set_busctl 287 LEDS 0x3303 288 call __head_fr451_survey_sdram 289 LEDS 0x3305 290 call __head_fr451_set_protection 291 292#else 293 movsg psr,gr5 294 srli gr5,#PSR_IMPLE_SHIFT,gr5 295 subicc gr5,#PSR_IMPLE_FR551,gr0,icc0 296 beq icc0,#0,__head_fr555_memmap 297 subicc gr5,#PSR_IMPLE_FR451,gr0,icc0 298 beq icc0,#0,__head_fr451_memmap 299 300 LEDS 0x3101 301 call __head_fr401_set_busctl 302 LEDS 0x3103 303 call __head_fr401_survey_sdram 304 LEDS 0x3105 305 call __head_fr401_set_protection 306 bra __head_done_memmap 307 308__head_fr451_memmap: 309 LEDS 0x3301 310 call __head_fr401_set_busctl 311 LEDS 0x3303 312 call __head_fr401_survey_sdram 313 LEDS 0x3305 314 call __head_fr451_set_protection 315 bra __head_done_memmap 316 317__head_fr555_memmap: 318 LEDS 0x3501 319 call __head_fr555_set_busctl 320 LEDS 0x3503 321 call __head_fr555_survey_sdram 322 LEDS 0x3505 323 call __head_fr555_set_protection 324 325__head_done_memmap: 326#endif 327 LEDS 0x0007 328 329############################################################################### 330# 331# turn the data cache and MMU on 332# - for the FR451 this'll mean that the window through which the kernel is 333# viewed will change 334# 335############################################################################### 336 337#ifdef CONFIG_MMU 338#define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT 339#else 340#define MMUMODE HSR0_EIMMU|HSR0_EDMMU 341#endif 342 343 movsg hsr0,gr5 344 345 sethi.p %hi(MMUMODE),gr4 346 setlo %lo(MMUMODE),gr4 347 or gr4,gr5,gr5 348 349#if defined(CONFIG_FRV_DEFL_CACHE_WTHRU) 350 sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4 351 setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4 352#elif defined(CONFIG_FRV_DEFL_CACHE_WBACK) 353 sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4 354 setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4 355#elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND) 356 sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4 357 setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4 358 359 movsg psr,gr6 360 srli gr6,#24,gr6 361 cmpi gr6,#0x50,icc0 // FR451 362 beq icc0,#0,0f 363 cmpi gr6,#0x40,icc0 // FR405 364 bne icc0,#0,1f 3650: 366 # turn off write-allocate 367 sethi.p %hi(HSR0_NWA),gr6 368 setlo %lo(HSR0_NWA),gr6 369 or gr4,gr6,gr4 3701: 371 372#else 373#error No default cache configuration set 374#endif 375 376 or gr4,gr5,gr5 377 movgs gr5,hsr0 378 bar 379 380 LEDS 0x0008 381 382 sethi.p %hi(__head_mmu_enabled),gr19 383 setlo %lo(__head_mmu_enabled),gr19 384 jmpl @(gr19,gr0) 385 386__head_mmu_enabled: 387 icei @(gr0,gr0),#1 388 dcei @(gr0,gr0),#1 389 390 LEDS 0x0009 391 392#ifdef CONFIG_MMU 393 call __head_fr451_finalise_protection 394#endif 395 396 LEDS 0x000a 397 398############################################################################### 399# 400# set up the runtime environment 401# 402############################################################################### 403 404 # clear the BSS area 405 sethi.p %hi(__bss_start),gr4 406 setlo %lo(__bss_start),gr4 407 sethi.p %hi(_end),gr5 408 setlo %lo(_end),gr5 409 or.p gr0,gr0,gr18 410 or gr0,gr0,gr19 411 4120: 413 stdi gr18,@(gr4,#0) 414 stdi gr18,@(gr4,#8) 415 stdi gr18,@(gr4,#16) 416 stdi.p gr18,@(gr4,#24) 417 addi gr4,#24,gr4 418 subcc gr5,gr4,gr0,icc0 419 bhi icc0,#2,0b 420 421 LEDS 0x000b 422 423 # save the SDRAM details 424 sethi.p %hi(__sdram_old_base),gr4 425 setlo %lo(__sdram_old_base),gr4 426 st gr24,@(gr4,gr0) 427 428 sethi.p %hi(__sdram_base),gr5 429 setlo %lo(__sdram_base),gr5 430 sethi.p %hi(memory_start),gr4 431 setlo %lo(memory_start),gr4 432 st gr5,@(gr4,gr0) 433 434 add gr25,gr5,gr25 435 sethi.p %hi(memory_end),gr4 436 setlo %lo(memory_end),gr4 437 st gr25,@(gr4,gr0) 438 439 # point the TBR at the kernel trap table 440 sethi.p %hi(__entry_kerneltrap_table),gr4 441 setlo %lo(__entry_kerneltrap_table),gr4 442 movgs gr4,tbr 443 444 # set up the exception frame for init 445 sethi.p %hi(__kernel_frame0_ptr),gr28 446 setlo %lo(__kernel_frame0_ptr),gr28 447 sethi.p %hi(_gp),gr16 448 setlo %lo(_gp),gr16 449 sethi.p %hi(__entry_usertrap_table),gr4 450 setlo %lo(__entry_usertrap_table),gr4 451 452 lddi @(gr28,#0),gr28 ; load __frame & current 453 ldi.p @(gr29,#4),gr15 ; set current_thread 454 455 or gr0,gr0,fp 456 or gr28,gr0,sp 457 458 sti.p gr4,@(gr28,REG_TBR) 459 setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5 460 movgs gr5,isr 461 462 # turn on and off various CPU services 463 movsg psr,gr22 464 sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4 465 setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4 466 or gr22,gr4,gr22 467 movgs gr22,psr 468 469 andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22 470 ori gr22,#PSR_ET,gr22 471 sti gr22,@(gr28,REG_PSR) 472 473 474############################################################################### 475# 476# set up the registers and jump into the kernel 477# 478############################################################################### 479 480 LEDS 0x000c 481 482 # initialise the processor and the peripherals 483 #call SYMBOL_NAME(processor_init) 484 #call SYMBOL_NAME(unit_init) 485 #LEDS 0x0aff 486 487 sethi.p #0xe5e5,gr3 488 setlo #0xe5e5,gr3 489 or.p gr3,gr0,gr4 490 or gr3,gr0,gr5 491 or.p gr3,gr0,gr6 492 or gr3,gr0,gr7 493 or.p gr3,gr0,gr8 494 or gr3,gr0,gr9 495 or.p gr3,gr0,gr10 496 or gr3,gr0,gr11 497 or.p gr3,gr0,gr12 498 or gr3,gr0,gr13 499 or.p gr3,gr0,gr14 500 or gr3,gr0,gr17 501 or.p gr3,gr0,gr18 502 or gr3,gr0,gr19 503 or.p gr3,gr0,gr20 504 or gr3,gr0,gr21 505 or.p gr3,gr0,gr23 506 or gr3,gr0,gr24 507 or.p gr3,gr0,gr25 508 or gr3,gr0,gr26 509 or.p gr3,gr0,gr27 510# or gr3,gr0,gr30 511 or gr3,gr0,gr31 512 movgs gr0,lr 513 movgs gr0,lcr 514 movgs gr0,ccr 515 movgs gr0,cccr 516 517 # initialise the virtual interrupt handling 518 subcc gr0,gr0,gr0,icc2 /* set Z, clear C */ 519 520#ifdef CONFIG_MMU 521 movgs gr3,scr2 522 movgs gr3,scr3 523#endif 524 525 LEDS 0x0fff 526 527 # invoke the debugging stub if present 528 # - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c 529 # (it will not return here) 530 break 531 .globl __debug_stub_init_break 532__debug_stub_init_break: 533 534 # however, if you need to use an ICE, and don't care about using any userspace 535 # debugging tools (such as the ptrace syscall), you can just step over the break 536 # above and get to the kernel this way 537 # look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed 538 call start_kernel 539 540 .globl __head_end 541__head_end: 542 .size _boot, .-_boot 543 544 # provide a point for GDB to place a break 545 .section .text..start,"ax" 546 .globl _start 547 .balign 4 548_start: 549 call _boot 550 551 .previous 552############################################################################### 553# 554# split a tile off of the region defined by GR8-GR9 555# 556# ENTRY: EXIT: 557# GR4 - IAMPR value representing tile 558# GR5 - DAMPR value representing tile 559# GR6 - IAMLR value representing tile 560# GR7 - DAMLR value representing tile 561# GR8 region base pointer [saved] 562# GR9 region top pointer updated to exclude new tile 563# GR11 xAMLR mask [saved] 564# GR25 SDRAM size [saved] 565# GR30 LED address [saved] 566# 567# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling 568# 569############################################################################### 570 .globl __head_split_region 571 .type __head_split_region,@function 572__head_split_region: 573 subcc.p gr9,gr8,gr4,icc0 574 setlos #31,gr5 575 scan.p gr4,gr0,gr6 576 beq icc0,#0,__head_region_empty 577 sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20) 578 setlos #1,gr4 579 sll.p gr4,gr6,gr4 ; size of region (1 << bitno) 580 subi gr6,#17,gr6 ; 1MB => 0x03 581 slli.p gr6,#4,gr6 ; 1MB => 0x30 582 sub gr9,gr4,gr9 ; move uncovered top down 583 584 or gr9,gr6,gr4 585 ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4 586 or.p gr4,gr0,gr5 587 588 and gr4,gr11,gr6 589 and.p gr5,gr11,gr7 590 bralr 591 592__head_region_empty: 593 or.p gr0,gr0,gr4 594 or gr0,gr0,gr5 595 or.p gr0,gr0,gr6 596 or gr0,gr0,gr7 597 bralr 598 .size __head_split_region, .-__head_split_region 599 600############################################################################### 601# 602# write the 32-bit hex number in GR8 to ttyS0 603# 604############################################################################### 605#if 0 606 .globl __head_write_to_ttyS0 607 .type __head_write_to_ttyS0,@function 608__head_write_to_ttyS0: 609 sethi.p %hi(0xfeff9c00),gr31 610 setlo %lo(0xfeff9c00),gr31 611 setlos #8,gr20 612 6130: ldubi @(gr31,#5*8),gr21 614 andi gr21,#0x60,gr21 615 subicc gr21,#0x60,gr21,icc0 616 bne icc0,#0,0b 617 6181: srli gr8,#28,gr21 619 slli gr8,#4,gr8 620 621 addi gr21,#'0',gr21 622 subicc gr21,#'9',gr0,icc0 623 bls icc0,#2,2f 624 addi gr21,#'A'-'0'-10,gr21 6252: 626 stbi gr21,@(gr31,#0*8) 627 subicc gr20,#1,gr20,icc0 628 bhi icc0,#2,1b 629 630 setlos #'\r',gr21 631 stbi gr21,@(gr31,#0*8) 632 633 setlos #'\n',gr21 634 stbi gr21,@(gr31,#0*8) 635 6363: ldubi @(gr31,#5*8),gr21 637 andi gr21,#0x60,gr21 638 subicc gr21,#0x60,gr21,icc0 639 bne icc0,#0,3b 640 bralr 641 642 .size __head_write_to_ttyS0, .-__head_write_to_ttyS0 643#endif 644