Message ID | 1467992526-13417-3-git-send-email-jcmvbkbc@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | Tom Rini |
Headers | show |
Hi Max, On 8 July 2016 at 09:42, Max Filippov <jcmvbkbc@gmail.com> wrote: > From: Chris Zankel <chris@zankel.net> > > The Xtensa processor architecture is a configurable, extensible, > and synthesizable 32-bit RISC processor core provided by Tensilica, inc. > > This is the second part of the basic architecture port, adding the > 'arch/xtensa' directory and a readme file. > > Signed-off-by: Chris Zankel <chris@zankel.net> > Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> > --- > arch/Kconfig | 8 + > arch/xtensa/Kconfig | 26 ++ > arch/xtensa/Makefile | 8 + > arch/xtensa/config.mk | 12 + > arch/xtensa/cpu/Makefile | 9 + > arch/xtensa/cpu/cpu.c | 92 +++++ > arch/xtensa/cpu/exceptions.c | 64 +++ > arch/xtensa/cpu/start.S | 737 ++++++++++++++++++++++++++++++++++ > arch/xtensa/cpu/u-boot.lds | 116 ++++++ > arch/xtensa/dts/Makefile | 13 + > arch/xtensa/dts/include/dt-bindings | 1 + > arch/xtensa/include/asm/addrspace.h | 31 ++ > arch/xtensa/include/asm/asmmacro.h | 152 +++++++ > arch/xtensa/include/asm/atomic.h | 55 +++ > arch/xtensa/include/asm/bitops.h | 36 ++ > arch/xtensa/include/asm/bootparam.h | 54 +++ > arch/xtensa/include/asm/byteorder.h | 81 ++++ > arch/xtensa/include/asm/cache.h | 20 + > arch/xtensa/include/asm/cacheasm.h | 211 ++++++++++ > arch/xtensa/include/asm/config.h | 24 ++ > arch/xtensa/include/asm/errno.h | 1 + > arch/xtensa/include/asm/global_data.h | 20 + > arch/xtensa/include/asm/io.h | 149 +++++++ > arch/xtensa/include/asm/ldscript.h | 222 ++++++++++ > arch/xtensa/include/asm/linkage.h | 4 + > arch/xtensa/include/asm/misc.h | 20 + > arch/xtensa/include/asm/posix_types.h | 74 ++++ > arch/xtensa/include/asm/processor.h | 11 + > arch/xtensa/include/asm/ptrace.h | 133 ++++++ > arch/xtensa/include/asm/regs.h | 95 +++++ > arch/xtensa/include/asm/sections.h | 12 + > arch/xtensa/include/asm/string.h | 10 + > arch/xtensa/include/asm/system.h | 27 ++ > arch/xtensa/include/asm/types.h | 60 +++ > arch/xtensa/include/asm/u-boot.h | 41 ++ > arch/xtensa/include/asm/unaligned.h | 6 + > arch/xtensa/include/asm/xtensa.h | 29 ++ > arch/xtensa/lib/Makefile | 10 + > arch/xtensa/lib/bootm.c | 197 +++++++++ > arch/xtensa/lib/misc.S | 179 +++++++++ > arch/xtensa/lib/time.c | 121 ++++++ > 41 files changed, 3171 insertions(+) > create mode 100644 arch/xtensa/Kconfig > create mode 100644 arch/xtensa/Makefile > create mode 100644 arch/xtensa/config.mk > create mode 100644 arch/xtensa/cpu/Makefile > create mode 100644 arch/xtensa/cpu/cpu.c > create mode 100644 arch/xtensa/cpu/exceptions.c > create mode 100644 arch/xtensa/cpu/start.S > create mode 100644 arch/xtensa/cpu/u-boot.lds > create mode 100644 arch/xtensa/dts/Makefile > create mode 120000 arch/xtensa/dts/include/dt-bindings > create mode 100644 arch/xtensa/include/asm/addrspace.h > create mode 100644 arch/xtensa/include/asm/asmmacro.h > create mode 100644 arch/xtensa/include/asm/atomic.h > create mode 100644 arch/xtensa/include/asm/bitops.h > create mode 100644 arch/xtensa/include/asm/bootparam.h > create mode 100644 arch/xtensa/include/asm/byteorder.h > create mode 100644 arch/xtensa/include/asm/cache.h > create mode 100644 arch/xtensa/include/asm/cacheasm.h > create mode 100644 arch/xtensa/include/asm/config.h > create mode 100644 arch/xtensa/include/asm/errno.h > create mode 100644 arch/xtensa/include/asm/global_data.h > create mode 100644 arch/xtensa/include/asm/io.h > create mode 100644 arch/xtensa/include/asm/ldscript.h > create mode 100644 arch/xtensa/include/asm/linkage.h > create mode 100644 arch/xtensa/include/asm/misc.h > create mode 100644 arch/xtensa/include/asm/posix_types.h > create mode 100644 arch/xtensa/include/asm/processor.h > create mode 100644 arch/xtensa/include/asm/ptrace.h > create mode 100644 arch/xtensa/include/asm/regs.h > create mode 100644 arch/xtensa/include/asm/sections.h > create mode 100644 arch/xtensa/include/asm/string.h > create mode 100644 arch/xtensa/include/asm/system.h > create mode 100644 arch/xtensa/include/asm/types.h > create mode 100644 arch/xtensa/include/asm/u-boot.h > create mode 100644 arch/xtensa/include/asm/unaligned.h > create mode 100644 arch/xtensa/include/asm/xtensa.h > create mode 100644 arch/xtensa/lib/Makefile > create mode 100644 arch/xtensa/lib/bootm.c > create mode 100644 arch/xtensa/lib/misc.S > create mode 100644 arch/xtensa/lib/time.c Reviewed-by: Simon Glass <sjg@chromium.org> Some comments below. > > diff --git a/arch/Kconfig b/arch/Kconfig > index 566f044..a36ac2f 100644 > --- a/arch/Kconfig > +++ b/arch/Kconfig > @@ -83,6 +83,13 @@ config X86 > select DM_SPI > select DM_SPI_FLASH > > +config XTENSA > + bool "Xtensa architecture" > + select CREATE_ARCH_SYMLINK > + select HAVE_GENERIC_BOARD This doesn't exist anymore as the migration is complete. > + select SUPPORT_OF_CONTROL > + select SYS_GENERIC_BOARD Same here. > + > endchoice > > config SYS_ARCH > @@ -156,3 +163,4 @@ source "arch/sandbox/Kconfig" > source "arch/sh/Kconfig" > source "arch/sparc/Kconfig" > source "arch/x86/Kconfig" > +source "arch/xtensa/Kconfig" > diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig > new file mode 100644 > index 0000000..e4e3625 > --- /dev/null > +++ b/arch/xtensa/Kconfig > @@ -0,0 +1,26 @@ > +menu "Xtensa architecture" > + depends on XTENSA > + > +config SYS_ARCH > + string > + default "xtensa" > + > +config SYS_CPU > + string "Xtensa Core Variant" > + > +choice > + prompt "Target select" > + > + > +endchoice > + > + > +config HAVE_SYS_ASCDISP > + bool > + > +config SYS_ASCDISP > + bool "System LCD Display" > + default y > + depends on HAVE_SYS_ASCDISP Needs a help message. Should SYS_ASCDISP go in drivers/video? > + > +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..fb7f810 > --- /dev/null > +++ b/arch/xtensa/cpu/cpu.c > @@ -0,0 +1,92 @@ > +/* > + * (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; > + > +#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 > + > +/* > + * Implement the "reset" command. > + * We need support from the board, though. > + */ > + > +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + board_reset(); > + > + /* Shouldn't come back! */ > + printf("****** RESET FAILED ******\n"); All of this can be replaced by a call to sysreset_walk_halt() I think, if you have a suitable UCLASS_RESET driver. > + return 0; > +} > + > +/* > + * We currently run always with caches enabled when running for mmemory. Do you mean '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_range(ulong start_addr, ulong end_addr) > +{ > + __flush_invalidate_dcache_range(start_addr, end_addr - start_addr); > +} > + > +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..412ca5f > --- /dev/null > +++ b/arch/xtensa/cpu/exceptions.c > @@ -0,0 +1,64 @@ > +/* > + * (C) Copyright 2008 - 2013 Tensilica Inc. > + * (C) Copyright 2014 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/xtensa.h> > +#include <asm/string.h> > +#include <asm/regs.h> > + > +typedef void (*handler_t)(struct pt_regs *); > + > +void xtensa_mem_exc_dummy(struct pt_regs *); > + > +void unhandled_exception(struct pt_regs *regs) > +{ > + display_printf("!! EXCCAUSE = %2ld", regs->exccause); > + printf("Unhandled Exception: EXCCAUSE = %ld (pc %lx)\n", > + regs->exccause, regs->pc); > + udelay(10000000); /* 10s to read display message */ Probably not needed? Up to you though. > + panic("*** PANIC\n"); > +} > + > +handler_t exc_table[EXCCAUSE_LAST] = { > + [0 ... EXCCAUSE_LAST-1] = unhandled_exception, > + [EXCCAUSE_LOAD_STORE_ERROR] = xtensa_mem_exc_dummy, > + [EXCCAUSE_UNALIGNED] = xtensa_mem_exc_dummy, > + [EXCCAUSE_LOAD_STORE_DATA_ERROR] = xtensa_mem_exc_dummy, > + [EXCCAUSE_LOAD_STORE_ADDR_ERROR] = xtensa_mem_exc_dummy, > + [EXCCAUSE_FETCH_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, > + [EXCCAUSE_DTLB_MISS] = xtensa_mem_exc_dummy, > + [EXCCAUSE_DTLB_MULTIHIT] = xtensa_mem_exc_dummy, > + [EXCCAUSE_DTLB_PRIVILEGE] = xtensa_mem_exc_dummy, > + [EXCCAUSE_DTLB_SIZE_RESTRICTION] = xtensa_mem_exc_dummy, > + [EXCCAUSE_LOAD_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, > + [EXCCAUSE_STORE_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, > +}; > + > +#ifdef CONFIG_USE_IRQ > +#error "Use of interrupts is not supported in Xtensa port" > +#else > +int interrupt_init(void) > +{ > + return 0; > +} > + > +void enable_interrupts(void) > +{ > +} > + > +int disable_interrupts(void) > +{ > + return 0; > +} > +#endif > diff --git a/arch/xtensa/cpu/start.S b/arch/xtensa/cpu/start.S > new file mode 100644 > index 0000000..ac32efb > --- /dev/null > +++ b/arch/xtensa/cpu/start.S > @@ -0,0 +1,737 @@ > +/* > + * (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 > + > + /* Clear BSS */ > + > + movi a2, _bss_start > + movi a3, _bss_end Can you please use board_init_f_init_reserve(), etc.? You can copy how ARM does things perhaps. This should not be in assembly. > + > + __loopt a2, a3, a4, 2 > + s32i a0, a2, 0 > + __endla a2, a3, 4 > + > + /* 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 As above. This is using the old approach. > + > +#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. */ nit: drop periods before */ > + > + > + .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 > + s32i a2, a1, PT_SAR > + s32i a3, a1, PT_PC > + > +#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 > + > + > +/* > + * Dummy memory exception handler to avoid crash/hang on load/store of > + * an invalid address (such as might be requested by user "md" command). > + * U-Boot currently does not provide a hook to prevent accessing invalid > + * addresses nor to inform the user, so we have to try to live with it. > + * Simply skip the offending instruction (don't care what load returns). > + * This is ugly (and possibly dangerous in Xtensa FLIX configs), but if we > + * get here we're in trouble anyway, so might as well *try* to recover. > + * void xtensa_mem_exc_dummy(struct pt_regs*); > + */ > + /* Table of instruction sizes based on op0 field. */ > + .section .rodata, "a" > + .type op0_format_lengths, @object > + .align 4 > +op0_format_lengths: > + .byte XCHAL_OP0_FORMAT_LENGTHS > + > + .text > + .global xtensa_mem_exc_dummy > + .type xtensa_mem_exc_dummy, @function > + .align 4 > +xtensa_mem_exc_dummy: > + > + abi_entry > + > + /* Decode the size of the instruction that caused the exception. */ > + l32i a3, a2, PT_PC /* a3 = PC of exception */ > + l8ui a4, a3, 0 /* a4 = first byte of insn */ > + movi a5, op0_format_lengths /* a5 = table of instruction sizes */ > + #if XCHAL_HAVE_BE > + extui a4, a4, 4, 4 /* a4 = op0 = big end nibble */ > + #else > + extui a4, a4, 0, 4 /* a4 = op0 = little end nibble */ > + #endif > + add a5, a5, a4 /* index table with op0 */ > + l8ui a4, a5, 0 /* a4 = instruction size */ > + > + /* Increment the PC past the instruction that caused the exception. */ > + add a3, a3, a4 /* PC += size of insn */ > + #if XCHAL_HAVE_LOOPS > + l32i a4, a2, PT_LEND /* if (PC == LEND */ > + bne a3, a4, 1f > + l32i a4, a2, PT_LCOUNT /* && LCOUNT != 0) */ > + beqz a4, 1f /* { */ > + addi a4, a4, -1 /* --LCOUNT */ > + l32i a3, a2, PT_LBEG /* PC = LBEG */ > + s32i a4, a2, PT_LCOUNT /* } */ > + #endif > +1: s32i a3, a2, PT_PC /* update PC */ > + > + abi_ret > + > +#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) } Are you including the list regions, etc.? u_boot_list is what it is in most .lds files. > +} > 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..dd79485 > --- /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..485bc4b > --- /dev/null > +++ b/arch/xtensa/include/asm/byteorder.h > @@ -0,0 +1,81 @@ > +/* > + * 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), /* * Given > + * 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..3999122 > --- /dev/null > +++ b/arch/xtensa/include/asm/cache.h > @@ -0,0 +1,20 @@ > +/* > + * 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_invalidate_dcache_range(unsigned long addr, unsigned long size); > +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..0a87d9f > --- /dev/null > +++ b/arch/xtensa/include/asm/io.h > @@ -0,0 +1,149 @@ > +/* > + * 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); > +} > + > +static inline void iounmap(void *addr) > +{ > +} > + > +/* > + * 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) > + > +/* We are using uncached addresses, ie: 0x80000000 ... */ > +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) > +{ > +} > + > +/* > + * 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..bb8ca61 > --- /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..6f623ef > --- /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/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..e30f519 > --- /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/include/asm/xtensa.h b/arch/xtensa/include/asm/xtensa.h > new file mode 100644 > index 0000000..a68024d > --- /dev/null > +++ b/arch/xtensa/include/asm/xtensa.h > @@ -0,0 +1,29 @@ > +/* > + * Copyright (C) 2007 Tensilica, Inc. > + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. > + * > + * A place for global definitions specific to Xtensa-based ports. > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef _XTENSA_H_ > +#define _XTENSA_H_ > + > +#include <stdarg.h> > +#include <config.h> > +#include <asm/u-boot.h> > + > +#ifdef CONFIG_SYS_ASCDISP > +/* > + * Print a formatted string to the board's ASCII character display. > + * String may have embedded newlines. Starts at top left and wraps long lines. > + */ > +void display_printf(const char *fmt, ...); > +#else > +static inline void display_printf(const char *fmt, ...) > +{ > +} > +#endif > + > +#endif /* _XTENSA_H_ */ > diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile > new file mode 100644 > index 0000000..72e7bc8 > --- /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 += misc.o time.o > diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c > new file mode 100644 > index 0000000..8c89d2c > --- /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; Do you not use device tree with Linux? It looks like you need to support both that and tags? > + 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/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/time.c b/arch/xtensa/lib/time.c > new file mode 100644 > index 0000000..6d0ff03 > --- /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 > -- > 2.1.4 > Regards, Simon
Hi Simon, On Tue, Jul 12, 2016 at 03:56:05PM -0600, Simon Glass wrote: [...] > Reviewed-by: Simon Glass <sjg@chromium.org> > > Some comments below. > > > > > diff --git a/arch/Kconfig b/arch/Kconfig > > index 566f044..a36ac2f 100644 > > --- a/arch/Kconfig > > +++ b/arch/Kconfig > > @@ -83,6 +83,13 @@ config X86 > > select DM_SPI > > select DM_SPI_FLASH > > > > +config XTENSA > > + bool "Xtensa architecture" > > + select CREATE_ARCH_SYMLINK > > + select HAVE_GENERIC_BOARD > > This doesn't exist anymore as the migration is complete. > > > + select SUPPORT_OF_CONTROL > > + select SYS_GENERIC_BOARD > > Same here. Ok, will remove both. > > diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig > > new file mode 100644 > > index 0000000..e4e3625 > > --- /dev/null > > +++ b/arch/xtensa/Kconfig > > @@ -0,0 +1,26 @@ > > +menu "Xtensa architecture" > > + depends on XTENSA > > + > > +config SYS_ARCH > > + string > > + default "xtensa" > > + > > +config SYS_CPU > > + string "Xtensa Core Variant" > > + > > +choice > > + prompt "Target select" > > + > > + > > +endchoice > > + > > + > > +config HAVE_SYS_ASCDISP > > + bool > > + > > +config SYS_ASCDISP > > + bool "System LCD Display" > > + default y > > + depends on HAVE_SYS_ASCDISP > > Needs a help message. Should SYS_ASCDISP go in drivers/video? Ok, will move it there and write help message. [...] > > diff --git a/arch/xtensa/cpu/cpu.c b/arch/xtensa/cpu/cpu.c > > new file mode 100644 > > index 0000000..fb7f810 > > --- /dev/null > > +++ b/arch/xtensa/cpu/cpu.c > > @@ -0,0 +1,92 @@ > > +/* > > + * (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; > > + > > +#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 > > + > > +/* > > + * Implement the "reset" command. > > + * We need support from the board, though. > > + */ > > + > > +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > > +{ > > + board_reset(); > > + > > + /* Shouldn't come back! */ > > + printf("****** RESET FAILED ******\n"); > > All of this can be replaced by a call to sysreset_walk_halt() I think, > if you have a suitable UCLASS_RESET driver. Ok, let me look at that. > > + return 0; > > +} > > + > > +/* > > + * We currently run always with caches enabled when running for mmemory. > > Do you mean 'from memory'? Yes, will fix. [...] > > diff --git a/arch/xtensa/cpu/exceptions.c b/arch/xtensa/cpu/exceptions.c > > new file mode 100644 > > index 0000000..412ca5f > > --- /dev/null > > +++ b/arch/xtensa/cpu/exceptions.c > > @@ -0,0 +1,64 @@ > > +/* > > + * (C) Copyright 2008 - 2013 Tensilica Inc. > > + * (C) Copyright 2014 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/xtensa.h> > > +#include <asm/string.h> > > +#include <asm/regs.h> > > + > > +typedef void (*handler_t)(struct pt_regs *); > > + > > +void xtensa_mem_exc_dummy(struct pt_regs *); > > + > > +void unhandled_exception(struct pt_regs *regs) > > +{ > > + display_printf("!! EXCCAUSE = %2ld", regs->exccause); > > + printf("Unhandled Exception: EXCCAUSE = %ld (pc %lx)\n", > > + regs->exccause, regs->pc); > > + udelay(10000000); /* 10s to read display message */ > > Probably not needed? Up to you though. I'd either drop it together with ASCII display, or leave them both. [...] > > diff --git a/arch/xtensa/cpu/start.S b/arch/xtensa/cpu/start.S > > new file mode 100644 > > index 0000000..ac32efb > > --- /dev/null > > +++ b/arch/xtensa/cpu/start.S [...] > > +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 > > + > > + /* Clear BSS */ > > + > > + movi a2, _bss_start > > + movi a3, _bss_end > > Can you please use board_init_f_init_reserve(), etc.? You can copy how > ARM does things perhaps. This should not be in assembly. We use them, one screen below. What exactly should not be in assembly? BSS zeroing? > > + > > + __loopt a2, a3, a4, 2 > > + s32i a0, a2, 0 > > + __endla a2, a3, 4 > > + > > + /* 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 > > As above. This is using the old approach. I see the same sequence in the ARM's _main in arch/arm/lib/crt0.S: mov r0, sp bl board_init_f_alloc_reserve mov sp, r0 /* set up gd here, outside any C code */ mov r9, r0 bl board_init_f_init_reserve mov r0, #0 bl board_init_f What is 'the new approach' and how does it differ from the old? [...] > > + /* Does not return here. */ > > nit: drop periods before */ Ok. [...] > > +fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 > > */ ? Oops, right. [...] > > 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) } > > Are you including the list regions, etc.? u_boot_list is what it is in > most .lds files. Yes, it's in the SECTION_u_boot_list a few lines above. [...] > > diff --git a/arch/xtensa/include/asm/byteorder.h b/arch/xtensa/include/asm/byteorder.h > > new file mode 100644 > > index 0000000..485bc4b > > --- /dev/null > > +++ b/arch/xtensa/include/asm/byteorder.h > > @@ -0,0 +1,81 @@ > > +/* > > + * 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), > > /* > * Given Ok. [...] > > diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c > > new file mode 100644 > > index 0000000..8c89d2c > > --- /dev/null > > +++ b/arch/xtensa/lib/bootm.c [...] > > +/* > > + * 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; > > Do you not use device tree with Linux? It looks like you need to > support both that and tags? We can use device tree with linux, but that's not mandatory. When it's used we pass DTB in one of the tags.
Hi Max, On 14 July 2016 at 16:58, Max Filippov <jcmvbkbc@gmail.com> wrote: > Hi Simon, > > On Tue, Jul 12, 2016 at 03:56:05PM -0600, Simon Glass wrote: > > [...] > >> Reviewed-by: Simon Glass <sjg@chromium.org> >> >> Some comments below. >> > >> > diff --git a/arch/xtensa/cpu/start.S b/arch/xtensa/cpu/start.S >> > new file mode 100644 >> > index 0000000..ac32efb >> > --- /dev/null >> > +++ b/arch/xtensa/cpu/start.S > > [...] > >> > +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 >> > + >> > + /* Clear BSS */ >> > + >> > + movi a2, _bss_start >> > + movi a3, _bss_end >> >> Can you please use board_init_f_init_reserve(), etc.? You can copy how >> ARM does things perhaps. This should not be in assembly. > > We use them, one screen below. > What exactly should not be in assembly? BSS zeroing? Yes. I misunderstood this sorry, but the idea is to have a little as possible in assembler. Perhaps you are already doing that, but if you can avoid clearing BSS here that would be better. > >> > + >> > + __loopt a2, a3, a4, 2 >> > + s32i a0, a2, 0 >> > + __endla a2, a3, 4 >> > + >> > + /* 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 >> >> As above. This is using the old approach. > > I see the same sequence in the ARM's _main in arch/arm/lib/crt0.S: > > mov r0, sp > bl board_init_f_alloc_reserve > mov sp, r0 > /* set up gd here, outside any C code */ > mov r9, r0 > bl board_init_f_init_reserve > > mov r0, #0 > bl board_init_f > > What is 'the new approach' and how does it differ from the old? The old approach was to have it all in assembler. > > [...] > >> > + /* Does not return here. */ >> >> nit: drop periods before */ > > Ok. > > [...] > >> > +fast_alloca_exception: /* must be at _WindowUnderflow4 + 16 >> >> */ ? > > Oops, right. > > [...] > >> > 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) } >> >> Are you including the list regions, etc.? u_boot_list is what it is in >> most .lds files. > > Yes, it's in the SECTION_u_boot_list a few lines above. OK I see. Regards, Simon
diff --git a/arch/Kconfig b/arch/Kconfig index 566f044..a36ac2f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -83,6 +83,13 @@ config X86 select DM_SPI select DM_SPI_FLASH +config XTENSA + bool "Xtensa architecture" + select CREATE_ARCH_SYMLINK + select HAVE_GENERIC_BOARD + select SUPPORT_OF_CONTROL + select SYS_GENERIC_BOARD + endchoice config SYS_ARCH @@ -156,3 +163,4 @@ source "arch/sandbox/Kconfig" source "arch/sh/Kconfig" source "arch/sparc/Kconfig" source "arch/x86/Kconfig" +source "arch/xtensa/Kconfig" diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig new file mode 100644 index 0000000..e4e3625 --- /dev/null +++ b/arch/xtensa/Kconfig @@ -0,0 +1,26 @@ +menu "Xtensa architecture" + depends on XTENSA + +config SYS_ARCH + string + default "xtensa" + +config SYS_CPU + string "Xtensa Core Variant" + +choice + prompt "Target select" + + +endchoice + + +config HAVE_SYS_ASCDISP + bool + +config SYS_ASCDISP + bool "System LCD Display" + default y + depends on HAVE_SYS_ASCDISP + +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..fb7f810 --- /dev/null +++ b/arch/xtensa/cpu/cpu.c @@ -0,0 +1,92 @@ +/* + * (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; + +#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 + +/* + * Implement the "reset" command. + * We need support from the board, though. + */ + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + board_reset(); + + /* Shouldn't come back! */ + printf("****** RESET FAILED ******\n"); + return 0; +} + +/* + * We currently run always with caches enabled when running for mmemory. + * 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_range(ulong start_addr, ulong end_addr) +{ + __flush_invalidate_dcache_range(start_addr, end_addr - start_addr); +} + +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..412ca5f --- /dev/null +++ b/arch/xtensa/cpu/exceptions.c @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2008 - 2013 Tensilica Inc. + * (C) Copyright 2014 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/xtensa.h> +#include <asm/string.h> +#include <asm/regs.h> + +typedef void (*handler_t)(struct pt_regs *); + +void xtensa_mem_exc_dummy(struct pt_regs *); + +void unhandled_exception(struct pt_regs *regs) +{ + display_printf("!! EXCCAUSE = %2ld", regs->exccause); + printf("Unhandled Exception: EXCCAUSE = %ld (pc %lx)\n", + regs->exccause, regs->pc); + udelay(10000000); /* 10s to read display message */ + panic("*** PANIC\n"); +} + +handler_t exc_table[EXCCAUSE_LAST] = { + [0 ... EXCCAUSE_LAST-1] = unhandled_exception, + [EXCCAUSE_LOAD_STORE_ERROR] = xtensa_mem_exc_dummy, + [EXCCAUSE_UNALIGNED] = xtensa_mem_exc_dummy, + [EXCCAUSE_LOAD_STORE_DATA_ERROR] = xtensa_mem_exc_dummy, + [EXCCAUSE_LOAD_STORE_ADDR_ERROR] = xtensa_mem_exc_dummy, + [EXCCAUSE_FETCH_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, + [EXCCAUSE_DTLB_MISS] = xtensa_mem_exc_dummy, + [EXCCAUSE_DTLB_MULTIHIT] = xtensa_mem_exc_dummy, + [EXCCAUSE_DTLB_PRIVILEGE] = xtensa_mem_exc_dummy, + [EXCCAUSE_DTLB_SIZE_RESTRICTION] = xtensa_mem_exc_dummy, + [EXCCAUSE_LOAD_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, + [EXCCAUSE_STORE_CACHE_ATTRIBUTE] = xtensa_mem_exc_dummy, +}; + +#ifdef CONFIG_USE_IRQ +#error "Use of interrupts is not supported in Xtensa port" +#else +int interrupt_init(void) +{ + return 0; +} + +void enable_interrupts(void) +{ +} + +int disable_interrupts(void) +{ + return 0; +} +#endif diff --git a/arch/xtensa/cpu/start.S b/arch/xtensa/cpu/start.S new file mode 100644 index 0000000..ac32efb --- /dev/null +++ b/arch/xtensa/cpu/start.S @@ -0,0 +1,737 @@ +/* + * (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 + + /* Clear BSS */ + + movi a2, _bss_start + movi a3, _bss_end + + __loopt a2, a3, a4, 2 + s32i a0, a2, 0 + __endla a2, a3, 4 + + /* 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 + s32i a2, a1, PT_SAR + s32i a3, a1, PT_PC + +#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 + + +/* + * Dummy memory exception handler to avoid crash/hang on load/store of + * an invalid address (such as might be requested by user "md" command). + * U-Boot currently does not provide a hook to prevent accessing invalid + * addresses nor to inform the user, so we have to try to live with it. + * Simply skip the offending instruction (don't care what load returns). + * This is ugly (and possibly dangerous in Xtensa FLIX configs), but if we + * get here we're in trouble anyway, so might as well *try* to recover. + * void xtensa_mem_exc_dummy(struct pt_regs*); + */ + /* Table of instruction sizes based on op0 field. */ + .section .rodata, "a" + .type op0_format_lengths, @object + .align 4 +op0_format_lengths: + .byte XCHAL_OP0_FORMAT_LENGTHS + + .text + .global xtensa_mem_exc_dummy + .type xtensa_mem_exc_dummy, @function + .align 4 +xtensa_mem_exc_dummy: + + abi_entry + + /* Decode the size of the instruction that caused the exception. */ + l32i a3, a2, PT_PC /* a3 = PC of exception */ + l8ui a4, a3, 0 /* a4 = first byte of insn */ + movi a5, op0_format_lengths /* a5 = table of instruction sizes */ + #if XCHAL_HAVE_BE + extui a4, a4, 4, 4 /* a4 = op0 = big end nibble */ + #else + extui a4, a4, 0, 4 /* a4 = op0 = little end nibble */ + #endif + add a5, a5, a4 /* index table with op0 */ + l8ui a4, a5, 0 /* a4 = instruction size */ + + /* Increment the PC past the instruction that caused the exception. */ + add a3, a3, a4 /* PC += size of insn */ + #if XCHAL_HAVE_LOOPS + l32i a4, a2, PT_LEND /* if (PC == LEND */ + bne a3, a4, 1f + l32i a4, a2, PT_LCOUNT /* && LCOUNT != 0) */ + beqz a4, 1f /* { */ + addi a4, a4, -1 /* --LCOUNT */ + l32i a3, a2, PT_LBEG /* PC = LBEG */ + s32i a4, a2, PT_LCOUNT /* } */ + #endif +1: s32i a3, a2, PT_PC /* update PC */ + + abi_ret + +#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..dd79485 --- /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..485bc4b --- /dev/null +++ b/arch/xtensa/include/asm/byteorder.h @@ -0,0 +1,81 @@ +/* + * 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..3999122 --- /dev/null +++ b/arch/xtensa/include/asm/cache.h @@ -0,0 +1,20 @@ +/* + * 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_invalidate_dcache_range(unsigned long addr, unsigned long size); +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..0a87d9f --- /dev/null +++ b/arch/xtensa/include/asm/io.h @@ -0,0 +1,149 @@ +/* + * 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); +} + +static inline void iounmap(void *addr) +{ +} + +/* + * 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) + +/* We are using uncached addresses, ie: 0x80000000 ... */ +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) +{ +} + +/* + * 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..bb8ca61 --- /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..6f623ef --- /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/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..e30f519 --- /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/include/asm/xtensa.h b/arch/xtensa/include/asm/xtensa.h new file mode 100644 index 0000000..a68024d --- /dev/null +++ b/arch/xtensa/include/asm/xtensa.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Tensilica, Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * + * A place for global definitions specific to Xtensa-based ports. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _XTENSA_H_ +#define _XTENSA_H_ + +#include <stdarg.h> +#include <config.h> +#include <asm/u-boot.h> + +#ifdef CONFIG_SYS_ASCDISP +/* + * Print a formatted string to the board's ASCII character display. + * String may have embedded newlines. Starts at top left and wraps long lines. + */ +void display_printf(const char *fmt, ...); +#else +static inline void display_printf(const char *fmt, ...) +{ +} +#endif + +#endif /* _XTENSA_H_ */ diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile new file mode 100644 index 0000000..72e7bc8 --- /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 += misc.o time.o diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c new file mode 100644 index 0000000..8c89d2c --- /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/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/time.c b/arch/xtensa/lib/time.c new file mode 100644 index 0000000..6d0ff03 --- /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