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 sethi.p #0xe5e5,gr3 483 setlo #0xe5e5,gr3 484 or.p gr3,gr0,gr4 485 or gr3,gr0,gr5 486 or.p gr3,gr0,gr6 487 or gr3,gr0,gr7 488 or.p gr3,gr0,gr8 489 or gr3,gr0,gr9 490 or.p gr3,gr0,gr10 491 or gr3,gr0,gr11 492 or.p gr3,gr0,gr12 493 or gr3,gr0,gr13 494 or.p gr3,gr0,gr14 495 or gr3,gr0,gr17 496 or.p gr3,gr0,gr18 497 or gr3,gr0,gr19 498 or.p gr3,gr0,gr20 499 or gr3,gr0,gr21 500 or.p gr3,gr0,gr23 501 or gr3,gr0,gr24 502 or.p gr3,gr0,gr25 503 or gr3,gr0,gr26 504 or.p gr3,gr0,gr27 505# or gr3,gr0,gr30 506 or gr3,gr0,gr31 507 movgs gr0,lr 508 movgs gr0,lcr 509 movgs gr0,ccr 510 movgs gr0,cccr 511 512 # initialise the virtual interrupt handling 513 subcc gr0,gr0,gr0,icc2 /* set Z, clear C */ 514 515#ifdef CONFIG_MMU 516 movgs gr3,scr2 517 movgs gr3,scr3 518#endif 519 520 LEDS 0x0fff 521 522 # invoke the debugging stub if present 523 # - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c 524 # (it will not return here) 525 break 526 .globl __debug_stub_init_break 527__debug_stub_init_break: 528 529 # however, if you need to use an ICE, and don't care about using any userspace 530 # debugging tools (such as the ptrace syscall), you can just step over the break 531 # above and get to the kernel this way 532 # look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed 533 call start_kernel 534 535 .globl __head_end 536__head_end: 537 .size _boot, .-_boot 538 539 # provide a point for GDB to place a break 540 .section .text..start,"ax" 541 .globl _start 542 .balign 4 543_start: 544 call _boot 545 546 .previous 547############################################################################### 548# 549# split a tile off of the region defined by GR8-GR9 550# 551# ENTRY: EXIT: 552# GR4 - IAMPR value representing tile 553# GR5 - DAMPR value representing tile 554# GR6 - IAMLR value representing tile 555# GR7 - DAMLR value representing tile 556# GR8 region base pointer [saved] 557# GR9 region top pointer updated to exclude new tile 558# GR11 xAMLR mask [saved] 559# GR25 SDRAM size [saved] 560# GR30 LED address [saved] 561# 562# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling 563# 564############################################################################### 565 .globl __head_split_region 566 .type __head_split_region,@function 567__head_split_region: 568 subcc.p gr9,gr8,gr4,icc0 569 setlos #31,gr5 570 scan.p gr4,gr0,gr6 571 beq icc0,#0,__head_region_empty 572 sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20) 573 setlos #1,gr4 574 sll.p gr4,gr6,gr4 ; size of region (1 << bitno) 575 subi gr6,#17,gr6 ; 1MB => 0x03 576 slli.p gr6,#4,gr6 ; 1MB => 0x30 577 sub gr9,gr4,gr9 ; move uncovered top down 578 579 or gr9,gr6,gr4 580 ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4 581 or.p gr4,gr0,gr5 582 583 and gr4,gr11,gr6 584 and.p gr5,gr11,gr7 585 bralr 586 587__head_region_empty: 588 or.p gr0,gr0,gr4 589 or gr0,gr0,gr5 590 or.p gr0,gr0,gr6 591 or gr0,gr0,gr7 592 bralr 593 .size __head_split_region, .-__head_split_region 594 595############################################################################### 596# 597# write the 32-bit hex number in GR8 to ttyS0 598# 599############################################################################### 600#if 0 601 .globl __head_write_to_ttyS0 602 .type __head_write_to_ttyS0,@function 603__head_write_to_ttyS0: 604 sethi.p %hi(0xfeff9c00),gr31 605 setlo %lo(0xfeff9c00),gr31 606 setlos #8,gr20 607 6080: ldubi @(gr31,#5*8),gr21 609 andi gr21,#0x60,gr21 610 subicc gr21,#0x60,gr21,icc0 611 bne icc0,#0,0b 612 6131: srli gr8,#28,gr21 614 slli gr8,#4,gr8 615 616 addi gr21,#'0',gr21 617 subicc gr21,#'9',gr0,icc0 618 bls icc0,#2,2f 619 addi gr21,#'A'-'0'-10,gr21 6202: 621 stbi gr21,@(gr31,#0*8) 622 subicc gr20,#1,gr20,icc0 623 bhi icc0,#2,1b 624 625 setlos #'\r',gr21 626 stbi gr21,@(gr31,#0*8) 627 628 setlos #'\n',gr21 629 stbi gr21,@(gr31,#0*8) 630 6313: ldubi @(gr31,#5*8),gr21 632 andi gr21,#0x60,gr21 633 subicc gr21,#0x60,gr21,icc0 634 bne icc0,#0,3b 635 bralr 636 637 .size __head_write_to_ttyS0, .-__head_write_to_ttyS0 638#endif 639