mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
09af39f649
xtensa core may be configured without register windows support, don't use register window specific opcodes in that case. Use window register specific opcodes to initialize hardware or reset core to a known state regardless of the chosen ABI. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
387 lines
7.0 KiB
ArmAsm
387 lines
7.0 KiB
ArmAsm
/*
|
|
* arch/xtensa/kernel/head.S
|
|
*
|
|
* Xtensa Processor startup code.
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 2001 - 2008 Tensilica Inc.
|
|
*
|
|
* Chris Zankel <chris@zankel.net>
|
|
* Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
|
|
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
|
|
* Kevin Chea
|
|
*/
|
|
|
|
#include <asm/asmmacro.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/page.h>
|
|
#include <asm/cacheasm.h>
|
|
#include <asm/initialize_mmu.h>
|
|
#include <asm/mxregs.h>
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/linkage.h>
|
|
|
|
/*
|
|
* This module contains the entry code for kernel images. It performs the
|
|
* minimal setup needed to call the generic C routines.
|
|
*
|
|
* Prerequisites:
|
|
*
|
|
* - The kernel image has been loaded to the actual address where it was
|
|
* compiled to.
|
|
* - a2 contains either 0 or a pointer to a list of boot parameters.
|
|
* (see setup.c for more details)
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* _start
|
|
*
|
|
* The bootloader passes a pointer to a list of boot parameters in a2.
|
|
*/
|
|
|
|
/* The first bytes of the kernel image must be an instruction, so we
|
|
* manually allocate and define the literal constant we need for a jx
|
|
* instruction.
|
|
*/
|
|
|
|
__HEAD
|
|
.begin no-absolute-literals
|
|
|
|
ENTRY(_start)
|
|
|
|
/* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
|
|
wsr a2, excsave1
|
|
_j _SetupOCD
|
|
|
|
.align 4
|
|
.literal_position
|
|
_SetupOCD:
|
|
/*
|
|
* Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
|
|
* Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
|
|
* xt-gdb to single step via DEBUG exceptions received directly
|
|
* by ocd.
|
|
*/
|
|
#if XCHAL_HAVE_WINDOWED
|
|
movi a1, 1
|
|
movi a0, 0
|
|
wsr a1, windowstart
|
|
wsr a0, windowbase
|
|
rsync
|
|
#endif
|
|
|
|
movi a1, LOCKLEVEL
|
|
wsr a1, ps
|
|
rsync
|
|
|
|
.global _SetupMMU
|
|
_SetupMMU:
|
|
Offset = _SetupMMU - _start
|
|
|
|
#ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
|
|
initialize_mmu
|
|
#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
|
|
rsr a2, excsave1
|
|
movi a3, XCHAL_KSEG_PADDR
|
|
bltu a2, a3, 1f
|
|
sub a2, a2, a3
|
|
movi a3, XCHAL_KSEG_SIZE
|
|
bgeu a2, a3, 1f
|
|
movi a3, XCHAL_KSEG_CACHED_VADDR
|
|
add a2, a2, a3
|
|
wsr a2, excsave1
|
|
1:
|
|
#endif
|
|
#endif
|
|
|
|
movi a0, _startup
|
|
jx a0
|
|
|
|
ENDPROC(_start)
|
|
.end no-absolute-literals
|
|
|
|
__REF
|
|
.literal_position
|
|
|
|
ENTRY(_startup)
|
|
|
|
/* Set a0 to 0 for the remaining initialization. */
|
|
|
|
movi a0, 0
|
|
|
|
#if XCHAL_HAVE_VECBASE
|
|
movi a2, VECBASE_VADDR
|
|
wsr a2, vecbase
|
|
#endif
|
|
|
|
/* Clear debugging registers. */
|
|
|
|
#if XCHAL_HAVE_DEBUG
|
|
#if XCHAL_NUM_IBREAK > 0
|
|
wsr a0, ibreakenable
|
|
#endif
|
|
wsr a0, icount
|
|
movi a1, 15
|
|
wsr a0, icountlevel
|
|
|
|
.set _index, 0
|
|
.rept XCHAL_NUM_DBREAK
|
|
wsr a0, SREG_DBREAKC + _index
|
|
.set _index, _index + 1
|
|
.endr
|
|
#endif
|
|
|
|
/* Clear CCOUNT (not really necessary, but nice) */
|
|
|
|
wsr a0, ccount # not really necessary, but nice
|
|
|
|
/* Disable zero-loops. */
|
|
|
|
#if XCHAL_HAVE_LOOPS
|
|
wsr a0, lcount
|
|
#endif
|
|
|
|
/* Disable all timers. */
|
|
|
|
.set _index, 0
|
|
.rept XCHAL_NUM_TIMERS
|
|
wsr a0, SREG_CCOMPARE + _index
|
|
.set _index, _index + 1
|
|
.endr
|
|
|
|
/* Interrupt initialization. */
|
|
|
|
movi a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
|
|
wsr a0, intenable
|
|
wsr a2, intclear
|
|
|
|
/* Disable coprocessors. */
|
|
|
|
#if XCHAL_HAVE_CP
|
|
wsr a0, cpenable
|
|
#endif
|
|
|
|
/* Initialize the caches.
|
|
* a2, a3 are just working registers (clobbered).
|
|
*/
|
|
|
|
#if XCHAL_DCACHE_LINE_LOCKABLE
|
|
___unlock_dcache_all a2 a3
|
|
#endif
|
|
|
|
#if XCHAL_ICACHE_LINE_LOCKABLE
|
|
___unlock_icache_all a2 a3
|
|
#endif
|
|
|
|
___invalidate_dcache_all a2 a3
|
|
___invalidate_icache_all a2 a3
|
|
|
|
isync
|
|
|
|
initialize_cacheattr
|
|
|
|
#ifdef CONFIG_HAVE_SMP
|
|
movi a2, CCON # MX External Register to Configure Cache
|
|
movi a3, 1
|
|
wer a3, a2
|
|
#endif
|
|
|
|
/* Setup stack and enable window exceptions (keep irqs disabled) */
|
|
|
|
movi a1, start_info
|
|
l32i a1, a1, 0
|
|
|
|
/* Disable interrupts. */
|
|
/* Enable window exceptions if kernel is built with windowed ABI. */
|
|
movi a2, KERNEL_PS_WOE_MASK | LOCKLEVEL
|
|
wsr a2, ps
|
|
rsync
|
|
|
|
#ifdef CONFIG_SMP
|
|
/*
|
|
* Notice that we assume with SMP that cores have PRID
|
|
* supported by the cores.
|
|
*/
|
|
rsr a2, prid
|
|
bnez a2, .Lboot_secondary
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
/* Unpack data sections
|
|
*
|
|
* The linker script used to build the Linux kernel image
|
|
* creates a table located at __boot_reloc_table_start
|
|
* that contains the information what data needs to be unpacked.
|
|
*
|
|
* Uses a2-a7.
|
|
*/
|
|
|
|
movi a2, __boot_reloc_table_start
|
|
movi a3, __boot_reloc_table_end
|
|
|
|
1: beq a2, a3, 3f # no more entries?
|
|
l32i a4, a2, 0 # start destination (in RAM)
|
|
l32i a5, a2, 4 # end destination (in RAM)
|
|
l32i a6, a2, 8 # start source (in ROM)
|
|
addi a2, a2, 12 # next entry
|
|
beq a4, a5, 1b # skip, empty entry
|
|
beq a4, a6, 1b # skip, source and dest. are the same
|
|
|
|
2: l32i a7, a6, 0 # load word
|
|
addi a6, a6, 4
|
|
s32i a7, a4, 0 # store word
|
|
addi a4, a4, 4
|
|
bltu a4, a5, 2b
|
|
j 1b
|
|
|
|
3:
|
|
/* All code and initialized data segments have been copied.
|
|
* Now clear the BSS segment.
|
|
*/
|
|
|
|
movi a2, __bss_start # start of BSS
|
|
movi a3, __bss_stop # end of BSS
|
|
|
|
__loopt a2, a3, a4, 2
|
|
s32i a0, a2, 0
|
|
__endla a2, a3, 4
|
|
|
|
#if XCHAL_DCACHE_IS_WRITEBACK
|
|
|
|
/* After unpacking, flush the writeback cache to memory so the
|
|
* instructions/data are available.
|
|
*/
|
|
|
|
___flush_dcache_all a2 a3
|
|
#endif
|
|
memw
|
|
isync
|
|
___invalidate_icache_all a2 a3
|
|
isync
|
|
|
|
#ifdef CONFIG_XIP_KERNEL
|
|
/* Setup bootstrap CPU stack in XIP kernel */
|
|
|
|
movi a1, start_info
|
|
l32i a1, a1, 0
|
|
#endif
|
|
|
|
movi abi_arg0, 0
|
|
xsr abi_arg0, excsave1
|
|
|
|
/* init_arch kick-starts the linux kernel */
|
|
|
|
abi_call init_arch
|
|
abi_call start_kernel
|
|
|
|
should_never_return:
|
|
j should_never_return
|
|
|
|
#ifdef CONFIG_SMP
|
|
.Lboot_secondary:
|
|
|
|
movi a2, cpu_start_ccount
|
|
1:
|
|
memw
|
|
l32i a3, a2, 0
|
|
beqi a3, 0, 1b
|
|
movi a3, 0
|
|
s32i a3, a2, 0
|
|
1:
|
|
memw
|
|
l32i a3, a2, 0
|
|
beqi a3, 0, 1b
|
|
wsr a3, ccount
|
|
movi a3, 0
|
|
s32i a3, a2, 0
|
|
memw
|
|
|
|
movi abi_arg0, 0
|
|
wsr abi_arg0, excsave1
|
|
|
|
abi_call secondary_start_kernel
|
|
j should_never_return
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
ENDPROC(_startup)
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
ENTRY(cpu_restart)
|
|
|
|
#if XCHAL_DCACHE_IS_WRITEBACK
|
|
___flush_invalidate_dcache_all a2 a3
|
|
#else
|
|
___invalidate_dcache_all a2 a3
|
|
#endif
|
|
memw
|
|
movi a2, CCON # MX External Register to Configure Cache
|
|
movi a3, 0
|
|
wer a3, a2
|
|
extw
|
|
|
|
rsr a0, prid
|
|
neg a2, a0
|
|
movi a3, cpu_start_id
|
|
memw
|
|
s32i a2, a3, 0
|
|
#if XCHAL_DCACHE_IS_WRITEBACK
|
|
dhwbi a3, 0
|
|
#endif
|
|
1:
|
|
memw
|
|
l32i a2, a3, 0
|
|
dhi a3, 0
|
|
bne a2, a0, 1b
|
|
|
|
/*
|
|
* Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
|
|
* Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
|
|
* xt-gdb to single step via DEBUG exceptions received directly
|
|
* by ocd.
|
|
*/
|
|
movi a1, 1
|
|
movi a0, 0
|
|
wsr a1, windowstart
|
|
wsr a0, windowbase
|
|
rsync
|
|
|
|
movi a1, LOCKLEVEL
|
|
wsr a1, ps
|
|
rsync
|
|
|
|
j _startup
|
|
|
|
ENDPROC(cpu_restart)
|
|
|
|
#endif /* CONFIG_HOTPLUG_CPU */
|
|
|
|
/*
|
|
* DATA section
|
|
*/
|
|
|
|
__REFDATA
|
|
.align 4
|
|
ENTRY(start_info)
|
|
.long init_thread_union + KERNEL_STACK_SIZE
|
|
|
|
/*
|
|
* BSS section
|
|
*/
|
|
|
|
__PAGE_ALIGNED_BSS
|
|
#ifdef CONFIG_MMU
|
|
ENTRY(swapper_pg_dir)
|
|
.fill PAGE_SIZE, 1, 0
|
|
END(swapper_pg_dir)
|
|
#endif
|
|
ENTRY(empty_zero_page)
|
|
.fill PAGE_SIZE, 1, 0
|
|
END(empty_zero_page)
|