123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- /* head.S: kernel entry point for FR-V kernel
- *
- * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
- #include <linux/init.h>
- #include <linux/threads.h>
- #include <linux/linkage.h>
- #include <asm/thread_info.h>
- #include <asm/ptrace.h>
- #include <asm/page.h>
- #include <asm/spr-regs.h>
- #include <asm/mb86943a.h>
- #include <asm/cache.h>
- #include "head.inc"
- ###############################################################################
- #
- # void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))
- #
- # - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel
- # command line string
- #
- ###############################################################################
- __HEAD
- .balign 4
- .globl _boot, __head_reference
- .type _boot,@function
- _boot:
- __head_reference:
- sethi.p %hi(LED_ADDR),gr30
- setlo %lo(LED_ADDR),gr30
- LEDS 0x0000
- # calculate reference address for PC-relative stuff
- call 0f
- 0: movsg lr,gr26
- addi gr26,#__head_reference-0b,gr26
- # invalidate and disable both of the caches and turn off the memory access checking
- dcef @(gr0,gr0),1
- bar
- sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
- setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr4
- movsg hsr0,gr5
- and gr4,gr5,gr5
- movgs gr5,hsr0
- movsg hsr0,gr5
- LEDS 0x0001
- icei @(gr0,gr0),1
- dcei @(gr0,gr0),1
- bar
- # turn the instruction cache back on
- sethi.p %hi(HSR0_ICE),gr4
- setlo %lo(HSR0_ICE),gr4
- movsg hsr0,gr5
- or gr4,gr5,gr5
- movgs gr5,hsr0
- movsg hsr0,gr5
- bar
- LEDS 0x0002
- # retrieve the parameters (including command line) before we overwrite them
- sethi.p %hi(0xdead1eaf),gr7
- setlo %lo(0xdead1eaf),gr7
- subcc gr7,gr8,gr0,icc0
- bne icc0,#0,__head_no_parameters
- sethi.p %hi(redboot_command_line-1),gr6
- setlo %lo(redboot_command_line-1),gr6
- sethi.p %hi(__head_reference),gr4
- setlo %lo(__head_reference),gr4
- sub gr6,gr4,gr6
- add.p gr6,gr26,gr6
- subi gr9,#1,gr9
- setlos.p #511,gr4
- setlos #1,gr5
- __head_copy_cmdline:
- ldubu.p @(gr9,gr5),gr16
- subicc gr4,#1,gr4,icc0
- stbu.p gr16,@(gr6,gr5)
- subicc gr16,#0,gr0,icc1
- bls icc0,#0,__head_end_cmdline
- bne icc1,#1,__head_copy_cmdline
- __head_end_cmdline:
- stbu gr0,@(gr6,gr5)
- __head_no_parameters:
- ###############################################################################
- #
- # we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)
- # - note that we're going to have to run entirely out of the icache whilst
- # fiddling with the SDRAM controller registers
- #
- ###############################################################################
- #ifdef CONFIG_MMU
- call __head_fr451_describe_sdram
- #else
- movsg psr,gr5
- srli gr5,#28,gr5
- subicc gr5,#3,gr0,icc0
- beq icc0,#0,__head_fr551_sdram
- call __head_fr401_describe_sdram
- bra __head_do_sdram
- __head_fr551_sdram:
- call __head_fr555_describe_sdram
- LEDS 0x000d
- __head_do_sdram:
- #endif
- # preload the registers with invalid values in case any DBR/DARS are marked not present
- sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value
- setlo %lo(0xfe000000),gr17
- or.p gr17,gr0,gr20
- or gr17,gr0,gr21
- or.p gr17,gr0,gr22
- or gr17,gr0,gr23
- # consult the SDRAM controller CS address registers
- cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0
- cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1
- cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2
- cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3
- sll gr20,gr15,gr20 ; shift values up for FR551
- sll gr21,gr15,gr21
- sll gr22,gr15,gr22
- sll gr23,gr15,gr23
- LEDS 0x0003
- # assume the lowest valid CS line to be the SDRAM base and get its address
- subcc gr20,gr17,gr0,icc0
- subcc.p gr21,gr17,gr0,icc1
- subcc gr22,gr17,gr0,icc2
- subcc.p gr23,gr17,gr0,icc3
- ckne icc0,cc4 ; T if DBR0 != 0xfe000000
- ckne icc1,cc5
- ckne icc2,cc6
- ckne icc3,cc7
- cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base
- cor gr22,gr0,gr24, cc6,#1
- cor gr21,gr0,gr24, cc5,#1
- cor gr20,gr0,gr24, cc4,#1
- # calculate the displacement required to get the SDRAM into the right place in memory
- sethi.p %hi(__sdram_base),gr16
- setlo %lo(__sdram_base),gr16
- sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx
- # calculate the new values to go in the controller regs
- cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta
- cadd gr21,gr16,gr21, cc5,#1
- cadd.p gr22,gr16,gr22, cc6,#1
- cadd gr23,gr16,gr23, cc7,#1
- srl gr20,gr15,gr20 ; shift values down for FR551
- srl gr21,gr15,gr21
- srl gr22,gr15,gr22
- srl gr23,gr15,gr23
- # work out the address at which the reg updater resides and lock it into icache
- # also work out the address the updater will jump to when finished
- sethi.p %hi(__head_move_sdram-__head_reference),gr18
- setlo %lo(__head_move_sdram-__head_reference),gr18
- sethi.p %hi(__head_sdram_moved-__head_reference),gr19
- setlo %lo(__head_sdram_moved-__head_reference),gr19
- add.p gr18,gr26,gr18
- add gr19,gr26,gr19
- add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx)
- add gr18,gr5,gr4 ; two cachelines probably required
- icpl gr18,gr0,#1 ; load and lock the cachelines
- icpl gr4,gr0,#1
- LEDS 0x0004
- membar
- bar
- jmpl @(gr18,gr0)
- .balign L1_CACHE_BYTES
- __head_move_sdram:
- cst gr20,@(gr14,gr0 ), cc4,#1
- cst gr21,@(gr14,gr11), cc5,#1
- cst gr22,@(gr14,gr12), cc6,#1
- cst gr23,@(gr14,gr13), cc7,#1
- cld @(gr14,gr0 ),gr20, cc4,#1
- cld @(gr14,gr11),gr21, cc5,#1
- cld @(gr14,gr12),gr22, cc4,#1
- cld @(gr14,gr13),gr23, cc7,#1
- bar
- membar
- jmpl @(gr19,gr0)
- .balign L1_CACHE_BYTES
- __head_sdram_moved:
- icul gr18
- add gr18,gr5,gr4
- icul gr4
- icei @(gr0,gr0),1
- dcei @(gr0,gr0),1
- LEDS 0x0005
- # recalculate reference address
- call 0f
- 0: movsg lr,gr26
- addi gr26,#__head_reference-0b,gr26
- ###############################################################################
- #
- # move the kernel image down to the bottom of the SDRAM
- #
- ###############################################################################
- sethi.p %hi(__kernel_image_size_no_bss+15),gr4
- setlo %lo(__kernel_image_size_no_bss+15),gr4
- srli.p gr4,#4,gr4 ; count
- or gr26,gr26,gr16 ; source
- sethi.p %hi(__sdram_base),gr17 ; destination
- setlo %lo(__sdram_base),gr17
- setlos #8,gr5
- sub.p gr16,gr5,gr16 ; adjust src for LDDU
- sub gr17,gr5,gr17 ; adjust dst for LDDU
- sethi.p %hi(__head_move_kernel-__head_reference),gr18
- setlo %lo(__head_move_kernel-__head_reference),gr18
- sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19
- setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19
- add gr18,gr26,gr18
- icpl gr18,gr0,#1
- jmpl @(gr18,gr0)
- .balign 32
- __head_move_kernel:
- lddu @(gr16,gr5),gr10
- lddu @(gr16,gr5),gr12
- stdu.p gr10,@(gr17,gr5)
- subicc gr4,#1,gr4,icc0
- stdu.p gr12,@(gr17,gr5)
- bhi icc0,#0,__head_move_kernel
- jmpl @(gr19,gr0)
- .balign 32
- __head_kernel_moved:
- icul gr18
- icei @(gr0,gr0),1
- dcei @(gr0,gr0),1
- LEDS 0x0006
- # recalculate reference address
- call 0f
- 0: movsg lr,gr26
- addi gr26,#__head_reference-0b,gr26
- ###############################################################################
- #
- # rearrange the iomem map and set the protection registers
- #
- ###############################################################################
- #ifdef CONFIG_MMU
- LEDS 0x3301
- call __head_fr451_set_busctl
- LEDS 0x3303
- call __head_fr451_survey_sdram
- LEDS 0x3305
- call __head_fr451_set_protection
- #else
- movsg psr,gr5
- srli gr5,#PSR_IMPLE_SHIFT,gr5
- subicc gr5,#PSR_IMPLE_FR551,gr0,icc0
- beq icc0,#0,__head_fr555_memmap
- subicc gr5,#PSR_IMPLE_FR451,gr0,icc0
- beq icc0,#0,__head_fr451_memmap
- LEDS 0x3101
- call __head_fr401_set_busctl
- LEDS 0x3103
- call __head_fr401_survey_sdram
- LEDS 0x3105
- call __head_fr401_set_protection
- bra __head_done_memmap
- __head_fr451_memmap:
- LEDS 0x3301
- call __head_fr401_set_busctl
- LEDS 0x3303
- call __head_fr401_survey_sdram
- LEDS 0x3305
- call __head_fr451_set_protection
- bra __head_done_memmap
- __head_fr555_memmap:
- LEDS 0x3501
- call __head_fr555_set_busctl
- LEDS 0x3503
- call __head_fr555_survey_sdram
- LEDS 0x3505
- call __head_fr555_set_protection
- __head_done_memmap:
- #endif
- LEDS 0x0007
- ###############################################################################
- #
- # turn the data cache and MMU on
- # - for the FR451 this'll mean that the window through which the kernel is
- # viewed will change
- #
- ###############################################################################
- #ifdef CONFIG_MMU
- #define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT
- #else
- #define MMUMODE HSR0_EIMMU|HSR0_EDMMU
- #endif
- movsg hsr0,gr5
- sethi.p %hi(MMUMODE),gr4
- setlo %lo(MMUMODE),gr4
- or gr4,gr5,gr5
- #if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)
- sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
- setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4
- #elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)
- sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
- setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
- #elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)
- sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
- setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4
- movsg psr,gr6
- srli gr6,#24,gr6
- cmpi gr6,#0x50,icc0 // FR451
- beq icc0,#0,0f
- cmpi gr6,#0x40,icc0 // FR405
- bne icc0,#0,1f
- 0:
- # turn off write-allocate
- sethi.p %hi(HSR0_NWA),gr6
- setlo %lo(HSR0_NWA),gr6
- or gr4,gr6,gr4
- 1:
- #else
- #error No default cache configuration set
- #endif
- or gr4,gr5,gr5
- movgs gr5,hsr0
- bar
- LEDS 0x0008
- sethi.p %hi(__head_mmu_enabled),gr19
- setlo %lo(__head_mmu_enabled),gr19
- jmpl @(gr19,gr0)
- __head_mmu_enabled:
- icei @(gr0,gr0),#1
- dcei @(gr0,gr0),#1
- LEDS 0x0009
- #ifdef CONFIG_MMU
- call __head_fr451_finalise_protection
- #endif
- LEDS 0x000a
- ###############################################################################
- #
- # set up the runtime environment
- #
- ###############################################################################
- # clear the BSS area
- sethi.p %hi(__bss_start),gr4
- setlo %lo(__bss_start),gr4
- sethi.p %hi(_end),gr5
- setlo %lo(_end),gr5
- or.p gr0,gr0,gr18
- or gr0,gr0,gr19
- 0:
- stdi gr18,@(gr4,#0)
- stdi gr18,@(gr4,#8)
- stdi gr18,@(gr4,#16)
- stdi.p gr18,@(gr4,#24)
- addi gr4,#24,gr4
- subcc gr5,gr4,gr0,icc0
- bhi icc0,#2,0b
- LEDS 0x000b
- # save the SDRAM details
- sethi.p %hi(__sdram_old_base),gr4
- setlo %lo(__sdram_old_base),gr4
- st gr24,@(gr4,gr0)
- sethi.p %hi(__sdram_base),gr5
- setlo %lo(__sdram_base),gr5
- sethi.p %hi(memory_start),gr4
- setlo %lo(memory_start),gr4
- st gr5,@(gr4,gr0)
- add gr25,gr5,gr25
- sethi.p %hi(memory_end),gr4
- setlo %lo(memory_end),gr4
- st gr25,@(gr4,gr0)
- # point the TBR at the kernel trap table
- sethi.p %hi(__entry_kerneltrap_table),gr4
- setlo %lo(__entry_kerneltrap_table),gr4
- movgs gr4,tbr
- # set up the exception frame for init
- sethi.p %hi(__kernel_frame0_ptr),gr28
- setlo %lo(__kernel_frame0_ptr),gr28
- sethi.p %hi(_gp),gr16
- setlo %lo(_gp),gr16
- sethi.p %hi(__entry_usertrap_table),gr4
- setlo %lo(__entry_usertrap_table),gr4
- lddi @(gr28,#0),gr28 ; load __frame & current
- ldi.p @(gr29,#4),gr15 ; set current_thread
- or gr0,gr0,fp
- or gr28,gr0,sp
- sti.p gr4,@(gr28,REG_TBR)
- setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
- movgs gr5,isr
- # turn on and off various CPU services
- movsg psr,gr22
- sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
- setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4
- or gr22,gr4,gr22
- movgs gr22,psr
- andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22
- ori gr22,#PSR_ET,gr22
- sti gr22,@(gr28,REG_PSR)
- ###############################################################################
- #
- # set up the registers and jump into the kernel
- #
- ###############################################################################
- LEDS 0x000c
- sethi.p #0xe5e5,gr3
- setlo #0xe5e5,gr3
- or.p gr3,gr0,gr4
- or gr3,gr0,gr5
- or.p gr3,gr0,gr6
- or gr3,gr0,gr7
- or.p gr3,gr0,gr8
- or gr3,gr0,gr9
- or.p gr3,gr0,gr10
- or gr3,gr0,gr11
- or.p gr3,gr0,gr12
- or gr3,gr0,gr13
- or.p gr3,gr0,gr14
- or gr3,gr0,gr17
- or.p gr3,gr0,gr18
- or gr3,gr0,gr19
- or.p gr3,gr0,gr20
- or gr3,gr0,gr21
- or.p gr3,gr0,gr23
- or gr3,gr0,gr24
- or.p gr3,gr0,gr25
- or gr3,gr0,gr26
- or.p gr3,gr0,gr27
- # or gr3,gr0,gr30
- or gr3,gr0,gr31
- movgs gr0,lr
- movgs gr0,lcr
- movgs gr0,ccr
- movgs gr0,cccr
- # initialise the virtual interrupt handling
- subcc gr0,gr0,gr0,icc2 /* set Z, clear C */
- #ifdef CONFIG_MMU
- movgs gr3,scr2
- movgs gr3,scr3
- #endif
- LEDS 0x0fff
- # invoke the debugging stub if present
- # - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c
- # (it will not return here)
- break
- .globl __debug_stub_init_break
- __debug_stub_init_break:
- # however, if you need to use an ICE, and don't care about using any userspace
- # debugging tools (such as the ptrace syscall), you can just step over the break
- # above and get to the kernel this way
- # look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed
- call start_kernel
- .globl __head_end
- __head_end:
- .size _boot, .-_boot
- # provide a point for GDB to place a break
- .section .text..start,"ax"
- .globl _start
- .balign 4
- _start:
- call _boot
- .previous
- ###############################################################################
- #
- # split a tile off of the region defined by GR8-GR9
- #
- # ENTRY: EXIT:
- # GR4 - IAMPR value representing tile
- # GR5 - DAMPR value representing tile
- # GR6 - IAMLR value representing tile
- # GR7 - DAMLR value representing tile
- # GR8 region base pointer [saved]
- # GR9 region top pointer updated to exclude new tile
- # GR11 xAMLR mask [saved]
- # GR25 SDRAM size [saved]
- # GR30 LED address [saved]
- #
- # - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling
- #
- ###############################################################################
- .globl __head_split_region
- .type __head_split_region,@function
- __head_split_region:
- subcc.p gr9,gr8,gr4,icc0
- setlos #31,gr5
- scan.p gr4,gr0,gr6
- beq icc0,#0,__head_region_empty
- sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20)
- setlos #1,gr4
- sll.p gr4,gr6,gr4 ; size of region (1 << bitno)
- subi gr6,#17,gr6 ; 1MB => 0x03
- slli.p gr6,#4,gr6 ; 1MB => 0x30
- sub gr9,gr4,gr9 ; move uncovered top down
- or gr9,gr6,gr4
- ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4
- or.p gr4,gr0,gr5
- and gr4,gr11,gr6
- and.p gr5,gr11,gr7
- bralr
- __head_region_empty:
- or.p gr0,gr0,gr4
- or gr0,gr0,gr5
- or.p gr0,gr0,gr6
- or gr0,gr0,gr7
- bralr
- .size __head_split_region, .-__head_split_region
- ###############################################################################
- #
- # write the 32-bit hex number in GR8 to ttyS0
- #
- ###############################################################################
- #if 0
- .globl __head_write_to_ttyS0
- .type __head_write_to_ttyS0,@function
- __head_write_to_ttyS0:
- sethi.p %hi(0xfeff9c00),gr31
- setlo %lo(0xfeff9c00),gr31
- setlos #8,gr20
- 0: ldubi @(gr31,#5*8),gr21
- andi gr21,#0x60,gr21
- subicc gr21,#0x60,gr21,icc0
- bne icc0,#0,0b
- 1: srli gr8,#28,gr21
- slli gr8,#4,gr8
- addi gr21,#'0',gr21
- subicc gr21,#'9',gr0,icc0
- bls icc0,#2,2f
- addi gr21,#'A'-'0'-10,gr21
- 2:
- stbi gr21,@(gr31,#0*8)
- subicc gr20,#1,gr20,icc0
- bhi icc0,#2,1b
- setlos #'\r',gr21
- stbi gr21,@(gr31,#0*8)
- setlos #'\n',gr21
- stbi gr21,@(gr31,#0*8)
- 3: ldubi @(gr31,#5*8),gr21
- andi gr21,#0x60,gr21
- subicc gr21,#0x60,gr21,icc0
- bne icc0,#0,3b
- bralr
- .size __head_write_to_ttyS0, .-__head_write_to_ttyS0
- #endif
|