/* head.S: kernel entry point for FR-V kernel1*2* Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved.3* Written by David Howells ([email protected])4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*/1011#include <linux/init.h>12#include <linux/threads.h>13#include <linux/linkage.h>14#include <asm/thread_info.h>15#include <asm/ptrace.h>16#include <asm/page.h>17#include <asm/spr-regs.h>18#include <asm/mb86943a.h>19#include <asm/cache.h>20#include "head.inc"2122###############################################################################23#24# void _boot(unsigned long magic, char *command_line) __attribute__((noreturn))25#26# - if magic is 0xdead1eaf, then command_line is assumed to point to the kernel27# command line string28#29###############################################################################30__HEAD31.balign 43233.globl _boot, __head_reference34.type _boot,@function35_boot:36__head_reference:37sethi.p %hi(LED_ADDR),gr3038setlo %lo(LED_ADDR),gr303940LEDS 0x00004142# calculate reference address for PC-relative stuff43call 0f440: movsg lr,gr2645addi gr26,#__head_reference-0b,gr264647# invalidate and disable both of the caches and turn off the memory access checking48dcef @(gr0,gr0),149bar5051sethi.p %hi(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr452setlo %lo(~(HSR0_ICE|HSR0_DCE|HSR0_CBM|HSR0_EIMMU|HSR0_EDMMU)),gr453movsg hsr0,gr554and gr4,gr5,gr555movgs gr5,hsr056movsg hsr0,gr55758LEDS 0x00015960icei @(gr0,gr0),161dcei @(gr0,gr0),162bar6364# turn the instruction cache back on65sethi.p %hi(HSR0_ICE),gr466setlo %lo(HSR0_ICE),gr467movsg hsr0,gr568or gr4,gr5,gr569movgs gr5,hsr070movsg hsr0,gr57172bar7374LEDS 0x00027576# retrieve the parameters (including command line) before we overwrite them77sethi.p %hi(0xdead1eaf),gr778setlo %lo(0xdead1eaf),gr779subcc gr7,gr8,gr0,icc080bne icc0,#0,__head_no_parameters8182sethi.p %hi(redboot_command_line-1),gr683setlo %lo(redboot_command_line-1),gr684sethi.p %hi(__head_reference),gr485setlo %lo(__head_reference),gr486sub gr6,gr4,gr687add.p gr6,gr26,gr688subi gr9,#1,gr989setlos.p #511,gr490setlos #1,gr59192__head_copy_cmdline:93ldubu.p @(gr9,gr5),gr1694subicc gr4,#1,gr4,icc095stbu.p gr16,@(gr6,gr5)96subicc gr16,#0,gr0,icc197bls icc0,#0,__head_end_cmdline98bne icc1,#1,__head_copy_cmdline99__head_end_cmdline:100stbu gr0,@(gr6,gr5)101__head_no_parameters:102103###############################################################################104#105# we need to relocate the SDRAM to 0x00000000 (linux) or 0xC0000000 (uClinux)106# - note that we're going to have to run entirely out of the icache whilst107# fiddling with the SDRAM controller registers108#109###############################################################################110#ifdef CONFIG_MMU111call __head_fr451_describe_sdram112113#else114movsg psr,gr5115srli gr5,#28,gr5116subicc gr5,#3,gr0,icc0117beq icc0,#0,__head_fr551_sdram118119call __head_fr401_describe_sdram120bra __head_do_sdram121122__head_fr551_sdram:123call __head_fr555_describe_sdram124LEDS 0x000d125126__head_do_sdram:127#endif128129# preload the registers with invalid values in case any DBR/DARS are marked not present130sethi.p %hi(0xfe000000),gr17 ; unused SDRAM DBR value131setlo %lo(0xfe000000),gr17132or.p gr17,gr0,gr20133or gr17,gr0,gr21134or.p gr17,gr0,gr22135or gr17,gr0,gr23136137# consult the SDRAM controller CS address registers138cld @(gr14,gr0 ),gr20, cc0,#1 ; DBR0 / DARS0139cld @(gr14,gr11),gr21, cc1,#1 ; DBR1 / DARS1140cld @(gr14,gr12),gr22, cc2,#1 ; DBR2 / DARS2141cld.p @(gr14,gr13),gr23, cc3,#1 ; DBR3 / DARS3142143sll gr20,gr15,gr20 ; shift values up for FR551144sll gr21,gr15,gr21145sll gr22,gr15,gr22146sll gr23,gr15,gr23147148LEDS 0x0003149150# assume the lowest valid CS line to be the SDRAM base and get its address151subcc gr20,gr17,gr0,icc0152subcc.p gr21,gr17,gr0,icc1153subcc gr22,gr17,gr0,icc2154subcc.p gr23,gr17,gr0,icc3155ckne icc0,cc4 ; T if DBR0 != 0xfe000000156ckne icc1,cc5157ckne icc2,cc6158ckne icc3,cc7159cor gr23,gr0,gr24, cc7,#1 ; GR24 = SDRAM base160cor gr22,gr0,gr24, cc6,#1161cor gr21,gr0,gr24, cc5,#1162cor gr20,gr0,gr24, cc4,#1163164# calculate the displacement required to get the SDRAM into the right place in memory165sethi.p %hi(__sdram_base),gr16166setlo %lo(__sdram_base),gr16167sub gr16,gr24,gr16 ; delta = __sdram_base - DBRx168169# calculate the new values to go in the controller regs170cadd.p gr20,gr16,gr20, cc4,#1 ; DCS#0 (new) = DCS#0 (old) + delta171cadd gr21,gr16,gr21, cc5,#1172cadd.p gr22,gr16,gr22, cc6,#1173cadd gr23,gr16,gr23, cc7,#1174175srl gr20,gr15,gr20 ; shift values down for FR551176srl gr21,gr15,gr21177srl gr22,gr15,gr22178srl gr23,gr15,gr23179180# work out the address at which the reg updater resides and lock it into icache181# also work out the address the updater will jump to when finished182sethi.p %hi(__head_move_sdram-__head_reference),gr18183setlo %lo(__head_move_sdram-__head_reference),gr18184sethi.p %hi(__head_sdram_moved-__head_reference),gr19185setlo %lo(__head_sdram_moved-__head_reference),gr19186add.p gr18,gr26,gr18187add gr19,gr26,gr19188add.p gr19,gr16,gr19 ; moved = addr + (__sdram_base - DBRx)189add gr18,gr5,gr4 ; two cachelines probably required190191icpl gr18,gr0,#1 ; load and lock the cachelines192icpl gr4,gr0,#1193LEDS 0x0004194membar195bar196jmpl @(gr18,gr0)197198.balign L1_CACHE_BYTES199__head_move_sdram:200cst gr20,@(gr14,gr0 ), cc4,#1201cst gr21,@(gr14,gr11), cc5,#1202cst gr22,@(gr14,gr12), cc6,#1203cst gr23,@(gr14,gr13), cc7,#1204cld @(gr14,gr0 ),gr20, cc4,#1205cld @(gr14,gr11),gr21, cc5,#1206cld @(gr14,gr12),gr22, cc4,#1207cld @(gr14,gr13),gr23, cc7,#1208bar209membar210jmpl @(gr19,gr0)211212.balign L1_CACHE_BYTES213__head_sdram_moved:214icul gr18215add gr18,gr5,gr4216icul gr4217icei @(gr0,gr0),1218dcei @(gr0,gr0),1219220LEDS 0x0005221222# recalculate reference address223call 0f2240: movsg lr,gr26225addi gr26,#__head_reference-0b,gr26226227228###############################################################################229#230# move the kernel image down to the bottom of the SDRAM231#232###############################################################################233sethi.p %hi(__kernel_image_size_no_bss+15),gr4234setlo %lo(__kernel_image_size_no_bss+15),gr4235srli.p gr4,#4,gr4 ; count236or gr26,gr26,gr16 ; source237238sethi.p %hi(__sdram_base),gr17 ; destination239setlo %lo(__sdram_base),gr17240241setlos #8,gr5242sub.p gr16,gr5,gr16 ; adjust src for LDDU243sub gr17,gr5,gr17 ; adjust dst for LDDU244245sethi.p %hi(__head_move_kernel-__head_reference),gr18246setlo %lo(__head_move_kernel-__head_reference),gr18247sethi.p %hi(__head_kernel_moved-__head_reference+__sdram_base),gr19248setlo %lo(__head_kernel_moved-__head_reference+__sdram_base),gr19249add gr18,gr26,gr18250icpl gr18,gr0,#1251jmpl @(gr18,gr0)252253.balign 32254__head_move_kernel:255lddu @(gr16,gr5),gr10256lddu @(gr16,gr5),gr12257stdu.p gr10,@(gr17,gr5)258subicc gr4,#1,gr4,icc0259stdu.p gr12,@(gr17,gr5)260bhi icc0,#0,__head_move_kernel261jmpl @(gr19,gr0)262263.balign 32264__head_kernel_moved:265icul gr18266icei @(gr0,gr0),1267dcei @(gr0,gr0),1268269LEDS 0x0006270271# recalculate reference address272call 0f2730: movsg lr,gr26274addi gr26,#__head_reference-0b,gr26275276277###############################################################################278#279# rearrange the iomem map and set the protection registers280#281###############################################################################282283#ifdef CONFIG_MMU284LEDS 0x3301285call __head_fr451_set_busctl286LEDS 0x3303287call __head_fr451_survey_sdram288LEDS 0x3305289call __head_fr451_set_protection290291#else292movsg psr,gr5293srli gr5,#PSR_IMPLE_SHIFT,gr5294subicc gr5,#PSR_IMPLE_FR551,gr0,icc0295beq icc0,#0,__head_fr555_memmap296subicc gr5,#PSR_IMPLE_FR451,gr0,icc0297beq icc0,#0,__head_fr451_memmap298299LEDS 0x3101300call __head_fr401_set_busctl301LEDS 0x3103302call __head_fr401_survey_sdram303LEDS 0x3105304call __head_fr401_set_protection305bra __head_done_memmap306307__head_fr451_memmap:308LEDS 0x3301309call __head_fr401_set_busctl310LEDS 0x3303311call __head_fr401_survey_sdram312LEDS 0x3305313call __head_fr451_set_protection314bra __head_done_memmap315316__head_fr555_memmap:317LEDS 0x3501318call __head_fr555_set_busctl319LEDS 0x3503320call __head_fr555_survey_sdram321LEDS 0x3505322call __head_fr555_set_protection323324__head_done_memmap:325#endif326LEDS 0x0007327328###############################################################################329#330# turn the data cache and MMU on331# - for the FR451 this'll mean that the window through which the kernel is332# viewed will change333#334###############################################################################335336#ifdef CONFIG_MMU337#define MMUMODE HSR0_EIMMU|HSR0_EDMMU|HSR0_EXMMU|HSR0_EDAT|HSR0_XEDAT338#else339#define MMUMODE HSR0_EIMMU|HSR0_EDMMU340#endif341342movsg hsr0,gr5343344sethi.p %hi(MMUMODE),gr4345setlo %lo(MMUMODE),gr4346or gr4,gr5,gr5347348#if defined(CONFIG_FRV_DEFL_CACHE_WTHRU)349sethi.p %hi(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4350setlo %lo(HSR0_DCE|HSR0_CBM_WRITE_THRU),gr4351#elif defined(CONFIG_FRV_DEFL_CACHE_WBACK)352sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4353setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4354#elif defined(CONFIG_FRV_DEFL_CACHE_WBEHIND)355sethi.p %hi(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4356setlo %lo(HSR0_DCE|HSR0_CBM_COPY_BACK),gr4357358movsg psr,gr6359srli gr6,#24,gr6360cmpi gr6,#0x50,icc0 // FR451361beq icc0,#0,0f362cmpi gr6,#0x40,icc0 // FR405363bne icc0,#0,1f3640:365# turn off write-allocate366sethi.p %hi(HSR0_NWA),gr6367setlo %lo(HSR0_NWA),gr6368or gr4,gr6,gr43691:370371#else372#error No default cache configuration set373#endif374375or gr4,gr5,gr5376movgs gr5,hsr0377bar378379LEDS 0x0008380381sethi.p %hi(__head_mmu_enabled),gr19382setlo %lo(__head_mmu_enabled),gr19383jmpl @(gr19,gr0)384385__head_mmu_enabled:386icei @(gr0,gr0),#1387dcei @(gr0,gr0),#1388389LEDS 0x0009390391#ifdef CONFIG_MMU392call __head_fr451_finalise_protection393#endif394395LEDS 0x000a396397###############################################################################398#399# set up the runtime environment400#401###############################################################################402403# clear the BSS area404sethi.p %hi(__bss_start),gr4405setlo %lo(__bss_start),gr4406sethi.p %hi(_end),gr5407setlo %lo(_end),gr5408or.p gr0,gr0,gr18409or gr0,gr0,gr194104110:412stdi gr18,@(gr4,#0)413stdi gr18,@(gr4,#8)414stdi gr18,@(gr4,#16)415stdi.p gr18,@(gr4,#24)416addi gr4,#24,gr4417subcc gr5,gr4,gr0,icc0418bhi icc0,#2,0b419420LEDS 0x000b421422# save the SDRAM details423sethi.p %hi(__sdram_old_base),gr4424setlo %lo(__sdram_old_base),gr4425st gr24,@(gr4,gr0)426427sethi.p %hi(__sdram_base),gr5428setlo %lo(__sdram_base),gr5429sethi.p %hi(memory_start),gr4430setlo %lo(memory_start),gr4431st gr5,@(gr4,gr0)432433add gr25,gr5,gr25434sethi.p %hi(memory_end),gr4435setlo %lo(memory_end),gr4436st gr25,@(gr4,gr0)437438# point the TBR at the kernel trap table439sethi.p %hi(__entry_kerneltrap_table),gr4440setlo %lo(__entry_kerneltrap_table),gr4441movgs gr4,tbr442443# set up the exception frame for init444sethi.p %hi(__kernel_frame0_ptr),gr28445setlo %lo(__kernel_frame0_ptr),gr28446sethi.p %hi(_gp),gr16447setlo %lo(_gp),gr16448sethi.p %hi(__entry_usertrap_table),gr4449setlo %lo(__entry_usertrap_table),gr4450451lddi @(gr28,#0),gr28 ; load __frame & current452ldi.p @(gr29,#4),gr15 ; set current_thread453454or gr0,gr0,fp455or gr28,gr0,sp456457sti.p gr4,@(gr28,REG_TBR)458setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5459movgs gr5,isr460461# turn on and off various CPU services462movsg psr,gr22463sethi.p %hi(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4464setlo %lo(#PSR_EM|PSR_EF|PSR_CM|PSR_NEM),gr4465or gr22,gr4,gr22466movgs gr22,psr467468andi gr22,#~(PSR_PIL|PSR_PS|PSR_S),gr22469ori gr22,#PSR_ET,gr22470sti gr22,@(gr28,REG_PSR)471472473###############################################################################474#475# set up the registers and jump into the kernel476#477###############################################################################478479LEDS 0x000c480481# initialise the processor and the peripherals482#call SYMBOL_NAME(processor_init)483#call SYMBOL_NAME(unit_init)484#LEDS 0x0aff485486sethi.p #0xe5e5,gr3487setlo #0xe5e5,gr3488or.p gr3,gr0,gr4489or gr3,gr0,gr5490or.p gr3,gr0,gr6491or gr3,gr0,gr7492or.p gr3,gr0,gr8493or gr3,gr0,gr9494or.p gr3,gr0,gr10495or gr3,gr0,gr11496or.p gr3,gr0,gr12497or gr3,gr0,gr13498or.p gr3,gr0,gr14499or gr3,gr0,gr17500or.p gr3,gr0,gr18501or gr3,gr0,gr19502or.p gr3,gr0,gr20503or gr3,gr0,gr21504or.p gr3,gr0,gr23505or gr3,gr0,gr24506or.p gr3,gr0,gr25507or gr3,gr0,gr26508or.p gr3,gr0,gr27509# or gr3,gr0,gr30510or gr3,gr0,gr31511movgs gr0,lr512movgs gr0,lcr513movgs gr0,ccr514movgs gr0,cccr515516# initialise the virtual interrupt handling517subcc gr0,gr0,gr0,icc2 /* set Z, clear C */518519#ifdef CONFIG_MMU520movgs gr3,scr2521movgs gr3,scr3522#endif523524LEDS 0x0fff525526# invoke the debugging stub if present527# - arch/frv/kernel/debug-stub.c will shift control directly to init/main.c528# (it will not return here)529break530.globl __debug_stub_init_break531__debug_stub_init_break:532533# however, if you need to use an ICE, and don't care about using any userspace534# debugging tools (such as the ptrace syscall), you can just step over the break535# above and get to the kernel this way536# look at arch/frv/kernel/debug-stub.c: debug_stub_init() to see what you've missed537call start_kernel538539.globl __head_end540__head_end:541.size _boot, .-_boot542543# provide a point for GDB to place a break544.section .text..start,"ax"545.globl _start546.balign 4547_start:548call _boot549550.previous551###############################################################################552#553# split a tile off of the region defined by GR8-GR9554#555# ENTRY: EXIT:556# GR4 - IAMPR value representing tile557# GR5 - DAMPR value representing tile558# GR6 - IAMLR value representing tile559# GR7 - DAMLR value representing tile560# GR8 region base pointer [saved]561# GR9 region top pointer updated to exclude new tile562# GR11 xAMLR mask [saved]563# GR25 SDRAM size [saved]564# GR30 LED address [saved]565#566# - GR8 and GR9 should be rounded up/down to the nearest megabyte before calling567#568###############################################################################569.globl __head_split_region570.type __head_split_region,@function571__head_split_region:572subcc.p gr9,gr8,gr4,icc0573setlos #31,gr5574scan.p gr4,gr0,gr6575beq icc0,#0,__head_region_empty576sub.p gr5,gr6,gr6 ; bit number of highest set bit (1MB=>20)577setlos #1,gr4578sll.p gr4,gr6,gr4 ; size of region (1 << bitno)579subi gr6,#17,gr6 ; 1MB => 0x03580slli.p gr6,#4,gr6 ; 1MB => 0x30581sub gr9,gr4,gr9 ; move uncovered top down582583or gr9,gr6,gr4584ori gr4,#xAMPRx_S_USER|xAMPRx_C_CACHED|xAMPRx_V,gr4585or.p gr4,gr0,gr5586587and gr4,gr11,gr6588and.p gr5,gr11,gr7589bralr590591__head_region_empty:592or.p gr0,gr0,gr4593or gr0,gr0,gr5594or.p gr0,gr0,gr6595or gr0,gr0,gr7596bralr597.size __head_split_region, .-__head_split_region598599###############################################################################600#601# write the 32-bit hex number in GR8 to ttyS0602#603###############################################################################604#if 0605.globl __head_write_to_ttyS0606.type __head_write_to_ttyS0,@function607__head_write_to_ttyS0:608sethi.p %hi(0xfeff9c00),gr31609setlo %lo(0xfeff9c00),gr31610setlos #8,gr206116120: ldubi @(gr31,#5*8),gr21613andi gr21,#0x60,gr21614subicc gr21,#0x60,gr21,icc0615bne icc0,#0,0b6166171: srli gr8,#28,gr21618slli gr8,#4,gr8619620addi gr21,#'0',gr21621subicc gr21,#'9',gr0,icc0622bls icc0,#2,2f623addi gr21,#'A'-'0'-10,gr216242:625stbi gr21,@(gr31,#0*8)626subicc gr20,#1,gr20,icc0627bhi icc0,#2,1b628629setlos #'\r',gr21630stbi gr21,@(gr31,#0*8)631632setlos #'\n',gr21633stbi gr21,@(gr31,#0*8)6346353: ldubi @(gr31,#5*8),gr21636andi gr21,#0x60,gr21637subicc gr21,#0x60,gr21,icc0638bne icc0,#0,3b639bralr640641.size __head_write_to_ttyS0, .-__head_write_to_ttyS0642#endif643644645