Commit c978b524 authored by Chris Zankel's avatar Chris Zankel Committed by Tom Rini

xtensa: add support for the xtensa processor architecture [2/2]

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: 's avatarChris Zankel <chris@zankel.net>
Signed-off-by: 's avatarMax Filippov <jcmvbkbc@gmail.com>
Reviewed-by: 's avatarSimon Glass <sjg@chromium.org>
Reviewed-by: 's avatarTom Rini <trini@konsulko.com>
parent de5e5cea
......@@ -88,6 +88,11 @@ config X86
select DM_SPI
select DM_SPI_FLASH
config XTENSA
bool "Xtensa architecture"
select CREATE_ARCH_SYMLINK
select SUPPORT_OF_CONTROL
endchoice
config SYS_ARCH
......@@ -161,3 +166,4 @@ source "arch/sandbox/Kconfig"
source "arch/sh/Kconfig"
source "arch/sparc/Kconfig"
source "arch/x86/Kconfig"
source "arch/xtensa/Kconfig"
menu "Xtensa architecture"
depends on XTENSA
config SYS_ARCH
string
default "xtensa"
config SYS_CPU
string "Xtensa Core Variant"
choice
prompt "Target select"
endchoice
endmenu
#
# SPDX-License-Identifier: GPL-2.0+
#
head-y := arch/xtensa/cpu/start.o
libs-y += arch/xtensa/cpu/
libs-y += arch/xtensa/lib/
#
# (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
#
# (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
/*
* (C) Copyright 2008 - 2013 Tensilica Inc.
* (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* CPU specific code
*/
#include <common.h>
#include <command.h>
#include <linux/stringify.h>
#include <asm/global_data.h>
#include <asm/cache.h>
#include <asm/string.h>
#include <asm/misc.h>
DECLARE_GLOBAL_DATA_PTR;
gd_t *gd __attribute__((section(".data")));
#if defined(CONFIG_DISPLAY_CPUINFO)
/*
* Print information about the CPU.
*/
int print_cpuinfo(void)
{
char buf[120], mhz[8];
uint32_t id0, id1;
asm volatile ("rsr %0, 176\n"
"rsr %1, 208\n"
: "=r"(id0), "=r"(id1));
sprintf(buf, "CPU: Xtensa %s (id: %08x:%08x) at %s MHz\n",
XCHAL_CORE_ID, id0, id1, strmhz(mhz, gd->cpu_clk));
puts(buf);
return 0;
}
#endif
int arch_cpu_init(void)
{
gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
return 0;
}
/*
* (C) Copyright 2008 - 2013 Tensilica Inc.
* (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* Exception handling.
* We currently don't handle any exception and force a reset.
* (Note that alloca is a special case and handled in start.S)
*/
#include <common.h>
#include <command.h>
#include <asm/string.h>
#include <asm/regs.h>
typedef void (*handler_t)(struct pt_regs *);
void unhandled_exception(struct pt_regs *regs)
{
printf("Unhandled Exception: EXCCAUSE = %ld, EXCVADDR = %lx, pc = %lx\n",
regs->exccause, regs->excvaddr, regs->pc);
panic("*** PANIC\n");
}
handler_t exc_table[EXCCAUSE_LAST] = {
[0 ... EXCCAUSE_LAST-1] = unhandled_exception,
};
int interrupt_init(void)
{
return 0;
}
void enable_interrupts(void)
{
}
int disable_interrupts(void)
{
return 0;
}
This diff is collapsed.
/*
* (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) }
}
#
# SPDX-License-Identifier: GPL-2.0+
#
targets += $(dtb-y)
DTC_FLAGS +=
PHONY += dtbs
dtbs: $(addprefix $(obj)/, $(dtb-y))
@:
clean-files := *.dtb
../../../../include/dt-bindings
\ No newline at end of file
/*
* 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 */
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* Copyright (C) 2009 Tensilica Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _XTENSA_CACHE_H
#define _XTENSA_CACHE_H
#include <asm/arch/core.h>
#define ARCH_DMA_MINALIGN XCHAL_DCACHE_LINESIZE
#ifndef __ASSEMBLY__
void __flush_dcache_all(void);
void __flush_invalidate_dcache_range(unsigned long addr, unsigned long size);
void __invalidate_dcache_all(void);
void __invalidate_dcache_range(unsigned long addr, unsigned long size);
void __invalidate_icache_all(void);
void __invalidate_icache_range(unsigned long addr, unsigned long size);
#endif
#endif /* _XTENSA_CACHE_H */