diff options
Diffstat (limited to 'arch/xtensa')
42 files changed, 3101 insertions, 0 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig new file mode 100644 index 0000000..bb6a678 --- /dev/null +++ b/arch/xtensa/Kconfig @@ -0,0 +1,18 @@ +menu "Xtensa architecture" + depends on XTENSA + +config SYS_ARCH + string + default "xtensa" + +config SYS_CPU + string "Xtensa Core Variant" + +choice + prompt "Target select" + + +endchoice + + +endmenu diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile new file mode 100644 index 0000000..130d76f --- /dev/null +++ b/arch/xtensa/Makefile @@ -0,0 +1,8 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +head-y := arch/xtensa/cpu/start.o + +libs-y += arch/xtensa/cpu/ +libs-y += arch/xtensa/lib/ diff --git a/arch/xtensa/config.mk b/arch/xtensa/config.mk new file mode 100644 index 0000000..7dd8d8a --- /dev/null +++ b/arch/xtensa/config.mk @@ -0,0 +1,12 @@ +# +# (C) Copyright 2007 - 2013 Tensilica, Inc. +# (C) Copyright 2014 - 2016 Cadence Design Systems Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +CROSS_COMPILE ?= xtensa-linux- +PLATFORM_CPPFLAGS += -D__XTENSA__ -mlongcalls -mforce-no-pic \ + -ffunction-sections -fdata-sections + +LDFLAGS_FINAL += --gc-sections diff --git a/arch/xtensa/cpu/Makefile b/arch/xtensa/cpu/Makefile new file mode 100644 index 0000000..e83f620 --- /dev/null +++ b/arch/xtensa/cpu/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2007 - 2013 Tensilica, Inc. +# (C) Copyright 2014 - 2016 Cadence Design Systems Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o exceptions.o +extra-y = start.o diff --git a/arch/xtensa/cpu/cpu.c b/arch/xtensa/cpu/cpu.c new file mode 100644 index 0000000..6787a61 --- /dev/null +++ b/arch/xtensa/cpu/cpu.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> +#include <linux/stringify.h> +#include <asm/global_data.h> +#include <asm/cache.h> +#include <asm/string.h> +#include <asm/misc.h> + +DECLARE_GLOBAL_DATA_PTR; + +gd_t *gd __attribute__((section(".data"))); + +#if defined(CONFIG_DISPLAY_CPUINFO) +/* + * Print information about the CPU. + */ + +int print_cpuinfo(void) +{ + char buf[120], mhz[8]; + uint32_t id0, id1; + + asm volatile ("rsr %0, 176\n" + "rsr %1, 208\n" + : "=r"(id0), "=r"(id1)); + + sprintf(buf, "CPU: Xtensa %s (id: %08x:%08x) at %s MHz\n", + XCHAL_CORE_ID, id0, id1, strmhz(mhz, gd->cpu_clk)); + puts(buf); + return 0; +} +#endif + +int arch_cpu_init(void) +{ + gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + return 0; +} diff --git a/arch/xtensa/cpu/exceptions.c b/arch/xtensa/cpu/exceptions.c new file mode 100644 index 0000000..16639a0 --- /dev/null +++ b/arch/xtensa/cpu/exceptions.c @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Exception handling. + * We currently don't handle any exception and force a reset. + * (Note that alloca is a special case and handled in start.S) + */ + +#include <common.h> +#include <command.h> +#include <asm/string.h> +#include <asm/regs.h> + +typedef void (*handler_t)(struct pt_regs *); + +void unhandled_exception(struct pt_regs *regs) +{ + printf("Unhandled Exception: EXCCAUSE = %ld, EXCVADDR = %lx, pc = %lx\n", + regs->exccause, regs->excvaddr, regs->pc); + panic("*** PANIC\n"); +} + +handler_t exc_table[EXCCAUSE_LAST] = { + [0 ... EXCCAUSE_LAST-1] = unhandled_exception, +}; + +int interrupt_init(void) +{ + return 0; +} + +void enable_interrupts(void) +{ +} + +int disable_interrupts(void) +{ + return 0; +} diff --git a/arch/xtensa/cpu/start.S b/arch/xtensa/cpu/start.S new file mode 100644 index 0000000..8e4bc99 --- /dev/null +++ b/arch/xtensa/cpu/start.S @@ -0,0 +1,677 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <asm/asmmacro.h> +#include <asm/cacheasm.h> +#include <asm/regs.h> +#include <asm/arch/tie.h> +#include <asm-offsets.h> + +/* + * Offsets into the the pt_regs struture. + * Make sure these always match with the structure defined in ptrace.h! + */ + +#define PT_PC 0 +#define PT_PS 4 +#define PT_DEPC 8 +#define PT_EXCCAUSE 12 +#define PT_EXCVADDR 16 +#define PT_DEBUGCAUSE 20 +#define PT_WMASK 24 +#define PT_LBEG 28 +#define PT_LEND 32 +#define PT_LCOUNT 36 +#define PT_SAR 40 +#define PT_WINDOWBASE 44 +#define PT_WINDOWSTART 48 +#define PT_SYSCALL 52 +#define PT_ICOUNTLEVEL 56 +#define PT_RESERVED 60 +#define PT_AREG 64 +#define PT_SIZE (64 + 64) + +/* + * Cache attributes are different for full MMU and region protection. + */ + +#if XCHAL_HAVE_PTP_MMU +#define CA_WRITEBACK (0x7) +#else +#define CA_WRITEBACK (0x4) +#endif + +/* + * Reset vector. + * Only a trampoline to jump to _start + * (Note that we have to mark the section writable as the section contains + * a relocatable literal) + */ + + .section .ResetVector.text, "awx" + .global _ResetVector +_ResetVector: + + j 1f + .align 4 +2: .long _start +1: l32r a2, 2b + jx a2 + + +/* + * Processor initialization. We still run in rom space. + * + * NOTE: Running in ROM + * For Xtensa, we currently don't allow to run some code from ROM but + * unpack the data immediately to memory. This requires, for example, + * that DDR has been set up before running U-Boot. (See also comments + * inline for ways to change it) + */ + + .section .reset.text, "ax" + .global _start + .align 4 +_start: + /* Keep a0 = 0 for various initializations */ + + movi a0, 0 + + /* + * For full MMU cores, put page table at unmapped virtual address. + * This ensures that accesses outside the static maps result + * in miss exceptions rather than random behaviour. + */ + +#if XCHAL_HAVE_PTP_MMU + wsr a0, PTEVADDR +#endif + + /* Disable dbreak debug exceptions */ + +#if XCHAL_HAVE_DEBUG && XCHAL_NUM_DBREAK > 0 + .set _index, 0 + .rept XCHAL_NUM_DBREAK + wsr a0, DBREAKC + _index + .set _index, _index + 1 + .endr +#endif + + /* Reset windowbase and windowstart */ + +#if XCHAL_HAVE_WINDOWED + movi a3, 1 + wsr a3, windowstart + wsr a0, windowbase + rsync + movi a0, 0 /* windowbase might have changed */ +#endif + + /* + * Vecbase in bitstream may differ from header files + * set or check it. + */ + +#if XCHAL_HAVE_VECBASE + movi a3, XCHAL_VECBASE_RESET_VADDR /* VECBASE reset value */ + wsr a3, VECBASE +#endif + +#if XCHAL_HAVE_LOOPS + /* Disable loops */ + + wsr a0, LCOUNT +#endif + + /* Set PS.WOE = 0, PS.EXCM = 0 (for loop), PS.INTLEVEL = EXCM level */ + +#if XCHAL_HAVE_XEA1 + movi a2, 1 +#else + movi a2, XCHAL_EXCM_LEVEL +#endif + wsr a2, PS + rsync + + /* Unlock and invalidate caches */ + + ___unlock_dcache_all a2, a3 + ___invalidate_dcache_all a2, a3 + ___unlock_icache_all a2, a3 + ___invalidate_icache_all a2, a3 + + isync + + /* Unpack data sections */ + + movi a2, __reloc_table_start + movi a3, __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 destination are the same + + /* If there's memory protection option with 512MB TLB regions and + * cache attributes in TLB entries and caching is not inhibited, + * enable data/instruction cache for relocated image. + */ +#if XCHAL_HAVE_SPANNING_WAY && \ + (!defined(CONFIG_SYS_DCACHE_OFF) || \ + !defined(CONFIG_SYS_ICACHE_OFF)) + srli a7, a4, 29 + slli a7, a7, 29 + addi a7, a7, XCHAL_SPANNING_WAY +#ifndef CONFIG_SYS_DCACHE_OFF + rdtlb1 a8, a7 + srli a8, a8, 4 + slli a8, a8, 4 + addi a8, a8, CA_WRITEBACK + wdtlb a8, a7 +#endif +#ifndef CONFIG_SYS_ICACHE_OFF + ritlb1 a8, a7 + srli a8, a8, 4 + slli a8, a8, 4 + addi a8, a8, CA_WRITEBACK + witlb a8, a7 +#endif + isync +#endif + +2: l32i a7, a6, 0 + addi a6, a6, 4 + s32i a7, a4, 0 + addi a4, a4, 4 + bltu a4, a5, 2b + j 1b + +3: /* All code and initalized data segments have been copied */ + + /* Setup PS, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */ + +#if __XTENSA_CALL0_ABI__ + movi a2, XCHAL_EXCM_LEVEL +#else + movi a2, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL +#endif + wsr a2, PS + rsync + + /* Writeback */ + + ___flush_dcache_all a2, a3 + +#ifdef __XTENSA_WINDOWED_ABI__ + /* + * In windowed ABI caller and call target need to be within the same + * gigabyte. Put the rest of the code into the text segment and jump + * there. + */ + + movi a4, .Lboard_init_code + jx a4 + + .text + .align 4 +.Lboard_init_code: +#endif + + movi a0, 0 + movi sp, (CONFIG_SYS_TEXT_ADDR - 16) & 0xfffffff0 + +#ifdef CONFIG_DEBUG_UART + movi a4, debug_uart_init +#ifdef __XTENSA_CALL0_ABI__ + callx0 a4 +#else + callx4 a4 +#endif +#endif + + movi a4, board_init_f_alloc_reserve + +#ifdef __XTENSA_CALL0_ABI__ + mov a2, sp + callx0 a4 + mov sp, a2 +#else + mov a6, sp + callx4 a4 + movsp sp, a6 +#endif + + movi a4, board_init_f_init_reserve + +#ifdef __XTENSA_CALL0_ABI__ + callx0 a4 +#else + callx4 a4 +#endif + + /* + * Call board initialization routine (never returns). + */ + + movi a4, board_init_f + +#ifdef __XTENSA_CALL0_ABI__ + movi a2, 0 + callx0 a4 +#else + movi a6, 0 + callx4 a4 +#endif + /* Never Returns */ + ill + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * a2 = addr_sp + * a3 = gd + * a4 = destination address + */ + .text + .globl relocate_code + .align 4 +relocate_code: + abi_entry + +#ifdef __XTENSA_CALL0_ABI__ + mov a1, a2 + mov a2, a3 + mov a3, a4 + movi a0, board_init_r + callx0 a0 +#else + /* We can't movsp here, because the chain of stack frames may cross + * the now reserved memory. We need to toss all window frames except + * the current, create new pristine stack frame and start from scratch. + */ + rsr a0, windowbase + ssl a0 + movi a0, 1 + sll a0, a0 + wsr a0, windowstart + rsync + + movi a0, 0 + + /* Reserve 16-byte save area */ + addi sp, a2, -16 + mov a6, a3 + mov a7, a4 + movi a4, board_init_r + callx4 a4 +#endif + ill + +#if XCHAL_HAVE_EXCEPTIONS + +/* + * Exception vectors. + * + * Various notes: + * - We currently don't use the user exception vector (PS.UM is always 0), + * but do define such a vector, just in case. They both jump to the + * same exception handler, though. + * - We currently only save the bare minimum number of registers: + * a0...a15, sar, loop-registers, exception register (epc1, excvaddr, + * exccause, depc) + * - WINDOWSTART is only saved to identify if registers have been spilled + * to the wrong stack (exception stack) while executing the exception + * handler. + */ + + .section .KernelExceptionVector.text, "ax" + .global _KernelExceptionVector +_KernelExceptionVector: + + wsr a2, EXCSAVE1 + movi a2, ExceptionHandler + jx a2 + + .section .UserExceptionVector.text, "ax" + .global _UserExceptionVector +_UserExceptionVector: + + wsr a2, EXCSAVE1 + movi a2, ExceptionHandler + jx a2 + +#if !XCHAL_HAVE_XEA1 + .section .DoubleExceptionVector.text, "ax" + .global _DoubleExceptionVector +_DoubleExceptionVector: + +#ifdef __XTENSA_CALL0_ABI__ + wsr a0, EXCSAVE1 + movi a0, hang # report and ask user to reset board + callx0 a0 +#else + wsr a4, EXCSAVE1 + movi a4, hang # report and ask user to reset board + callx4 a4 +#endif +#endif + /* Does not return here */ + + + .text + .align 4 +ExceptionHandler: + + rsr a2, EXCCAUSE # find handler + +#if XCHAL_HAVE_WINDOWED + /* Special case for alloca handler */ + + bnei a2, 5, 1f # jump if not alloca exception + + addi a1, a1, -16 - 4 # create a small stack frame + s32i a3, a1, 0 # and save a3 (a2 still in excsave1) + movi a2, fast_alloca_exception + jx a2 # jump to fast_alloca_exception +#endif + /* All other exceptions go here: */ + + /* Create ptrace stack and save a0...a3 */ + +1: addi a2, a1, - PT_SIZE - 16 + s32i a0, a2, PT_AREG + 0 * 4 + s32i a1, a2, PT_AREG + 1 * 4 + s32i a3, a2, PT_AREG + 3 * 4 + rsr a3, EXCSAVE1 + s32i a3, a2, PT_AREG + 2 * 4 + mov a1, a2 + + /* Save remaining AR registers */ + + s32i a4, a1, PT_AREG + 4 * 4 + s32i a5, a1, PT_AREG + 5 * 4 + s32i a6, a1, PT_AREG + 6 * 4 + s32i a7, a1, PT_AREG + 7 * 4 + s32i a8, a1, PT_AREG + 8 * 4 + s32i a9, a1, PT_AREG + 9 * 4 + s32i a10, a1, PT_AREG + 10 * 4 + s32i a11, a1, PT_AREG + 11 * 4 + s32i a12, a1, PT_AREG + 12 * 4 + s32i a13, a1, PT_AREG + 13 * 4 + s32i a14, a1, PT_AREG + 14 * 4 + s32i a15, a1, PT_AREG + 15 * 4 + + /* Save SRs */ + +#if XCHAL_HAVE_WINDOWED + rsr a2, WINDOWSTART + s32i a2, a1, PT_WINDOWSTART +#endif + + rsr a2, SAR + rsr a3, EPC1 + rsr a4, EXCVADDR + s32i a2, a1, PT_SAR + s32i a3, a1, PT_PC + s32i a4, a1, PT_EXCVADDR + +#if XCHAL_HAVE_LOOPS + movi a2, 0 + rsr a3, LBEG + xsr a2, LCOUNT + s32i a3, a1, PT_LBEG + rsr a3, LEND + s32i a2, a1, PT_LCOUNT + s32i a3, a1, PT_LEND +#endif + + /* Set up C environment and call registered handler */ + /* Setup stack, PS.WOE = 1, PS.EXCM = 0, PS.INTLEVEL = EXCM level. */ + + rsr a2, EXCCAUSE +#if XCHAL_HAVE_XEA1 + movi a3, (1<<PS_WOE_BIT) | 1 +#elif __XTENSA_CALL0_ABI__ + movi a3, XCHAL_EXCM_LEVEL +#else + movi a3, (1<<PS_WOE_BIT) | XCHAL_EXCM_LEVEL +#endif + xsr a3, PS + rsync + s32i a2, a1, PT_EXCCAUSE + s32i a3, a1, PT_PS + + movi a0, exc_table + addx4 a0, a2, a0 + l32i a0, a0, 0 +#ifdef __XTENSA_CALL0_ABI__ + mov a2, a1 # Provide stack frame as only argument + callx0 a0 + l32i a3, a1, PT_PS +#else + mov a6, a1 # Provide stack frame as only argument + callx4 a0 +#endif + + /* Restore PS and go to exception mode (PS.EXCM=1) */ + + wsr a3, PS + + /* Restore SR registers */ + +#if XCHAL_HAVE_LOOPS + l32i a2, a1, PT_LBEG + l32i a3, a1, PT_LEND + l32i a4, a1, PT_LCOUNT + wsr a2, LBEG + wsr a3, LEND + wsr a4, LCOUNT +#endif + + l32i a2, a1, PT_SAR + l32i a3, a1, PT_PC + wsr a2, SAR + wsr a3, EPC1 + +#if XCHAL_HAVE_WINDOWED + /* Do we need to simulate a MOVSP? */ + + l32i a2, a1, PT_WINDOWSTART + addi a3, a2, -1 + and a2, a2, a3 + beqz a2, 1f # Skip if regs were spilled before exc. + + rsr a2, WINDOWSTART + addi a3, a2, -1 + and a2, a2, a3 + bnez a2, 1f # Skip if registers aren't spilled now + + addi a2, a1, -16 + l32i a4, a2, 0 + l32i a5, a2, 4 + s32i a4, a1, PT_SIZE + 0 + s32i a5, a1, PT_SIZE + 4 + l32i a4, a2, 8 + l32i a5, a2, 12 + s32i a4, a1, PT_SIZE + 8 + s32i a5, a1, PT_SIZE + 12 +#endif + + /* Restore address register */ + +1: l32i a15, a1, PT_AREG + 15 * 4 + l32i a14, a1, PT_AREG + 14 * 4 + l32i a13, a1, PT_AREG + 13 * 4 + l32i a12, a1, PT_AREG + 12 * 4 + l32i a11, a1, PT_AREG + 11 * 4 + l32i a10, a1, PT_AREG + 10 * 4 + l32i a9, a1, PT_AREG + 9 * 4 + l32i a8, a1, PT_AREG + 8 * 4 + l32i a7, a1, PT_AREG + 7 * 4 + l32i a6, a1, PT_AREG + 6 * 4 + l32i a5, a1, PT_AREG + 5 * 4 + l32i a4, a1, PT_AREG + 4 * 4 + l32i a3, a1, PT_AREG + 3 * 4 + l32i a2, a1, PT_AREG + 2 * 4 + l32i a0, a1, PT_AREG + 0 * 4 + + l32i a1, a1, PT_AREG + 1 * 4 # Remove ptrace stack frame + + rfe + +#endif /* XCHAL_HAVE_EXCEPTIONS */ + +#if XCHAL_HAVE_WINDOWED + +/* + * Window overflow and underflow handlers. + * The handlers must be 64 bytes apart, first starting with the underflow + * handlers underflow-4 to underflow-12, then the overflow handlers + * overflow-4 to overflow-12. + * + * Note: We rerun the underflow handlers if we hit an exception, so + * we try to access any page that would cause a page fault early. + */ + + .section .WindowVectors.text, "ax" + +/* 4-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow4 +_WindowOverflow4: + s32e a0, a5, -16 + s32e a1, a5, -12 + s32e a2, a5, -8 + s32e a3, a5, -4 + rfwo + + +/* 4-Register Window Underflow Vector (Handler) */ + + .align 64 +.global _WindowUnderflow4 +_WindowUnderflow4: + l32e a0, a5, -16 + l32e a1, a5, -12 + l32e a2, a5, -8 + l32e a3, a5, -4 + rfwu + +/* + * a0: a0 + * a1: new stack pointer = a1 - 16 - 4 + * a2: available, saved in excsave1 + * a3: available, saved on stack *a1 + */ + +/* 15*/ .byte 0xff + +fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 */ + +/* 16*/ rsr a2, PS +/* 19*/ rsr a3, WINDOWBASE +/* 22*/ extui a2, a2, PS_OWB_SHIFT, PS_OWB_SHIFT +/* 25*/ xor a2, a2, a3 +/* 28*/ rsr a3, PS +/* 31*/ slli a2, a2, PS_OWB_SHIFT +/* 34*/ xor a2, a3, a2 +/* 37*/ wsr a2, PS + +/* 40*/ _l32i a3, a1, 0 +/* 43*/ addi a1, a1, 16 + 4 +/* 46*/ rsr a2, EXCSAVE1 + +/* 49*/ rotw -1 +/* 52*/ _bbci.l a4, 31, _WindowUnderflow4 /* 0x: call4 */ +/* 55*/ rotw -1 +/* 58*/ _bbci.l a8, 30, _WindowUnderflow8 /* 10: call8 */ +/* 61*/ _j __WindowUnderflow12 /* 11: call12 */ +/* 64*/ + +/* 8-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow8 +_WindowOverflow8: + s32e a0, a9, -16 + l32e a0, a1, -12 + s32e a2, a9, -8 + s32e a1, a9, -12 + s32e a3, a9, -4 + s32e a4, a0, -32 + s32e a5, a0, -28 + s32e a6, a0, -24 + s32e a7, a0, -20 + rfwo + +/* 8-Register Window Underflow Vector (Handler) */ + + .align 64 +.global _WindowUnderflow8 +_WindowUnderflow8: + l32e a1, a9, -12 + l32e a0, a9, -16 + l32e a7, a1, -12 + l32e a2, a9, -8 + l32e a4, a7, -32 + l32e a3, a9, -4 + l32e a5, a7, -28 + l32e a6, a7, -24 + l32e a7, a7, -20 + rfwu + +/* 12-Register Window Overflow Vector (Handler) */ + + .align 64 +.global _WindowOverflow12 +_WindowOverflow12: + s32e a0, a13, -16 + l32e a0, a1, -12 + s32e a1, a13, -12 + s32e a2, a13, -8 + s32e a3, a13, -4 + s32e a4, a0, -48 + s32e a5, a0, -44 + s32e a6, a0, -40 + s32e a7, a0, -36 + s32e a8, a0, -32 + s32e a9, a0, -28 + s32e a10, a0, -24 + s32e a11, a0, -20 + rfwo + +/* 12-Register Window Underflow Vector (Handler) */ + + .org _WindowOverflow12 + 64 - 3 +__WindowUnderflow12: + rotw -1 +.global _WindowUnderflow12 +_WindowUnderflow12: + l32e a1, a13, -12 + l32e a0, a13, -16 + l32e a11, a1, -12 + l32e a2, a13, -8 + l32e a4, a11, -48 + l32e a8, a11, -32 + l32e a3, a13, -4 + l32e a5, a11, -44 + l32e a6, a11, -40 + l32e a7, a11, -36 + l32e a9, a11, -28 + l32e a10, a11, -24 + l32e a11, a11, -20 + rfwu + +#endif /* XCHAL_HAVE_WINDOWED */ diff --git a/arch/xtensa/cpu/u-boot.lds b/arch/xtensa/cpu/u-boot.lds new file mode 100644 index 0000000..853ae5a --- /dev/null +++ b/arch/xtensa/cpu/u-boot.lds @@ -0,0 +1,116 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica, Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <asm/ldscript.h> +#include <asm/arch/core.h> +#include <asm/addrspace.h> +#include <asm-offsets.h> + +OUTPUT_ARCH(xtensa) +ENTRY(_start) + +/* + * U-Boot resets from SYSROM and unpacks itself from a ROM store to RAM. + * The reset vector is usually near the base of SYSROM and has room + * above it for the ROM store into which the rest of U-Boot is packed. + * The ROM store also needs to be above any other vectors that are in ROM. + * If a core has its vectors near the top of ROM, this must be edited. + * + * Note that to run C code out of ROM, the processor would have to support + * 'relocatable' exception vectors and provide a scratch memory for the + * initial stack. Not all Xtensa processor configurations support that, so + * we can simplify the boot process and unpack U-Boot to RAM immediately. + * This, however, requires that memory have been initialized throug some + * other means (serial ROM, for example) or are initialized early (requiring + * an assembler function. See start.S for more details) + */ + +SECTIONS +{ + . = + SIZEOF_HEADERS; + SECTION_ResetVector(XCHAL_RESET_VECTOR_VADDR, LMA_EQ_VMA) + + .reloc_table ALIGN(4) : FOLLOWING(.ResetVector.text) + { + __reloc_table_start = ABSOLUTE(.); +#if XCHAL_HAVE_WINDOWED + RELOCATE2(WindowVectors,text); +#endif + RELOCATE2(KernelExceptionVector,literal); + RELOCATE2(KernelExceptionVector,text); + RELOCATE2(UserExceptionVector,literal); + RELOCATE2(UserExceptionVector,text); + RELOCATE2(DoubleExceptionVector,literal); + RELOCATE2(DoubleExceptionVector,text); + RELOCATE1(text); + RELOCATE1(rodata); + RELOCATE1(data); + RELOCATE1(u_boot_list); + __reloc_table_end = ABSOLUTE(.); + } + +#if XCHAL_HAVE_WINDOWED + SECTION_VECTOR(WindowVectors,text,XCHAL_WINDOW_VECTORS_VADDR, + FOLLOWING(.reloc_table)) + SECTION_VECTOR(KernelExceptionVector,literal,XCHAL_KERNEL_VECTOR_VADDR-8, + FOLLOWING(.WindowVectors.text)) +#else + SECTION_VECTOR(KernelExceptionVector,literal,XCHAL_KERNEL_VECTOR_VADDR-8, + FOLLOWING(.reloc_table)) +#endif + SECTION_VECTOR(KernelExceptionVector,text,XCHAL_KERNEL_VECTOR_VADDR, + FOLLOWING(.KernelExceptionVector.literal)) + SECTION_VECTOR(UserExceptionVector,literal,XCHAL_USER_VECTOR_VADDR-8, + FOLLOWING(.KernelExceptionVector.text)) + SECTION_VECTOR(UserExceptionVector,text,XCHAL_USER_VECTOR_VADDR, + FOLLOWING(.UserExceptionVector.literal)) + SECTION_VECTOR(DoubleExceptionVector,literal,XCHAL_DOUBLEEXC_VECTOR_VADDR-8, + FOLLOWING(.UserExceptionVector.text)) + SECTION_VECTOR(DoubleExceptionVector,text,XCHAL_DOUBLEEXC_VECTOR_VADDR, + FOLLOWING(.DoubleExceptionVector.literal)) + + __monitor_start = CONFIG_SYS_TEXT_ADDR; + + SECTION_text(CONFIG_SYS_TEXT_ADDR, FOLLOWING(.DoubleExceptionVector.text)) + SECTION_rodata(ALIGN(16), FOLLOWING(.text)) + SECTION_u_boot_list(ALIGN(16), FOLLOWING(.rodata)) + SECTION_data(ALIGN(16), FOLLOWING(.u_boot_list)) + + __reloc_end = .; + __init_end = .; + + SECTION_bss(__init_end (OVERLAY),) + + __monitor_end = .; + + /* + * On many Xtensa boards a region of RAM may be mapped to the ROM address + * space to facilitate on-chip-debug, and U-Boot must fit with that region. + * The config variables CONFIG_SYS_MONITOR_* define the region. + * If U-Boot extends beyond this region it will appear discontiguous in the + * address space and is in danger of overwriting itself during unpacking + * ("relocation"). + * This causes U-Boot to crash in a way that is difficult to debug. On some + * boards (such as xtav60) the region is small enough that U-Boot will not + * fit if compiled entirely with -O0 (a common scenario). To avoid a lengthy + * debugging session when this happens, ensure a link-time error occurs. + * + */ + + ASSERT(__monitor_end - __monitor_start <= CONFIG_SYS_MONITOR_LEN, + "U-Boot ROM image is too large. Check optimization level.") + + SECTION_xtensa + SECTION_debug + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.hash*) } + /DISCARD/ : { *(.interp) } + /DISCARD/ : { *(.got*) } + /DISCARD/ : { *(.dynsym) } +} diff --git a/arch/xtensa/dts/Makefile b/arch/xtensa/dts/Makefile new file mode 100644 index 0000000..eacf6f3 --- /dev/null +++ b/arch/xtensa/dts/Makefile @@ -0,0 +1,13 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +targets += $(dtb-y) + +DTC_FLAGS += + +PHONY += dtbs +dtbs: $(addprefix $(obj)/, $(dtb-y)) + @: + +clean-files := *.dtb diff --git a/arch/xtensa/dts/include/dt-bindings b/arch/xtensa/dts/include/dt-bindings new file mode 120000 index 0000000..0cecb3d --- /dev/null +++ b/arch/xtensa/dts/include/dt-bindings @@ -0,0 +1 @@ +../../../../include/dt-bindings
\ No newline at end of file diff --git a/arch/xtensa/include/asm/addrspace.h b/arch/xtensa/include/asm/addrspace.h new file mode 100644 index 0000000..1d62259 --- /dev/null +++ b/arch/xtensa/include/asm/addrspace.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2008-2013 Tensilica Inc. + * Copyright (C) 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_ADDRSPACE_H +#define _XTENSA_ADDRSPACE_H + +#include <asm/arch/core.h> + +/* + * MMU Memory Map + * + * noMMU and v3 MMU have identity mapped address space on reset. + * V2 MMU: + * IO (uncached) f0000000..ffffffff -> f000000 + * IO (cached) e0000000..efffffff -> f000000 + * MEM (uncached) d8000000..dfffffff -> 0000000 + * MEM (cached) d0000000..d7ffffff -> 0000000 + * + * The actual location of memory and IO is the board property. + */ + +#define IOADDR(x) (CONFIG_SYS_IO_BASE + (x)) +#define MEMADDR(x) (CONFIG_SYS_MEMORY_BASE + (x)) +#define PHYSADDR(x) ((x) - XCHAL_VECBASE_RESET_VADDR + \ + XCHAL_VECBASE_RESET_PADDR) + +#endif /* _XTENSA_ADDRSPACE_H */ diff --git a/arch/xtensa/include/asm/asmmacro.h b/arch/xtensa/include/asm/asmmacro.h new file mode 100644 index 0000000..b7adc7e --- /dev/null +++ b/arch/xtensa/include/asm/asmmacro.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2005 - 2013 Tensilica Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_ASMMACRO_H +#define _XTENSA_ASMMACRO_H + +#include <asm/arch/core.h> + +/* + * Function entry and return macros for supported ABIs. + */ + +#if defined(__XTENSA_WINDOWED_ABI__) +#define abi_entry entry sp, 16 +#define abi_ret retw +#elif defined(__XTENSA_CALL0_ABI__) +#define abi_entry +#define abi_ret ret +#else +#error Unsupported Xtensa ABI +#endif + +/* + * Some little helpers for loops. Use zero-overhead-loops + * where applicable and if supported by the processor. + * + * __loopi ar, at, size, inc + * ar register initialized with the start address + * at scratch register used by macro + * size size immediate value + * inc increment + * + * __loops ar, as, at, inc_log2[, mask_log2][, cond][, ncond] + * ar register initialized with the start address + * as register initialized with the size + * at scratch register use by macro + * inc_log2 increment [in log2] + * mask_log2 mask [in log2] + * cond true condition (used in loop'cond') + * ncond false condition (used in b'ncond') + * + * __loop as + * restart loop. 'as' register must not have been modified! + * + * __endla ar, as, incr + * ar start address (modified) + * as scratch register used by __loops/__loopi macros or + * end address used by __loopt macro + * inc increment + */ + +#if XCHAL_HAVE_LOOPS + +.macro __loopi ar, at, size, incr + movi \at, ((\size + \incr - 1) / (\incr)) + loop \at, 99f +.endm + + +.macro __loops ar, as, at, incr_log2, mask_log2, cond, ncond + .ifgt \incr_log2 - 1 + addi \at, \as, (1 << \incr_log2) - 1 + .ifnc \mask_log2, + extui \at, \at, \incr_log2, \mask_log2 + .else + srli \at, \at, \incr_log2 + .endif + .endif + loop\cond \at, 99f +.endm + + +.macro __loopt ar, as, at, incr_log2 + sub \at, \as, \ar + .ifgt \incr_log2 - 1 + addi \at, \at, (1 << \incr_log2) - 1 + srli \at, \at, \incr_log2 + .endif + loop \at, 99f +.endm + + +.macro __loop as + loop \as, 99f +.endm + + +.macro __endl ar, as +99: +.endm + + +#else + +.macro __loopi ar, at, size, incr + movi \at, ((\size + \incr - 1) / (\incr)) + addi \at, \ar, \size +98: +.endm + + +.macro __loops ar, as, at, incr_log2, mask_log2, cond, ncond + .ifnc \mask_log2, + extui \at, \as, \incr_log2, \mask_log2 + .else + .ifnc \ncond, + srli \at, \as, \incr_log2 + .endif + .endif + .ifnc \ncond, + b\ncond \at, 99f + + .endif + .ifnc \mask_log2, + slli \at, \at, \incr_log2 + add \at, \ar, \at + .else + add \at, \ar, \as + .endif +98: +.endm + +.macro __loopt ar, as, at, incr_log2 +98: +.endm + + +.macro __loop as +98: +.endm + + +.macro __endl ar, as + bltu \ar, \as, 98b +99: +.endm + + +#endif + + +.macro __endla ar, as, incr + addi \ar, \ar, \incr + __endl \ar \as +.endm + + +#endif /* _XTENSA_ASMMACRO_H */ diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h new file mode 100644 index 0000000..a75baa0 --- /dev/null +++ b/arch/xtensa/include/asm/atomic.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_ATOMIC_H +#define _XTENSA_ATOMIC_H + +#include <asm/system.h> + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v, i) ((v)->counter = (i)) + +static inline void atomic_add(int i, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter += i; + local_irq_restore(flags); +} + +static inline void atomic_sub(int i, atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter -= i; + local_irq_restore(flags); +} + +static inline void atomic_inc(atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + ++v->counter; + local_irq_restore(flags); +} + +static inline void atomic_dec(atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + --v->counter; + local_irq_restore(flags); +} + +#endif diff --git a/arch/xtensa/include/asm/bitops.h b/arch/xtensa/include/asm/bitops.h new file mode 100644 index 0000000..550d12f --- /dev/null +++ b/arch/xtensa/include/asm/bitops.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2001 - 2012 Tensilica Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_BITOPS_H +#define _XTENSA_BITOPS_H + +#include <asm/system.h> +#include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/fls64.h> +#include <asm-generic/bitops/__ffs.h> + +static inline int test_bit(int nr, const void *addr) +{ + return ((unsigned char *)addr)[nr >> 3] & (1u << (nr & 7)); +} + +static inline int test_and_set_bit(int nr, volatile void *addr) +{ + unsigned long flags; + unsigned char tmp; + unsigned char mask = 1u << (nr & 7); + + local_irq_save(flags); + tmp = ((unsigned char *)addr)[nr >> 3]; + ((unsigned char *)addr)[nr >> 3] |= mask; + local_irq_restore(flags); + + return tmp & mask; +} + +#endif /* _XTENSA_BITOPS_H */ diff --git a/arch/xtensa/include/asm/bootparam.h b/arch/xtensa/include/asm/bootparam.h new file mode 100644 index 0000000..a2a9013 --- /dev/null +++ b/arch/xtensa/include/asm/bootparam.h @@ -0,0 +1,54 @@ +/* + * Definition of the Linux/Xtensa boot parameter structure + * + * Copyright (C) 2001 - 2009 Tensilica Inc. + * + * (Concept borrowed from the 68K port) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_BOOTPARAM_H +#define _XTENSA_BOOTPARAM_H + +#define BP_VERSION 0x0001 + +#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/ +#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */ +#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */ +#define BP_TAG_SERIAL_BAUDRATE 0x1004 /* baud rate of current console */ +#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */ +#define BP_TAG_FDT 0x1006 /* flat device tree */ + +#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */ +#define BP_TAG_LAST 0x7E0B /* last tag */ + +#ifndef __ASSEMBLY__ + +/* All records are aligned to 4 bytes */ + +struct bp_tag { + unsigned short id; /* tag id */ + unsigned short size; /* size of this record excluding the structure*/ + unsigned long data[0]; /* data */ +}; + +#define bp_tag_next(tag) \ + ((struct bp_tag *)((unsigned long)((tag) + 1) + (tag)->size)) + +struct meminfo { + unsigned long type; + unsigned long start; + unsigned long end; +}; + +#define MEMORY_TYPE_CONVENTIONAL 0x1000 +#define MEMORY_TYPE_NONE 0x2000 + +struct sysmem_info { + int nr_banks; + struct meminfo bank[0]; +}; + +#endif +#endif diff --git a/arch/xtensa/include/asm/byteorder.h b/arch/xtensa/include/asm/byteorder.h new file mode 100644 index 0000000..278653c --- /dev/null +++ b/arch/xtensa/include/asm/byteorder.h @@ -0,0 +1,83 @@ +/* + * Based on Linux/Xtensa kernel version + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_BYTEORDER_H +#define _XTENSA_BYTEORDER_H + +#include <asm/types.h> + +static inline __attribute__((const)) __u32 ___arch__swab32(__u32 x) +{ + __u32 res; + + /* instruction sequence from Xtensa ISA release 2/2000 */ + __asm__("ssai 8\n\t" + "srli %0, %1, 16\n\t" + "src %0, %0, %1\n\t" + "src %0, %0, %0\n\t" + "src %0, %1, %0\n" + : "=&a" (res) + : "a" (x) + ); + return res; +} + +static inline __attribute__((const)) __u16 ___arch__swab16(__u16 x) +{ + /* + * Given that 'short' values are signed (i.e., can be negative), + * we cannot assume that the upper 16-bits of the register are + * zero. We are careful to mask values after shifting. + */ + + /* + * There exists an anomaly between xt-gcc and xt-xcc. xt-gcc + * inserts an extui instruction after putting this function inline + * to ensure that it uses only the least-significant 16 bits of + * the result. xt-xcc doesn't use an extui, but assumes the + * __asm__ macro follows convention that the upper 16 bits of an + * 'unsigned short' result are still zero. This macro doesn't + * follow convention; indeed, it leaves garbage in the upport 16 + * bits of the register. + * + * Declaring the temporary variables 'res' and 'tmp' to be 32-bit + * types while the return type of the function is a 16-bit type + * forces both compilers to insert exactly one extui instruction + * (or equivalent) to mask off the upper 16 bits. + */ + + __u32 res; + __u32 tmp; + + __asm__("extui %1, %2, 8, 8\n\t" + "slli %0, %2, 8\n\t" + "or %0, %0, %1\n" + : "=&a" (res), "=&a" (tmp) + : "a" (x) + ); + + return res; +} + +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#ifdef __XTENSA_EL__ +# include <linux/byteorder/little_endian.h> +#elif defined(__XTENSA_EB__) +# include <linux/byteorder/big_endian.h> +#else +# error processor byte order undefined! +#endif + +#endif /* _XTENSA_BYTEORDER_H */ diff --git a/arch/xtensa/include/asm/cache.h b/arch/xtensa/include/asm/cache.h new file mode 100644 index 0000000..08c534c --- /dev/null +++ b/arch/xtensa/include/asm/cache.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _XTENSA_CACHE_H +#define _XTENSA_CACHE_H + +#include <asm/arch/core.h> + +#define ARCH_DMA_MINALIGN XCHAL_DCACHE_LINESIZE + +#ifndef __ASSEMBLY__ + +void __flush_dcache_all(void); +void __flush_invalidate_dcache_range(unsigned long addr, unsigned long size); +void __invalidate_dcache_all(void); +void __invalidate_dcache_range(unsigned long addr, unsigned long size); + +void __invalidate_icache_all(void); +void __invalidate_icache_range(unsigned long addr, unsigned long size); + +#endif + +#endif /* _XTENSA_CACHE_H */ diff --git a/arch/xtensa/include/asm/cacheasm.h b/arch/xtensa/include/asm/cacheasm.h new file mode 100644 index 0000000..342a817 --- /dev/null +++ b/arch/xtensa/include/asm/cacheasm.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2006 Tensilica Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_CACHEASM_H +#define _XTENSA_CACHEASM_H + +#include <asm/cache.h> +#include <asm/asmmacro.h> +#include <linux/stringify.h> + +#define PAGE_SIZE 4096 +#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) +#define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) +#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) +#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) + +/* + * Define cache functions as macros here so that they can be used + * by the kernel and boot loader. We should consider moving them to a + * library that can be linked by both. + * + * Locking + * + * ___unlock_dcache_all + * ___unlock_icache_all + * + * Flush and invaldating + * + * ___flush_invalidate_dcache_{all|range|page} + * ___flush_dcache_{all|range|page} + * ___invalidate_dcache_{all|range|page} + * ___invalidate_icache_{all|range|page} + * + */ + + .macro __loop_cache_all ar at insn size line_width + + movi \ar, 0 + + __loopi \ar, \at, \size, (4 << (\line_width)) + + \insn \ar, 0 << (\line_width) + \insn \ar, 1 << (\line_width) + \insn \ar, 2 << (\line_width) + \insn \ar, 3 << (\line_width) + + __endla \ar, \at, 4 << (\line_width) + + .endm + + + .macro __loop_cache_range ar as at insn line_width + + extui \at, \ar, 0, \line_width + add \as, \as, \at + + __loops \ar, \as, \at, \line_width + \insn \ar, 0 + __endla \ar, \at, (1 << (\line_width)) + + .endm + + + .macro __loop_cache_page ar at insn line_width + + __loopi \ar, \at, PAGE_SIZE, 4 << (\line_width) + + \insn \ar, 0 << (\line_width) + \insn \ar, 1 << (\line_width) + \insn \ar, 2 << (\line_width) + \insn \ar, 3 << (\line_width) + + __endla \ar, \at, 4 << (\line_width) + + .endm + + + .macro ___unlock_dcache_all ar at + +#if XCHAL_DCACHE_LINE_LOCKABLE && XCHAL_DCACHE_SIZE + __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___unlock_icache_all ar at + +#if XCHAL_ICACHE_LINE_LOCKABLE && XCHAL_ICACHE_SIZE + __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE XCHAL_ICACHE_LINEWIDTH +#endif + + .endm + + + .macro ___flush_invalidate_dcache_all ar at + +#if XCHAL_DCACHE_SIZE + __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___flush_dcache_all ar at + +#if XCHAL_DCACHE_SIZE + __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_dcache_all ar at + +#if XCHAL_DCACHE_SIZE + __loop_cache_all \ar \at dii __stringify(DCACHE_WAY_SIZE) \ + XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_icache_all ar at + +#if XCHAL_ICACHE_SIZE + __loop_cache_all \ar \at iii __stringify(ICACHE_WAY_SIZE) \ + XCHAL_ICACHE_LINEWIDTH +#endif + + .endm + + + + .macro ___flush_invalidate_dcache_range ar as at + +#if XCHAL_DCACHE_SIZE + __loop_cache_range \ar \as \at dhwbi XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___flush_dcache_range ar as at + +#if XCHAL_DCACHE_SIZE + __loop_cache_range \ar \as \at dhwb XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_dcache_range ar as at + +#if XCHAL_DCACHE_SIZE + __loop_cache_range \ar \as \at dhi XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_icache_range ar as at + +#if XCHAL_ICACHE_SIZE + __loop_cache_range \ar \as \at ihi XCHAL_ICACHE_LINEWIDTH +#endif + + .endm + + + + .macro ___flush_invalidate_dcache_page ar as + +#if XCHAL_DCACHE_SIZE + __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___flush_dcache_page ar as + +#if XCHAL_DCACHE_SIZE + __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_dcache_page ar as + +#if XCHAL_DCACHE_SIZE + __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH +#endif + + .endm + + + .macro ___invalidate_icache_page ar as + +#if XCHAL_ICACHE_SIZE + __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH +#endif + + .endm + +#endif /* _XTENSA_CACHEASM_H */ diff --git a/arch/xtensa/include/asm/config.h b/arch/xtensa/include/asm/config.h new file mode 100644 index 0000000..db1ea87 --- /dev/null +++ b/arch/xtensa/include/asm/config.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2009 Tensilica Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_CONFIG_H_ +#define _ASM_CONFIG_H_ + +#include <asm/arch/core.h> + +#define CONFIG_LMB + +/* + * Make boot parameters available in the MMUv2 virtual memory layout by + * restricting used physical memory to the first 128MB. + */ +#if XCHAL_HAVE_PTP_MMU +#define CONFIG_VERY_BIG_RAM +#define CONFIG_MAX_MEM_MAPPED (128 << 20) +#endif + +#endif diff --git a/arch/xtensa/include/asm/errno.h b/arch/xtensa/include/asm/errno.h new file mode 100644 index 0000000..4c82b50 --- /dev/null +++ b/arch/xtensa/include/asm/errno.h @@ -0,0 +1 @@ +#include <asm-generic/errno.h> diff --git a/arch/xtensa/include/asm/global_data.h b/arch/xtensa/include/asm/global_data.h new file mode 100644 index 0000000..4569345 --- /dev/null +++ b/arch/xtensa/include/asm/global_data.h @@ -0,0 +1,20 @@ +/* + * (C) Copyright 2007, Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_GBL_DATA_H +#define _XTENSA_GBL_DATA_H + +/* Architecture-specific global data */ + +struct arch_global_data { + unsigned long cpu_clk; +}; + +#include <asm-generic/global_data.h> + +#define DECLARE_GLOBAL_DATA_PTR extern gd_t *gd + +#endif /* _XTENSA_GBL_DATA_H */ diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h new file mode 100644 index 0000000..e34d6e1 --- /dev/null +++ b/arch/xtensa/include/asm/io.h @@ -0,0 +1,148 @@ +/* + * IO header file + * + * Copyright (C) 2001-2007 Tensilica Inc. + * Based on the Linux/Xtensa version of this header. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_IO_H +#define _XTENSA_IO_H + +#include <linux/types.h> +#include <asm/byteorder.h> + +/* + * swap functions to change byte order from little-endian to big-endian and + * vice versa. + */ + +static inline unsigned short _swapw(unsigned short v) +{ + return (v << 8) | (v >> 8); +} + +static inline unsigned int _swapl(unsigned int v) +{ + return (v << 24) | ((v & 0xff00) << 8) | + ((v >> 8) & 0xff00) | (v >> 24); +} + +/* + * Generic I/O + */ + +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *)(addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *)(addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *)(addr)); __v; }) +#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b)) +#define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b)) +#define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b)) + +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +/* These are the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl, the "string" versions + * insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions + * inb_p/inw_p/... + * The macros don't do byte-swapping. + */ + +#define inb(port) readb((u8 *)((port))) +#define outb(val, port) writeb((val), (u8 *)((unsigned long)(port))) +#define inw(port) readw((u16 *)((port))) +#define outw(val, port) writew((val), (u16 *)((unsigned long)(port))) +#define inl(port) readl((u32 *)((port))) +#define outl(val, port) writel((val), (u32 *)((unsigned long)(port))) + +#define inb_p(port) inb((port)) +#define outb_p(val, port) outb((val), (port)) +#define inw_p(port) inw((port)) +#define outw_p(val, port) outw((val), (port)) +#define inl_p(port) inl((port)) +#define outl_p(val, port) outl((val), (port)) + +void insb(unsigned long port, void *dst, unsigned long count); +void insw(unsigned long port, void *dst, unsigned long count); +void insl(unsigned long port, void *dst, unsigned long count); +void outsb(unsigned long port, const void *src, unsigned long count); +void outsw(unsigned long port, const void *src, unsigned long count); +void outsl(unsigned long port, const void *src, unsigned long count); + +#define IO_SPACE_LIMIT ~0 + +#define memset_io(a, b, c) memset((void *)(a), (b), (c)) +#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c)) +#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c)) + +/* At this point the Xtensa doesn't provide byte swap instructions */ + +#ifdef __XTENSA_EB__ +# define in_8(addr) (*(u8 *)(addr)) +# define in_le16(addr) _swapw(*(u16 *)(addr)) +# define in_le32(addr) _swapl(*(u32 *)(addr)) +# define out_8(b, addr) *(u8 *)(addr) = (b) +# define out_le16(b, addr) *(u16 *)(addr) = _swapw(b) +# define out_le32(b, addr) *(u32 *)(addr) = _swapl(b) +#elif defined(__XTENSA_EL__) +# define in_8(addr) (*(u8 *)(addr)) +# define in_le16(addr) (*(u16 *)(addr)) +# define in_le32(addr) (*(u32 *)(addr)) +# define out_8(b, addr) *(u8 *)(addr) = (b) +# define out_le16(b, addr) *(u16 *)(addr) = (b) +# define out_le32(b, addr) *(u32 *)(addr) = (b) +#else +# error processor byte order undefined! +#endif + + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void * +map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ +} + +static inline phys_addr_t virt_to_phys(void *vaddr) +{ + return (phys_addr_t)((unsigned long)vaddr); +} + +/* + * Dummy function to keep U-Boot's cfi_flash.c driver happy. + */ +static inline void sync(void) +{ +} + +#endif /* _XTENSA_IO_H */ diff --git a/arch/xtensa/include/asm/ldscript.h b/arch/xtensa/include/asm/ldscript.h new file mode 100644 index 0000000..62a1c05 --- /dev/null +++ b/arch/xtensa/include/asm/ldscript.h @@ -0,0 +1,222 @@ +/* + * (C) Copyright 2007 Tensilica, Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_LDSCRIPT_H +#define _XTENSA_LDSCRIPT_H + +/* + * This linker script is pre-processed with CPP to avoid hard-coding + * addresses that depend on the Xtensa core configuration, because + * this FPGA board can be used with a huge variety of Xtensa cores. + */ + +#include <asm/arch/core.h> +#include <asm/addrspace.h> + +#define ALIGN_LMA 4 +#define LMA_EQ_VMA +#define FORCE_OUTPUT . = . +#define FOLLOWING(sec) \ + AT(((LOADADDR(sec) + SIZEOF(sec) + ALIGN_LMA-1)) & ~(ALIGN_LMA-1)) + +/* + * Specify an output section that will be added to the ROM store table + * (PACKED_SECTION) or one that will be resident in ROM (RESIDENT_SECTION). + * 'symname' is a base name for section boundary symbols *_start & *_end. + * 'lma' is the load address at which a section will be packed in ROM. + * 'region' is the basename identifying a memory region and program header. + * 'keep' prevents removal of empty sections (must be 'KEEP' or 'NOKEEP'). + */ + +#define RELOCATE1(_sec_) \ + LONG(_##_sec_##_start); \ + LONG(_##_sec_##_end); \ + LONG(LOADADDR(.##_sec_)); + +#define RELOCATE2(_sym_, _sec_) \ + LONG(_##_sym_##_##_sec_##_start); \ + LONG(_##_sym_##_##_sec_##_end); \ + LONG(LOADADDR(.##_sym_##.##_sec_)); + +#define SECTION_VECTOR(_sym_, _sec_, _vma_, _lma_) \ +.##_sym_##.##_sec_ _vma_ : _lma_ \ +{ \ + . = ALIGN(4); \ + _##_sym_##_##_sec_##_start = ABSOLUTE(.); \ + KEEP(*(.##_sym_##.##_sec_)) \ + _##_sym_##_##_sec_##_end = ABSOLUTE(.); \ +} + +/* In MMU configs there are two aliases of SYSROM, cached and uncached. + * For various reasons it is simpler to use the uncached mapping for load + * addresses, so ROM sections end up contiguous with the reset vector and + * we get a compact binary image. However we can gain performance by doing + * the unpacking from the cached ROM mapping. So we adjust all the load + * addresses in the ROM store table with an offset to the cached mapping, + * including the symbols referring to the ROM store table itself. + */ + +#define SECTION_ResetVector(_vma_, _lma_) \ + .ResetVector.text _vma_ : _lma_ \ + { \ + FORCE_OUTPUT; \ + KEEP(*(.ResetVector.text)); \ + KEEP(*(.reset.literal .reset.text)) \ + } + +#define SECTION_text(_vma_, _lma_) \ + .text _vma_ : _lma_ \ + { \ + _text_start = ABSOLUTE(.); \ + *(.literal .text) \ + *(.literal.* .text.* .stub) \ + *(.gnu.warning .gnu.linkonce.literal.*) \ + *(.gnu.linkonce.t.*.literal .gnu.linkonce.t.*) \ + *(.fini.literal) \ + *(.fini) \ + *(.gnu.version) \ + _text_end = ABSOLUTE(.); \ + } + +#define SECTION_rodata(_vma_, _lma_) \ + .rodata _vma_ : _lma_ \ + { \ + _rodata_start = ABSOLUTE(.); \ + *(.rodata) \ + *(.rodata.*) \ + *(.dtb.init.rodata) \ + *(.gnu.linkonce.r.*) \ + *(.rodata1) \ + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); \ + *(.xt_except_table) \ + *(.gcc_except_table) \ + *(.gnu.linkonce.e.*) \ + *(.gnu.version_r) \ + . = ALIGN(16); \ + _rodata_end = ABSOLUTE(.); \ + } + +#define SECTION_u_boot_list(_vma_, _lma_) \ + .u_boot_list _vma_ : _lma_ \ + { \ + _u_boot_list_start = ABSOLUTE(.); \ + KEEP(*(SORT(.u_boot_list*))); \ + _u_boot_list_end = ABSOLUTE(.); \ + } + +#define SECTION_data(_vma_, _lma_) \ + .data _vma_ : _lma_ \ + { \ + _data_start = ABSOLUTE(.); \ + *(.data) \ + *(.data.*) \ + *(.gnu.linkonce.d.*) \ + *(.data1) \ + *(.sdata) \ + *(.sdata.*) \ + *(.gnu.linkonce.s.*) \ + *(.sdata2) \ + *(.sdata2.*) \ + *(.gnu.linkonce.s2.*) \ + *(.jcr) \ + *(.eh_frame) \ + *(.dynamic) \ + *(.gnu.version_d) \ + _data_end = ABSOLUTE(.); \ + } + +#define SECTION_lit4(_vma_, _lma_) \ + .lit4 _vma_ : _lma_ \ + { \ + _lit4_start = ABSOLUTE(.); \ + *(*.lit4) \ + *(.gnu.linkonce.lit4.*) \ + _lit4_end = ABSOLUTE(.); \ + } + +#define SECTION_bss(_vma_, _lma_) \ + .bss _vma_ : _lma_ \ + { \ + . = ALIGN(8); \ + _bss_start = ABSOLUTE(.); \ + __bss_start = ABSOLUTE(.); \ + *(.dynsbss) \ + *(.sbss) \ + *(.sbss.*) \ + *(.gnu.linkonce.sb.*) \ + *(.scommon) \ + *(.sbss2) \ + *(.sbss2.*) \ + *(.gnu.linkonce.sb2.*) \ + *(.dynbss) \ + *(.bss) \ + *(.bss.*) \ + *(.gnu.linkonce.b.*) \ + *(COMMON) \ + *(.sram.bss) \ + . = ALIGN(8); \ + _bss_end = ABSOLUTE(.); \ + __bss_end = ABSOLUTE(.); \ + _end = ALIGN(0x8); \ + PROVIDE(end = ALIGN(0x8)); \ + _stack_sentry = ALIGN(0x8); \ + } + +#define SECTION_debug \ + .debug 0 : { *(.debug) } \ + .line 0 : { *(.line) } \ + .debug_srcinfo 0 : { *(.debug_srcinfo) } \ + .debug_sfnames 0 : { *(.debug_sfnames) } \ + .debug_aranges 0 : { *(.debug_aranges) } \ + .debug_pubnames 0 : { *(.debug_pubnames) } \ + .debug_info 0 : { *(.debug_info) } \ + .debug_abbrev 0 : { *(.debug_abbrev) } \ + .debug_line 0 : { *(.debug_line) } \ + .debug_frame 0 : { *(.debug_frame) } \ + .debug_str 0 : { *(.debug_str) } \ + .debug_loc 0 : { *(.debug_loc) } \ + .debug_macinfo 0 : { *(.debug_macinfo) } \ + .debug_weaknames 0 : { *(.debug_weaknames) } \ + .debug_funcnames 0 : { *(.debug_funcnames) } \ + .debug_typenames 0 : { *(.debug_typenames) } \ + .debug_varnames 0 : { *(.debug_varnames) } + +#define SECTION_xtensa \ + .xt.insn 0 : \ + { \ + KEEP (*(.xt.insn)) \ + KEEP (*(.gnu.linkonce.x.*)) \ + } \ + .xt.prop 0 : \ + { \ + KEEP (*(.xt.prop)) \ + KEEP (*(.xt.prop.*)) \ + KEEP (*(.gnu.linkonce.prop.*)) \ + } \ + .xt.lit 0 : \ + { \ + KEEP (*(.xt.lit)) \ + KEEP (*(.xt.lit.*)) \ + KEEP (*(.gnu.linkonce.p.*)) \ + } \ + .xt.profile_range 0 : \ + { \ + KEEP (*(.xt.profile_range)) \ + KEEP (*(.gnu.linkonce.profile_range.*)) \ + } \ + .xt.profile_ranges 0 : \ + { \ + KEEP (*(.xt.profile_ranges)) \ + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) \ + } \ + .xt.profile_files 0 : \ + { \ + KEEP (*(.xt.profile_files)) \ + KEEP (*(.gnu.linkonce.xt.profile_files.*)) \ + } + +#endif /* _XTENSA_LDSCRIPT_H */ diff --git a/arch/xtensa/include/asm/linkage.h b/arch/xtensa/include/asm/linkage.h new file mode 100644 index 0000000..3f46161 --- /dev/null +++ b/arch/xtensa/include/asm/linkage.h @@ -0,0 +1,4 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#endif diff --git a/arch/xtensa/include/asm/misc.h b/arch/xtensa/include/asm/misc.h new file mode 100644 index 0000000..5a2708f --- /dev/null +++ b/arch/xtensa/include/asm/misc.h @@ -0,0 +1,20 @@ +/* + * (C) Copyright 2008, Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef _XTENSA_MISC_H +#define _XTENSA_MISC_H + +/* Used in cpu/xtensa/cpu.c */ +void board_reset(void); + +#endif /* _XTENSA_MISC_H */ diff --git a/arch/xtensa/include/asm/posix_types.h b/arch/xtensa/include/asm/posix_types.h new file mode 100644 index 0000000..821115c --- /dev/null +++ b/arch/xtensa/include/asm/posix_types.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007, Tensilica Inc. + * + * Based on the ARM version: Copyright (C) 1996-1998 Russell King. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _XTENSA_POSIX_TYPES_H +#define _XTENSA_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset(fdsetp, 0, sizeof(*(fd_set *)fdsetp))) + +#endif + +#endif /* _XTENSA_POSIX_TYPES_H */ diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h new file mode 100644 index 0000000..8822f80 --- /dev/null +++ b/arch/xtensa/include/asm/processor.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 1997 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_PROCESSOR_H +#define _XTENSA_PROCESSOR_H + + +#endif /* _XTENSA_PROCESSOR_H */ diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h new file mode 100644 index 0000000..d187dbf --- /dev/null +++ b/arch/xtensa/include/asm/ptrace.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2001 - 2007 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_PTRACE_H +#define _XTENSA_PTRACE_H + +#include <compiler.h> + +/* + * Kernel stack + * + * +-----------------------+ -------- STACK_SIZE + * | register file | | + * +-----------------------+ | + * | struct pt_regs | | + * +-----------------------+ | ------ PT_REGS_OFFSET + * double : 16 bytes spill area : | ^ + * exception :- - - - - - - - - - - -: | | + * frame : struct pt_regs : | | + * :- - - - - - - - - - - -: | | + * | | | | + * | memory stack | | | + * | | | | + * ~ ~ ~ ~ + * ~ ~ ~ ~ + * | | | | + * | | | | + * +-----------------------+ | | --- STACK_BIAS + * | struct task_struct | | | ^ + * current --> +-----------------------+ | | | + * | struct thread_info | | | | + * +-----------------------+ -------- + */ + +#define KERNEL_STACK_SIZE (2 * PAGE_SIZE) + +/* Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables) */ + +#define EXC_TABLE_KSTK 0x004 /* Kernel Stack */ +#define EXC_TABLE_DOUBLE_SAVE 0x008 /* Double exception save area for a0 */ +#define EXC_TABLE_FIXUP 0x00c /* Fixup handler */ +#define EXC_TABLE_PARAM 0x010 /* For passing a parameter to fixup */ +#define EXC_TABLE_SYSCALL_SAVE 0x014 /* For fast syscall handler */ +#define EXC_TABLE_FAST_USER 0x100 /* Fast user exception handler */ +#define EXC_TABLE_FAST_KERNEL 0x200 /* Fast kernel exception handler */ +#define EXC_TABLE_DEFAULT 0x300 /* Default C-Handler */ +#define EXC_TABLE_SIZE 0x400 + +/* Registers used by strace */ + +#define REG_A_BASE 0xfc000000 +#define REG_AR_BASE 0x04000000 +#define REG_PC 0x14000000 +#define REG_PS 0x080000e6 +#define REG_WB 0x08000048 +#define REG_WS 0x08000049 +#define REG_LBEG 0x08000000 +#define REG_LEND 0x08000001 +#define REG_LCOUNT 0x08000002 +#define REG_SAR 0x08000003 +#define REG_DEPC 0x080000c0 +#define REG_EXCCAUSE 0x080000e8 +#define REG_EXCVADDR 0x080000ee +#define SYSCALL_NR 0x1 + +#define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1) + +/* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */ + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_GETFPREGSIZE 18 + +#ifndef __ASSEMBLY__ + +/* + * This struct defines the way the registers are stored on the + * kernel stack during a system call or other kernel entry. + */ +struct pt_regs { + unsigned long pc; /* 4 */ + unsigned long ps; /* 8 */ + unsigned long depc; /* 12 */ + unsigned long exccause; /* 16 */ + unsigned long excvaddr; /* 20 */ + unsigned long debugcause; /* 24 */ + unsigned long wmask; /* 28 */ + unsigned long lbeg; /* 32 */ + unsigned long lend; /* 36 */ + unsigned long lcount; /* 40 */ + unsigned long sar; /* 44 */ + unsigned long windowbase; /* 48 */ + unsigned long windowstart; /* 52 */ + unsigned long syscall; /* 56 */ + unsigned long icountlevel; /* 60 */ + int reserved[1]; /* 64 */ + + /* Make sure the areg field is 16 bytes aligned */ + int align[0] __aligned(16); + + /* current register frame. + * Note: The ESF for kernel exceptions ends after 16 registers! + */ + unsigned long areg[16]; /* 128 (64) */ +}; + +#ifdef __KERNEL__ + +# define task_pt_regs(tsk) ((struct pt_regs *) \ + (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1) +# define user_mode(regs) (((regs)->ps & 0x00000020) != 0) +# define instruction_pointer(regs) ((regs)->pc) +void show_regs(struct pt_regs *); + +# ifndef CONFIG_SMP +# define profile_pc(regs) instruction_pointer(regs) +# endif +#endif /* __KERNEL__ */ + +#else /* __ASSEMBLY__ */ + +#ifdef __KERNEL__ +# include <asm/asm-offsets.h> +#define PT_REGS_OFFSET (KERNEL_STACK_SIZE - PT_USER_SIZE) +#endif + +#endif /* !__ASSEMBLY__ */ +#endif /* _XTENSA_PTRACE_H */ diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h new file mode 100644 index 0000000..0a82a22 --- /dev/null +++ b/arch/xtensa/include/asm/regs.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006 Tensilica, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_REGS_H +#define _XTENSA_REGS_H + +/* Special registers */ + +#define IBREAKA 128 +#define DBREAKA 144 +#define DBREAKC 160 + +/* Special names for read-only and write-only interrupt registers */ + +#define INTREAD 226 +#define INTSET 226 +#define INTCLEAR 227 + +/* EXCCAUSE register fields */ + +#define EXCCAUSE_EXCCAUSE_SHIFT 0 +#define EXCCAUSE_EXCCAUSE_MASK 0x3F + +#define EXCCAUSE_ILLEGAL_INSTRUCTION 0 +#define EXCCAUSE_SYSTEM_CALL 1 +#define EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 +#define EXCCAUSE_LOAD_STORE_ERROR 3 +#define EXCCAUSE_LEVEL1_INTERRUPT 4 +#define EXCCAUSE_ALLOCA 5 +#define EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 +#define EXCCAUSE_SPECULATION 7 +#define EXCCAUSE_PRIVILEGED 8 +#define EXCCAUSE_UNALIGNED 9 +#define EXCCAUSE_INSTR_DATA_ERROR 12 +#define EXCCAUSE_LOAD_STORE_DATA_ERROR 13 +#define EXCCAUSE_INSTR_ADDR_ERROR 14 +#define EXCCAUSE_LOAD_STORE_ADDR_ERROR 15 +#define EXCCAUSE_ITLB_MISS 16 +#define EXCCAUSE_ITLB_MULTIHIT 17 +#define EXCCAUSE_ITLB_PRIVILEGE 18 +#define EXCCAUSE_ITLB_SIZE_RESTRICTION 19 +#define EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 +#define EXCCAUSE_DTLB_MISS 24 +#define EXCCAUSE_DTLB_MULTIHIT 25 +#define EXCCAUSE_DTLB_PRIVILEGE 26 +#define EXCCAUSE_DTLB_SIZE_RESTRICTION 27 +#define EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 +#define EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 +#define EXCCAUSE_COPROCESSOR0_DISABLED 32 +#define EXCCAUSE_COPROCESSOR1_DISABLED 33 +#define EXCCAUSE_COPROCESSOR2_DISABLED 34 +#define EXCCAUSE_COPROCESSOR3_DISABLED 35 +#define EXCCAUSE_COPROCESSOR4_DISABLED 36 +#define EXCCAUSE_COPROCESSOR5_DISABLED 37 +#define EXCCAUSE_COPROCESSOR6_DISABLED 38 +#define EXCCAUSE_COPROCESSOR7_DISABLED 39 +#define EXCCAUSE_LAST 63 + +/* PS register fields */ + +#define PS_WOE_BIT 18 +#define PS_CALLINC_SHIFT 16 +#define PS_CALLINC_MASK 0x00030000 +#define PS_OWB_SHIFT 8 +#define PS_OWB_MASK 0x00000F00 +#define PS_RING_SHIFT 6 +#define PS_RING_MASK 0x000000C0 +#define PS_UM_BIT 5 +#define PS_EXCM_BIT 4 +#define PS_INTLEVEL_SHIFT 0 +#define PS_INTLEVEL_MASK 0x0000000F + +/* DBREAKCn register fields */ + +#define DBREAKC_MASK_BIT 0 +#define DBREAKC_MASK_MASK 0x0000003F +#define DBREAKC_LOAD_BIT 30 +#define DBREAKC_LOAD_MASK 0x40000000 +#define DBREAKC_STOR_BIT 31 +#define DBREAKC_STOR_MASK 0x80000000 + +/* DEBUGCAUSE register fields */ + +#define DEBUGCAUSE_DEBUGINT_BIT 5 /* External debug interrupt */ +#define DEBUGCAUSE_BREAKN_BIT 4 /* BREAK.N instruction */ +#define DEBUGCAUSE_BREAK_BIT 3 /* BREAK instruction */ +#define DEBUGCAUSE_DBREAK_BIT 2 /* DBREAK match */ +#define DEBUGCAUSE_IBREAK_BIT 1 /* IBREAK match */ +#define DEBUGCAUSE_ICOUNT_BIT 0 /* ICOUNT would incr. to zero */ + +#endif /* _XTENSA_SPECREG_H */ + diff --git a/arch/xtensa/include/asm/relocate.h b/arch/xtensa/include/asm/relocate.h new file mode 100644 index 0000000..9c4ce23 --- /dev/null +++ b/arch/xtensa/include/asm/relocate.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ASM_XTENSA_RELOCATE_H +#define _ASM_XTENSA_RELOCATE_H + +#include <common.h> + +int clear_bss(void); + +#endif /* _ASM_XTENSA_RELOCATE_H */ diff --git a/arch/xtensa/include/asm/sections.h b/arch/xtensa/include/asm/sections.h new file mode 100644 index 0000000..2309b14 --- /dev/null +++ b/arch/xtensa/include/asm/sections.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_XTENSA_SECTIONS_H +#define __ASM_XTENSA_SECTIONS_H + +#include <asm-generic/sections.h> + +#endif diff --git a/arch/xtensa/include/asm/string.h b/arch/xtensa/include/asm/string.h new file mode 100644 index 0000000..65a3601 --- /dev/null +++ b/arch/xtensa/include/asm/string.h @@ -0,0 +1,10 @@ +#ifndef _XTENSA_STRING_H +#define _XTENSA_STRING_H + +/* + * Use the generic string functions in U-Boot's lib_generic. + * In the boot loader we care about compactness more than performance. + * Prototypes will be taken from <linux/string.h> + */ + +#endif /* _XTENSA_STRING_H */ diff --git a/arch/xtensa/include/asm/system.h b/arch/xtensa/include/asm/system.h new file mode 100644 index 0000000..5b71008 --- /dev/null +++ b/arch/xtensa/include/asm/system.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_SYSTEM_H +#define _XTENSA_SYSTEM_H + +#include <asm/arch/core.h> + +#if XCHAL_HAVE_INTERRUPTS +#define local_irq_save(flags) \ + __asm__ __volatile__ ("rsil %0, %1" \ + : "=a"(flags) \ + : "I"(XCHAL_EXCM_LEVEL) \ + : "memory") +#define local_irq_restore(flags) \ + __asm__ __volatile__ ("wsr %0, ps\n\t" \ + "rsync" \ + :: "a"(flags) : "memory") +#else +#define local_irq_save(flags) ((void)(flags)) +#define local_irq_restore(flags) ((void)(flags)) +#endif + +#endif diff --git a/arch/xtensa/include/asm/types.h b/arch/xtensa/include/asm/types.h new file mode 100644 index 0000000..f7eda9d --- /dev/null +++ b/arch/xtensa/include/asm/types.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 1997 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_TYPES_H +#define _XTENSA_TYPES_H + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide */ + +typedef u32 dma_addr_t; + +typedef unsigned long phys_addr_t; +typedef unsigned long phys_size_t; + + +#endif /* __KERNEL__ */ + +#endif /* _XTENSA_TYPES_H */ diff --git a/arch/xtensa/include/asm/u-boot.h b/arch/xtensa/include/asm/u-boot.h new file mode 100644 index 0000000..cfdc036 --- /dev/null +++ b/arch/xtensa/include/asm/u-boot.h @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2007, Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef _XTENSA_U_BOOT_H +#define _XTENSA_U_BOOT_H + +#ifdef CONFIG_SYS_GENERIC_BOARD +/* Use the generic board which requires a unified bd_info */ +#include <asm-generic/u-boot.h> +#else + +#ifndef __ASSEMBLY__ +typedef struct bd_info { + int bi_baudrate; /* serial console baudrate */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned long bi_boot_params; /* where this board expects params */ + unsigned long bi_memstart; /* start of DRAM memory VA */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* offset to skip UBoot image */ +} bd_t; +#endif /* __ ASSEMBLY__ */ + +#endif /* CONFIG_SYS_GENERIC_BOARD */ + +/* For image.h:image_check_target_arch() */ +#define IH_ARCH_DEFAULT IH_ARCH_XTENSA + +#endif /* _XTENSA_U_BOOT_H */ diff --git a/arch/xtensa/include/asm/unaligned.h b/arch/xtensa/include/asm/unaligned.h new file mode 100644 index 0000000..536f364 --- /dev/null +++ b/arch/xtensa/include/asm/unaligned.h @@ -0,0 +1,6 @@ +#ifndef _ASM_XTENSA_UNALIGNED_H +#define _ASM_XTENSA_UNALIGNED_H + +#include <asm-generic/unaligned.h> + +#endif /* _ASM_XTENSA_UNALIGNED_H */ diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile new file mode 100644 index 0000000..7c7d8d5 --- /dev/null +++ b/arch/xtensa/lib/Makefile @@ -0,0 +1,10 @@ +# +# (C) Copyright 2007 - 2013 Tensilica Inc. +# (C) Copyright 2014 - 2016 Cadence Design Systems Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_CMD_BOOTM) += bootm.o + +obj-y += cache.o misc.o relocate.o time.o diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c new file mode 100644 index 0000000..1604bb9 --- /dev/null +++ b/arch/xtensa/lib/bootm.c @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <u-boot/zlib.h> +#include <asm/byteorder.h> +#include <asm/addrspace.h> +#include <asm/bootparam.h> +#include <asm/cache.h> +#include <image.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Setup boot-parameters. + */ + +static struct bp_tag *setup_first_tag(struct bp_tag *params) +{ + params->id = BP_TAG_FIRST; + params->size = sizeof(long); + *(unsigned long *)¶ms->data = BP_VERSION; + + return bp_tag_next(params); +} + +static struct bp_tag *setup_last_tag(struct bp_tag *params) +{ + params->id = BP_TAG_LAST; + params->size = 0; + + return bp_tag_next(params); +} + +static struct bp_tag *setup_memory_tag(struct bp_tag *params) +{ + struct bd_info *bd = gd->bd; + struct meminfo *mem; + + params->id = BP_TAG_MEMORY; + params->size = sizeof(struct meminfo); + mem = (struct meminfo *)params->data; + mem->type = MEMORY_TYPE_CONVENTIONAL; + mem->start = bd->bi_memstart; + mem->end = bd->bi_memstart + bd->bi_memsize; + + printf(" MEMORY: tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n", + BP_TAG_MEMORY, mem->type, mem->start, mem->end); + + return bp_tag_next(params); +} + +static struct bp_tag *setup_commandline_tag(struct bp_tag *params, + char *cmdline) +{ + int len; + + if (!cmdline) + return params; + + len = strlen(cmdline); + + params->id = BP_TAG_COMMAND_LINE; + params->size = (len + 3) & -4; + strcpy((char *)params->data, cmdline); + + printf(" COMMAND_LINE: tag:0x%04x, size:%u, data:'%s'\n", + BP_TAG_COMMAND_LINE, params->size, cmdline); + + return bp_tag_next(params); +} + +static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params, + unsigned long rd_start, + unsigned long rd_end) +{ + struct meminfo *mem; + + if (rd_start == rd_end) + return params; + + /* Add a single banked memory */ + + params->id = BP_TAG_INITRD; + params->size = sizeof(struct meminfo); + + mem = (struct meminfo *)params->data; + mem->type = MEMORY_TYPE_CONVENTIONAL; + mem->start = PHYSADDR(rd_start); + mem->end = PHYSADDR(rd_end); + + printf(" INITRD: tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n", + BP_TAG_INITRD, mem->type, mem->start, mem->end); + + return bp_tag_next(params); +} + +static struct bp_tag *setup_serial_tag(struct bp_tag *params) +{ + params->id = BP_TAG_SERIAL_BAUDRATE; + params->size = sizeof(unsigned long); + params->data[0] = gd->baudrate; + + printf(" SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n", + BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]); + + return bp_tag_next(params); +} + +#ifdef CONFIG_OF_LIBFDT + +static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start) +{ + params->id = BP_TAG_FDT; + params->size = sizeof(unsigned long); + params->data[0] = (unsigned long)fdt_start; + + printf(" FDT: tag:0x%04x, size:%u, start:0x%lx\n", + BP_TAG_FDT, params->size, params->data[0]); + + return bp_tag_next(params); +} + +#endif + +/* + * Boot Linux. + */ + +int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +{ + struct bp_tag *params, *params_start; + ulong initrd_start, initrd_end; + char *commandline = getenv("bootargs"); + + if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO))) + return 0; + + show_boot_progress(15); + + if (images->rd_start) { + initrd_start = images->rd_start; + initrd_end = images->rd_end; + } else { + initrd_start = 0; + initrd_end = 0; + } + + params_start = (struct bp_tag *)gd->bd->bi_boot_params; + params = params_start; + params = setup_first_tag(params); + params = setup_memory_tag(params); + params = setup_commandline_tag(params, commandline); + params = setup_serial_tag(params); + + if (initrd_start) + params = setup_ramdisk_tag(params, initrd_start, initrd_end); + +#ifdef CONFIG_OF_LIBFDT + if (images->ft_addr) + params = setup_fdt_tag(params, images->ft_addr); +#endif + + printf("\n"); + + params = setup_last_tag(params); + + show_boot_progress(15); + + printf("Transferring Control to Linux @0x%08lx ...\n\n", + (ulong)images->ep); + + flush_dcache_range((unsigned long)params_start, (unsigned long)params); + + if (flag & BOOTM_STATE_OS_FAKE_GO) + return 0; + + /* + * _start() in vmlinux expects boot params in register a2. + * NOTE: + * Disable/delete your u-boot breakpoints before stepping into linux. + */ + asm volatile ("mov a2, %0\n\t" + "jx %1\n\t" + : : "a" (params_start), "a" (images->ep) + : "a2"); + + /* Does not return */ + + return 1; +} + diff --git a/arch/xtensa/lib/cache.c b/arch/xtensa/lib/cache.c new file mode 100644 index 0000000..2680839 --- /dev/null +++ b/arch/xtensa/lib/cache.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 - 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/cache.h> + +/* + * We currently run always with caches enabled when running from memory. + * Xtensa version D or later will support changing cache behavior, so + * we could implement it if necessary. + */ + +int dcache_status(void) +{ + return 1; +} + +void dcache_enable(void) +{ +} + +void dcache_disable(void) +{ +} + +void flush_cache(ulong start_addr, ulong size) +{ + __flush_invalidate_dcache_range(start_addr, size); + __invalidate_icache_range(start_addr, size); +} + +void flush_dcache_all(void) +{ + __flush_dcache_all(); + __invalidate_icache_all(); +} + +void flush_dcache_range(ulong start_addr, ulong end_addr) +{ + __flush_invalidate_dcache_range(start_addr, end_addr - start_addr); +} + +void invalidate_dcache_range(ulong start, ulong stop) +{ + __invalidate_dcache_range(start, stop - start); +} + +void invalidate_dcache_all(void) +{ + __invalidate_dcache_all(); +} + +void invalidate_icache_all(void) +{ + __invalidate_icache_all(); +} diff --git a/arch/xtensa/lib/misc.S b/arch/xtensa/lib/misc.S new file mode 100644 index 0000000..449a6db --- /dev/null +++ b/arch/xtensa/lib/misc.S @@ -0,0 +1,179 @@ +/* + * Miscellaneous assembly functions. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * Chris Zankel <chris@zankel.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + +#include <linux/linkage.h> +#include <asm/asmmacro.h> +#include <asm/cacheasm.h> + +/* + * void __invalidate_icache_page(ulong start) + */ + +ENTRY(__invalidate_icache_page) + + abi_entry + + ___invalidate_icache_page a2 a3 + isync + + abi_ret + +ENDPROC(__invalidate_icache_page) + +/* + * void __invalidate_dcache_page(ulong start) + */ + +ENTRY(__invalidate_dcache_page) + + abi_entry + + ___invalidate_dcache_page a2 a3 + dsync + + abi_ret + +ENDPROC(__invalidate_dcache_page) + +/* + * void __flush_invalidate_dcache_page(ulong start) + */ + +ENTRY(__flush_invalidate_dcache_page) + + abi_entry + + ___flush_invalidate_dcache_page a2 a3 + + dsync + abi_ret + +ENDPROC(__flush_invalidate_dcache_page) + +/* + * void __flush_dcache_page(ulong start) + */ + +ENTRY(__flush_dcache_page) + + abi_entry + + ___flush_dcache_page a2 a3 + + dsync + abi_ret + +ENDPROC(__flush_dcache_page) + +/* + * void __invalidate_icache_range(ulong start, ulong size) + */ + +ENTRY(__invalidate_icache_range) + + abi_entry + + ___invalidate_icache_range a2 a3 a4 + isync + + abi_ret + +ENDPROC(__invalidate_icache_range) + +/* + * void __flush_invalidate_dcache_range(ulong start, ulong size) + */ + +ENTRY(__flush_invalidate_dcache_range) + + abi_entry + + ___flush_invalidate_dcache_range a2 a3 a4 + dsync + + abi_ret + +ENDPROC(__flush_invalidate_dcache_range) + +/* + * void _flush_dcache_range(ulong start, ulong size) + */ + +ENTRY(__flush_dcache_range) + + abi_entry + + ___flush_dcache_range a2 a3 a4 + dsync + + abi_ret + +ENDPROC(__flush_dcache_range) + +/* + * void _invalidate_dcache_range(ulong start, ulong size) + */ + +ENTRY(__invalidate_dcache_range) + + abi_entry + + ___invalidate_dcache_range a2 a3 a4 + + abi_ret + +ENDPROC(__invalidate_dcache_range) + +/* + * void _invalidate_icache_all(void) + */ + +ENTRY(__invalidate_icache_all) + + abi_entry + + ___invalidate_icache_all a2 a3 + isync + + abi_ret + +ENDPROC(__invalidate_icache_all) + +/* + * void _flush_invalidate_dcache_all(void) + */ + +ENTRY(__flush_invalidate_dcache_all) + + abi_entry + + ___flush_invalidate_dcache_all a2 a3 + dsync + + abi_ret + +ENDPROC(__flush_invalidate_dcache_all) + +/* + * void _invalidate_dcache_all(void) + */ + +ENTRY(__invalidate_dcache_all) + + abi_entry + + ___invalidate_dcache_all a2 a3 + dsync + + abi_ret + +ENDPROC(__invalidate_dcache_all) diff --git a/arch/xtensa/lib/relocate.c b/arch/xtensa/lib/relocate.c new file mode 100644 index 0000000..3f747ec --- /dev/null +++ b/arch/xtensa/lib/relocate.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2016 Cadence Design Systems Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/relocate.h> +#include <asm/sections.h> +#include <asm/string.h> + +int clear_bss(void) +{ + size_t len = (size_t)&__bss_end - (size_t)&__bss_start; + + memset((void *)&__bss_start, 0x00, len); + return 0; +} + diff --git a/arch/xtensa/lib/time.c b/arch/xtensa/lib/time.c new file mode 100644 index 0000000..1332072 --- /dev/null +++ b/arch/xtensa/lib/time.c @@ -0,0 +1,121 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/global_data.h> +#include <linux/stringify.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if XCHAL_HAVE_CCOUNT +static ulong get_ccount(void) +{ + ulong ccount; + asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (ccount)); + return ccount; +} +#else +static ulong fake_ccount; +#define get_ccount() fake_ccount +#endif + +static void delay_cycles(unsigned cycles) +{ +#if XCHAL_HAVE_CCOUNT + unsigned expiry = get_ccount() + cycles; + while ((signed)(expiry - get_ccount()) > 0) + ; +#else +#warning "Without Xtensa timer option, timing will not be accurate." + + /* + * Approximate the cycle count by a loop iteration count. + * This is highly dependent on config and optimization. + */ + + volatile unsigned i; + for (i = cycles >> 4U; i > 0; --i) + ; + fake_ccount += cycles; +#endif +} + +/* + * Delay (busy-wait) for a number of microseconds. + */ + +void __udelay(unsigned long usec) +{ + ulong lo, hi, i; + ulong mhz = CONFIG_SYS_CLK_FREQ / 1000000; + + /* Scale to support full 32-bit usec range */ + + lo = usec & ((1<<22)-1); + hi = usec >> 22UL; + for (i = 0; i < hi; ++i) + delay_cycles(mhz << 22); + delay_cycles(mhz * lo); +} + + +/* + * Return the elapsed time (ticks) since 'base'. + */ + +ulong get_timer(ulong base) +{ + /* Don't tie up a timer; use cycle counter if available (or fake it) */ + +#if XCHAL_HAVE_CCOUNT + register ulong ccount; + __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount)); + return ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base; +#else + /* + * Add at least the overhead of this call (in cycles). + * Avoids hanging in case caller doesn't use udelay(). + * Note that functions that don't call udelay() (such as + * the "sleep" command) will not get a significant delay + * because there is no time reference. + */ + + fake_ccount += 20; + return fake_ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base; +#endif +} + + +/* + * This function is derived from ARM/PowerPC code (read timebase as long long). + * On Xtensa it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from ARM/PowerPC code (timebase clock frequency). + * On Xtensa it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = CONFIG_SYS_HZ; + return tbclk; +} + +#if XCHAL_HAVE_CCOUNT +unsigned long timer_get_us(void) +{ + unsigned long ccount; + + __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount)); + return ccount / (CONFIG_SYS_CLK_FREQ / 1000000); +} +#endif |