[PATCH v2 00/10] xtensa: Enable qemu-xtensa board

Hi all,
This series enabled qemu-xtensa board.
For dc232b CPU it needs to be built with toolchain[1].
This is a side product of me investigating architectures physical address != virtual address in U-Boot. Now we can get it covered under CI and regular tests.
VirtIO devices are not working as expected, due to U-Boot's assumption on VA == PA everywhere, I'm going to get this fixed later.
My Xtensa knowledge is pretty limited, Xtensa people please feel free to point out if I got anything wrong.
Thanks [1]: https://github.com/foss-xtensa/toolchain/releases/download/2020.07/x86_64-20...
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- Changes in v2: - Fix noMMU memory mappings - Addressing Max's comments in other patches - Link to v1: https://lore.kernel.org/r/20240519-qemu-xtensa-v1-0-8fff0cb11c19@flygoat.com
--- Jiaxun Yang (10): xtensa: Move dram_init to xtfpga board file xtensa: Correct define of _end symbol xtensa: Implement phys virt conversion for PTP_MMU xtensa: Define PLATFORM_ELFFLAGS xtensa: Bring in semihosting headers and config options drivers: serial: Add xtensa semihosting driver drivers: cpu: Add xtensa CPU driver dts/upsteam: Add Makefile for xtensa board: emulation: New board qemu-xtensa doc: New documentation for qemu-xtensa
arch/xtensa/Kconfig | 32 +++++++ arch/xtensa/config.mk | 6 ++ arch/xtensa/cpu/cpu.c | 5 - arch/xtensa/cpu/u-boot.lds | 2 + arch/xtensa/dts/virt-u-boot.dtsi | 17 ++++ arch/xtensa/include/asm/addrspace.h | 2 + arch/xtensa/include/asm/io.h | 32 +++++++ arch/xtensa/include/asm/ldscript.h | 1 - arch/xtensa/include/asm/platform/simcall-gdbio.h | 34 +++++++ arch/xtensa/include/asm/platform/simcall-iss.h | 73 ++++++++++++++ arch/xtensa/include/asm/platform/simcall.h | 110 +++++++++++++++++++++ board/cadence/xtfpga/xtfpga.c | 5 + board/emulation/qemu-xtensa/Kconfig | 42 ++++++++ board/emulation/qemu-xtensa/MAINTAINERS | 8 ++ board/emulation/qemu-xtensa/Makefile | 5 + board/emulation/qemu-xtensa/qemu-xtensa.c | 60 ++++++++++++ configs/qemu-xtensa-dc232b_defconfig | 32 +++++++ doc/board/emulation/index.rst | 1 + doc/board/emulation/qemu-xtensa.rst | 33 +++++++ drivers/cpu/Kconfig | 6 ++ drivers/cpu/Makefile | 1 + drivers/cpu/xtensa_cpu.c | 117 +++++++++++++++++++++++ drivers/serial/Kconfig | 18 +++- drivers/serial/Makefile | 1 + drivers/serial/serial_xtensa_semihosting.c | 92 ++++++++++++++++++ dts/upstream/src/xtensa/Makefile | 14 +++ include/configs/qemu-xtensa.h | 36 +++++++ 27 files changed, 778 insertions(+), 7 deletions(-) --- base-commit: 3be9f399e911cfc437a37ac826441f1d96da1c9b change-id: 20240519-qemu-xtensa-5fb95bb474e9
Best regards,

This is a board level stuff.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- arch/xtensa/cpu/cpu.c | 5 ----- board/cadence/xtfpga/xtfpga.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/xtensa/cpu/cpu.c b/arch/xtensa/cpu/cpu.c index abcd8f7984fa..d2266812229c 100644 --- a/arch/xtensa/cpu/cpu.c +++ b/arch/xtensa/cpu/cpu.c @@ -48,8 +48,3 @@ int arch_cpu_init(void) gd->ram_size = CFG_SYS_SDRAM_SIZE; return 0; } - -int dram_init(void) -{ - return 0; -} diff --git a/board/cadence/xtfpga/xtfpga.c b/board/cadence/xtfpga/xtfpga.c index 5110fed31194..6b92fe31c0e0 100644 --- a/board/cadence/xtfpga/xtfpga.c +++ b/board/cadence/xtfpga/xtfpga.c @@ -66,6 +66,11 @@ unsigned long get_board_sys_clk(void) #endif }
+int dram_init(void) +{ + return 0; +} + int board_postclk_init(void) { gd->cpu_clk = get_board_sys_clk();

So U-Boot is using _end symbol to detect location of devicetree appended at the end of the ROM.
It needs to be calculated based on end of .data load address, as in our lds .current address is address in RAM.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- arch/xtensa/cpu/u-boot.lds | 2 ++ arch/xtensa/include/asm/ldscript.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/xtensa/cpu/u-boot.lds b/arch/xtensa/cpu/u-boot.lds index 84ba32c04444..72e4b9a706e5 100644 --- a/arch/xtensa/cpu/u-boot.lds +++ b/arch/xtensa/cpu/u-boot.lds @@ -82,6 +82,8 @@ SECTIONS
__reloc_end = .; __init_end = .; + /* Calculation to get end address in ROM */ + _end = LOADADDR(.data) + (_data_end - _data_start);
SECTION_bss(__init_end (OVERLAY),)
diff --git a/arch/xtensa/include/asm/ldscript.h b/arch/xtensa/include/asm/ldscript.h index 78a0b230bdaa..bcf0fd5a7443 100644 --- a/arch/xtensa/include/asm/ldscript.h +++ b/arch/xtensa/include/asm/ldscript.h @@ -165,7 +165,6 @@ . = ALIGN(8); \ _bss_end = ABSOLUTE(.); \ __bss_end = ABSOLUTE(.); \ - _end = ALIGN(0x8); \ PROVIDE(end = ALIGN(0x8)); \ _stack_sentry = ALIGN(0x8); \ }

For PTP_MMU our physical address is not directly mapped into virtual address space, we need to access physical memory from those fixed map segments.
Implement phys_to_virt and virt_to_phys hook to reflect this setting.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- arch/xtensa/include/asm/addrspace.h | 2 ++ arch/xtensa/include/asm/io.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/arch/xtensa/include/asm/addrspace.h b/arch/xtensa/include/asm/addrspace.h index 920b5fd26b20..c8bed8834b55 100644 --- a/arch/xtensa/include/asm/addrspace.h +++ b/arch/xtensa/include/asm/addrspace.h @@ -7,6 +7,8 @@ #ifndef _XTENSA_ADDRSPACE_H #define _XTENSA_ADDRSPACE_H
+#include <config.h> + #include <asm/arch/core.h>
/* diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h index 87ad9faa2995..ab2438b829ac 100644 --- a/arch/xtensa/include/asm/io.h +++ b/arch/xtensa/include/asm/io.h @@ -12,6 +12,8 @@ #include <linux/types.h> #include <asm/byteorder.h>
+#include <asm/addrspace.h> + /* * swap functions to change byte order from little-endian to big-endian and * vice versa. @@ -127,6 +129,36 @@ static inline void sync(void) { }
+#if XCHAL_HAVE_PTP_MMU +static inline void *phys_to_virt(phys_addr_t paddr) +{ + if (paddr >= CFG_SYS_IO_BASE) + return (void *)(unsigned long)paddr; + + if (paddr < CFG_MAX_MEM_MAPPED) + return (void *)(unsigned long)MEMADDR(paddr); + + return NULL; +} + +#define phys_to_virt phys_to_virt + +static inline phys_addr_t virt_to_phys(void *vaddr) +{ + unsigned long addr = (unsigned long)vaddr; + + if (addr >= CFG_SYS_IO_BASE) + return addr; + + if (addr >= CFG_SYS_SDRAM_BASE && addr < MEMADDR(CFG_MAX_MEM_MAPPED)) + return PHYSADDR(addr); + + return 0; +} + +#define virt_to_phys virt_to_phys +#endif /* XCHAL_HAVE_PTP_MMU */ + #include <asm-generic/io.h>
#endif /* _XTENSA_IO_H */

u-boot.elf target requires it to work.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- v2: - Concerning big endian CPU
Note: CONFIG_SYS_BIG_ENDIAN will never be set for xtensa for now, but as we don't have big endian headers for xtensa core either I think it's fine for now. This will be improved after my arm64be work get merged. --- arch/xtensa/config.mk | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/xtensa/config.mk b/arch/xtensa/config.mk index b0809999e403..200b66f85047 100644 --- a/arch/xtensa/config.mk +++ b/arch/xtensa/config.mk @@ -7,3 +7,9 @@ PLATFORM_CPPFLAGS += -D__XTENSA__ -mlongcalls -mforce-no-pic \ -ffunction-sections -fdata-sections
LDFLAGS_FINAL += --gc-sections + +ifeq ($(CONFIG_SYS_BIG_ENDIAN),y) +PLATFORM_CPPFLAGS += -B xtensa -O elf32-xtensa-be +else +PLATFORM_ELFFLAGS += -B xtensa -O elf32-xtensa-le +endif

They are all directly imported from Linux kernel.
Reviewed-by: Max Filippov jcmvbkbc@gmail.com Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- arch/xtensa/Kconfig | 27 ++++++ arch/xtensa/include/asm/platform/simcall-gdbio.h | 34 +++++++ arch/xtensa/include/asm/platform/simcall-iss.h | 73 +++++++++++++++ arch/xtensa/include/asm/platform/simcall.h | 110 +++++++++++++++++++++++ 4 files changed, 244 insertions(+)
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 8f668cc67ed0..4afd56bca095 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -41,6 +41,33 @@ config SPL_SYS_DCACHE_OFF help Do not enable data cache in SPL.
+config XTENSA_SEMIHOSTING + bool "Support semihosting" + help + Enable Xtensa semihosting debugging support. + +choice + prompt "Semihosting interface" + default XTENSA_SIMCALL_ISS + depends on XTENSA_SEMIHOSTING + help + Choose semihosting interface that will be used for serial port, + block device and networking. + +config XTENSA_SIMCALL_ISS + bool "simcall" + help + Use simcall instruction. simcall is only available on simulators, + it does nothing on hardware. + +config XTENSA_SIMCALL_GDBIO + bool "GDBIO" + help + Use break instruction. It is available on real hardware when GDB + is attached to it via JTAG. + +endchoice + source "board/cadence/xtfpga/Kconfig"
endmenu diff --git a/arch/xtensa/include/asm/platform/simcall-gdbio.h b/arch/xtensa/include/asm/platform/simcall-gdbio.h new file mode 100644 index 000000000000..e642860e25a8 --- /dev/null +++ b/arch/xtensa/include/asm/platform/simcall-gdbio.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2021 Cadence Design Systems Inc. */ + +#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_GDBIO_H +#define _XTENSA_PLATFORM_ISS_SIMCALL_GDBIO_H + +/* + * System call like services offered by the GDBIO host. + */ + +#define SYS_open -2 +#define SYS_close -3 +#define SYS_read -4 +#define SYS_write -5 +#define SYS_lseek -6 + +static int errno; + +static inline int __simc(int a, int b, int c, int d) +{ + register int a1 asm("a2") = a; + register int b1 asm("a6") = b; + register int c1 asm("a3") = c; + register int d1 asm("a4") = d; + __asm__ __volatile__ ( + "break 1, 14\n" + : "+r"(a1), "+r"(c1) + : "r"(b1), "r"(d1) + : "memory"); + errno = c1; + return a1; +} + +#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_GDBIO_H */ diff --git a/arch/xtensa/include/asm/platform/simcall-iss.h b/arch/xtensa/include/asm/platform/simcall-iss.h new file mode 100644 index 000000000000..5a1e7a1f182e --- /dev/null +++ b/arch/xtensa/include/asm/platform/simcall-iss.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2021 Cadence Design Systems Inc. */ + +#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_ISS_H +#define _XTENSA_PLATFORM_ISS_SIMCALL_ISS_H + +/* + * System call like services offered by the simulator host. + */ + +#define SYS_nop 0 /* unused */ +#define SYS_exit 1 /*x*/ +#define SYS_fork 2 +#define SYS_read 3 /*x*/ +#define SYS_write 4 /*x*/ +#define SYS_open 5 /*x*/ +#define SYS_close 6 /*x*/ +#define SYS_rename 7 /*x 38 - waitpid */ +#define SYS_creat 8 /*x*/ +#define SYS_link 9 /*x (not implemented on WIN32) */ +#define SYS_unlink 10 /*x*/ +#define SYS_execv 11 /* n/a - execve */ +#define SYS_execve 12 /* 11 - chdir */ +#define SYS_pipe 13 /* 42 - time */ +#define SYS_stat 14 /* 106 - mknod */ +#define SYS_chmod 15 +#define SYS_chown 16 /* 202 - lchown */ +#define SYS_utime 17 /* 30 - break */ +#define SYS_wait 18 /* n/a - oldstat */ +#define SYS_lseek 19 /*x*/ +#define SYS_getpid 20 +#define SYS_isatty 21 /* n/a - mount */ +#define SYS_fstat 22 /* 108 - oldumount */ +#define SYS_time 23 /* 13 - setuid */ +#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */ +#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */ +#define SYS_socket 26 +#define SYS_sendto 27 +#define SYS_recvfrom 28 +#define SYS_select_one 29 /* not compatible select, one file descriptor at the time */ +#define SYS_bind 30 +#define SYS_ioctl 31 + +#define SYS_iss_argc 1000 /* returns value of argc */ +#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */ +#define SYS_iss_set_argv 1002 /* saves argv & arg strings at given addr */ + +/* + * SYS_select_one specifiers + */ + +#define XTISS_SELECT_ONE_READ 1 +#define XTISS_SELECT_ONE_WRITE 2 +#define XTISS_SELECT_ONE_EXCEPT 3 + +static int errno; + +static inline int __simc(int a, int b, int c, int d) +{ + register int a1 asm("a2") = a; + register int b1 asm("a3") = b; + register int c1 asm("a4") = c; + register int d1 asm("a5") = d; + __asm__ __volatile__ ( + "simcall\n" + : "+r"(a1), "+r"(b1) + : "r"(c1), "r"(d1) + : "memory"); + errno = b1; + return a1; +} + +#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_ISS_H */ diff --git a/arch/xtensa/include/asm/platform/simcall.h b/arch/xtensa/include/asm/platform/simcall.h new file mode 100644 index 000000000000..a1cb269e68f0 --- /dev/null +++ b/arch/xtensa/include/asm/platform/simcall.h @@ -0,0 +1,110 @@ +/* + * include/asm-xtensa/platform-iss/simcall.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 Tensilica Inc. + * Copyright (C) 2017 - 2021 Cadence Design Systems Inc. + */ + +#ifndef _XTENSA_PLATFORM_ISS_SIMCALL_H +#define _XTENSA_PLATFORM_ISS_SIMCALL_H + +#include <linux/bug.h> + +#ifdef CONFIG_XTENSA_SIMCALL_ISS +#include <asm/platform/simcall-iss.h> +#endif +#ifdef CONFIG_XTENSA_SIMCALL_GDBIO +#include <asm/platform/simcall-gdbio.h> +#endif + +static inline int simc_exit(int exit_code) +{ +#ifdef SYS_exit + return __simc(SYS_exit, exit_code, 0, 0); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); + return -1; +#endif +} + +static inline int simc_open(const char *file, int flags, int mode) +{ + return __simc(SYS_open, (int) file, flags, mode); +} + +static inline int simc_close(int fd) +{ + return __simc(SYS_close, fd, 0, 0); +} + +static inline int simc_ioctl(int fd, int request, void *arg) +{ +#ifdef SYS_ioctl + return __simc(SYS_ioctl, fd, request, (int) arg); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); + return -1; +#endif +} + +static inline int simc_read(int fd, void *buf, size_t count) +{ + return __simc(SYS_read, fd, (int) buf, count); +} + +static inline int simc_write(int fd, const void *buf, size_t count) +{ + return __simc(SYS_write, fd, (int) buf, count); +} + +static inline int simc_poll(int fd) +{ +#ifdef SYS_select_one + long timeval[2] = { 0, 0 }; + + return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&timeval); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); + return -1; +#endif +} + +static inline int simc_lseek(int fd, uint32_t off, int whence) +{ + return __simc(SYS_lseek, fd, off, whence); +} + +static inline int simc_argc(void) +{ +#ifdef SYS_iss_argc + return __simc(SYS_iss_argc, 0, 0, 0); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); + return 0; +#endif +} + +static inline int simc_argv_size(void) +{ +#ifdef SYS_iss_argv_size + return __simc(SYS_iss_argv_size, 0, 0, 0); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); + return 0; +#endif +} + +static inline void simc_argv(void *buf) +{ +#ifdef SYS_iss_set_argv + __simc(SYS_iss_set_argv, (int)buf, 0, 0); +#else + WARN_ONCE(1, "%s: not implemented\n", __func__); +#endif +} + +#endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */

Add xtensa semihosting driver.
It can't use regular semihosting driver as Xtensa's has it's own semihosting ABI.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- v2: - Fix simc_serial_pending implementation - Get puts work --- drivers/serial/Kconfig | 18 +++++- drivers/serial/Makefile | 1 + drivers/serial/serial_xtensa_semihosting.c | 92 ++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1fe4607598eb..3a1e5a6f2877 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -501,6 +501,15 @@ config DEBUG_UART_MT7620 driver will be available until the real driver model serial is running.
+config DEBUG_UART_XTENSA_SEMIHOSTING + bool "Xtensa semihosting" + depends on XTENSA_SEMIHOSTING_SERIAL + help + Select this to enable the debug UART using the Xtensa semihosting driver. + This provides basic serial output from the console without needing to + start up driver model. The driver will be available until the real + driver model serial is running. + endchoice
config DEBUG_UART_BASE @@ -936,7 +945,6 @@ config SH_SCIF_CLK_FREQ config SEMIHOSTING_SERIAL bool "Semihosting UART support" depends on SEMIHOSTING && !SERIAL_RX_BUFFER - imply SERIAL_PUTS help Select this to enable a serial UART using semihosting. Special halt instructions will be issued which an external debugger (such as a @@ -1115,6 +1123,14 @@ config XEN_SERIAL If built without DM support, then requires Xen to be built with CONFIG_VERBOSE_DEBUG.
+config XTENSA_SEMIHOSTING_SERIAL + bool "Xtensa Semihosting UART support" + depends on DM_SERIAL + depends on XTENSA_SEMIHOSTING + imply SERIAL_PUTS + help + Select this to enable a serial UART using Xtensa semihosting. + choice prompt "Console port" default 8xx_CONS_SMC1 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index dbe598b74064..78810f98367c 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_MT7620_SERIAL) += serial_mt7620.o obj-$(CONFIG_HTIF_CONSOLE) += serial_htif.o obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o obj-$(CONFIG_XEN_SERIAL) += serial_xen.o +obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o
ifndef CONFIG_SPL_BUILD diff --git a/drivers/serial/serial_xtensa_semihosting.c b/drivers/serial/serial_xtensa_semihosting.c new file mode 100644 index 000000000000..0e59a9bfdc75 --- /dev/null +++ b/drivers/serial/serial_xtensa_semihosting.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + */ + +#include <dm.h> +#include <malloc.h> +#include <serial.h> + +#include <asm/platform/simcall.h> + +/** + * struct simc_serial_priv - Semihosting serial private data + * @counter: Counter used to fake pending every other call + */ +struct simc_serial_priv { + unsigned int counter; +}; + +static int simc_serial_getc(struct udevice *dev) +{ + char ch = 0; + + simc_read(0, &ch, sizeof(ch)); + + return ch; +} + +static int simc_serial_putc(struct udevice *dev, const char ch) +{ + char str[2] = {0}; + + str[0] = ch; + simc_write(1, str, 1); + + return 0; +} + +static int simc_serial_pending(struct udevice *dev, bool input) +{ + struct simc_serial_priv *priv = dev_get_priv(dev); + + if (input) { + int res = simc_poll(0); + return res < 0 ? priv->counter++ & 1 : res; + } + + return false; +} + +static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len) +{ + int ret; + + ret = simc_write(1, s, len); + + return ret; +} + +static const struct dm_serial_ops simc_serial_ops = { + .putc = simc_serial_putc, + .puts = smh_serial_puts, + .getc = simc_serial_getc, + .pending = simc_serial_pending, +}; + +U_BOOT_DRIVER(simc_serial) = { + .name = "serial_xtensa_semihosting", + .id = UCLASS_SERIAL, + .priv_auto = sizeof(struct simc_serial_priv), + .ops = &simc_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRVINFO(simc_serial) = { + .name = "serial_xtensa_semihosting", +}; + +#if CONFIG_IS_ENABLED(DEBUG_UART_XTENSA_SEMIHOSTING) +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int c) +{ + simc_serial_putc(NULL, c); +} + +DEBUG_UART_FUNCS +#endif

Implement various CPU related functions. I'm actually just using it to get cpu clock frequency.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- drivers/cpu/Kconfig | 6 +++ drivers/cpu/Makefile | 1 + drivers/cpu/xtensa_cpu.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+)
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 1c3c810651ef..5c06cd9f60e8 100644 --- a/drivers/cpu/Kconfig +++ b/drivers/cpu/Kconfig @@ -33,3 +33,9 @@ config CPU_MICROBLAZE select XILINX_MICROBLAZE0_PVR help Support CPU cores for Microblaze architecture. + +config CPU_XTENSA + bool "Enable Xtensa CPU driver" + depends on CPU && XTENSA + help + Support CPU cores for Xtensa architecture. diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index d4bbf6fa5e05..bc75d9b974e8 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_CPU_IMX) += imx8_cpu.o obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o obj-$(CONFIG_CPU_MICROBLAZE) += microblaze_cpu.o +obj-$(CONFIG_CPU_XTENSA) += xtensa_cpu.o obj-$(CONFIG_SANDBOX) += cpu_sandbox.o diff --git a/drivers/cpu/xtensa_cpu.c b/drivers/cpu/xtensa_cpu.c new file mode 100644 index 000000000000..fbb561dd6128 --- /dev/null +++ b/drivers/cpu/xtensa_cpu.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + */ + +#include <clk.h> +#include <cpu.h> +#include <dm.h> +#include <errno.h> +#include <linux/bitops.h> +#include <linux/err.h> + +#include <asm/arch/core.h> + +static int xtensa_cpu_get_desc(const struct udevice *dev, char *buf, int size) +{ + const char *cpu = XCHAL_CORE_ID; + + if (!cpu || size < (strlen(cpu) + 1)) + return -ENOSPC; + + strcpy(buf, cpu); + + return 0; +} + +static int xtensa_cpu_get_info(const struct udevice *dev, struct cpu_info *info) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + + info->cpu_freq = plat->timebase_freq; + +#if XCHAL_HAVE_PTP_MMU + info->features |= BIT(CPU_FEAT_MMU); +#endif +#if XCHAL_ICACHE_SIZE || XCHAL_DCACHE_SIZE + info->features |= BIT(CPU_FEAT_L1_CACHE); +#endif + + return 0; +} + +static int xtensa_cpu_get_count(const struct udevice *dev) +{ + ofnode node; + int num = 0; + + ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { + const char *device_type; + + /* skip if hart is marked as not available in the device tree */ + if (!ofnode_is_enabled(node)) + continue; + + device_type = ofnode_read_string(node, "device_type"); + if (!device_type) + continue; + if (strcmp(device_type, "cpu") == 0) + num++; + } + + return num; +} + +static int xtensa_cpu_bind(struct udevice *dev) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + + plat->cpu_id = dev_read_addr(dev); + + return 0; +} + +static int xtensa_cpu_probe(struct udevice *dev) +{ + int ret = 0; + struct clk clk; + struct cpu_plat *plat = dev_get_parent_plat(dev); + + asm volatile ("rsr %0, 176\n" + "rsr %1, 208\n" + : "=r"(plat->id[0]), "=r"(plat->id[1])); + + /* Get a clock if it exists */ + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) { + ret = clk_enable(&clk); + if (ret && (ret != -ENOSYS || ret != -ENOTSUPP)) + return ret; + ret = clk_get_rate(&clk); + if (!IS_ERR_VALUE(ret)) + plat->timebase_freq = ret; + } + + return 0; +} + +static const struct cpu_ops xtensa_cpu_ops = { + .get_desc = xtensa_cpu_get_desc, + .get_info = xtensa_cpu_get_info, + .get_count = xtensa_cpu_get_count, +}; + +static const struct udevice_id xtensa_cpu_ids[] = { + { .compatible = "cdns,xtensa-cpu" }, + { } +}; + +U_BOOT_DRIVER(xtensa_cpu) = { + .name = "xtensa_cpu", + .id = UCLASS_CPU, + .of_match = xtensa_cpu_ids, + .bind = xtensa_cpu_bind, + .probe = xtensa_cpu_probe, + .ops = &xtensa_cpu_ops, + .flags = DM_FLAG_PRE_RELOC, +};

It is required to get it xtensa OF_UPSTREAM work.
Reviewed-by: Sumit Garg sumit.garg@linaro.org Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- dts/upstream/src/xtensa/Makefile | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/dts/upstream/src/xtensa/Makefile b/dts/upstream/src/xtensa/Makefile new file mode 100644 index 000000000000..2a81acb32bc3 --- /dev/null +++ b/dts/upstream/src/xtensa/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0+ + +include $(srctree)/scripts/Makefile.dts + +targets += $(dtb-y) + +# Add any required device tree compiler flags here +DTC_FLAGS += -a 0x8 + +PHONY += dtbs +dtbs: $(addprefix $(obj)/, $(dtb-y)) + @: + +clean-files := *.dtb *.dtbo */*.dtb */*.dtbo

Introduce the new board, define every bits.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- v2: - Fix maintainers entries - Refine address mapping for noMMU machine - Add a dtsi overlay to describe different memory size for noMMU system --- arch/xtensa/Kconfig | 5 +++ arch/xtensa/dts/virt-u-boot.dtsi | 17 +++++++++ board/emulation/qemu-xtensa/Kconfig | 42 ++++++++++++++++++++++ board/emulation/qemu-xtensa/MAINTAINERS | 8 +++++ board/emulation/qemu-xtensa/Makefile | 5 +++ board/emulation/qemu-xtensa/qemu-xtensa.c | 60 +++++++++++++++++++++++++++++++ configs/qemu-xtensa-dc232b_defconfig | 32 +++++++++++++++++ include/configs/qemu-xtensa.h | 36 +++++++++++++++++++ 8 files changed, 205 insertions(+)
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 4afd56bca095..70eebb4bd22f 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -15,6 +15,10 @@ config TARGET_XTFPGA bool "Support XTFPGA" select BOARD_POSTCLK_INIT
+config TARGET_QEMU_XTENSA + bool "Support QEMU Xtensa Virt Board" + select BOARD_LATE_INIT + endchoice
config SYS_ICACHE_OFF @@ -69,5 +73,6 @@ config XTENSA_SIMCALL_GDBIO endchoice
source "board/cadence/xtfpga/Kconfig" +source "board/emulation/qemu-xtensa/Kconfig"
endmenu diff --git a/arch/xtensa/dts/virt-u-boot.dtsi b/arch/xtensa/dts/virt-u-boot.dtsi new file mode 100644 index 000000000000..22b4683e7617 --- /dev/null +++ b/arch/xtensa/dts/virt-u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + */ + +#include <config.h> + +/ { + memory@0 { + device_type = "memory"; +#if XCHAL_HAVE_PTP_MMU + reg = <0x00000000 CFG_SYS_SDRAM_SIZE>; +#else + reg = <CFG_SYS_MEMORY_BASE CFG_SYS_SDRAM_SIZE>; +#endif + }; +}; diff --git a/board/emulation/qemu-xtensa/Kconfig b/board/emulation/qemu-xtensa/Kconfig new file mode 100644 index 000000000000..7e2575461be3 --- /dev/null +++ b/board/emulation/qemu-xtensa/Kconfig @@ -0,0 +1,42 @@ +if TARGET_QEMU_XTENSA + +config SYS_BOARD + default "qemu-xtensa" + +config SYS_VENDOR + default "emulation" + +config SYS_CONFIG_NAME + default "qemu-xtensa" + +config TEXT_BASE + default 0x50000000 if (SYS_CPU = de212) + default 0xfe000000 + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select BOARD_EARLY_INIT_F + select DM + select CPU + select CPU_XTENSA + select CLK + select DM_SERIAL + select XTENSA_SEMIHOSTING + select XTENSA_SEMIHOSTING_SERIAL + imply BLK + imply VIRTIO + imply VIRTIO_PCI + imply VIRTIO_NET + imply VIRTIO_BLK + imply E1000 + imply PCI + imply PCI_INIT_R + imply NVME_PCI + imply PCIE_ECAM_GENERIC + imply SCSI + imply REMAKE_ELF + select OF_CONTROL + select OF_UPSTREAM + imply CMD_DM + +endif diff --git a/board/emulation/qemu-xtensa/MAINTAINERS b/board/emulation/qemu-xtensa/MAINTAINERS new file mode 100644 index 000000000000..829c27f86369 --- /dev/null +++ b/board/emulation/qemu-xtensa/MAINTAINERS @@ -0,0 +1,8 @@ +QEMU XTENSA 'VIRT' BOARD +M: Jiaxun Yang jiaxun.yang@flygoat.com +M: Max Filippov jcmvbkbc@gmail.com +S: Maintained +F: board/emulation/qemu-xtensa/ +F: board/emulation/common/ +F: include/configs/qemu-xtensa.h +F: configs/qemu-xtensa-dc232b_defconfig diff --git a/board/emulation/qemu-xtensa/Makefile b/board/emulation/qemu-xtensa/Makefile new file mode 100644 index 000000000000..0f33a65f6c6b --- /dev/null +++ b/board/emulation/qemu-xtensa/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2024, Jiaxun Yang jiaxun.yang@flygoat.com + +obj-y += qemu-xtensa.o diff --git a/board/emulation/qemu-xtensa/qemu-xtensa.c b/board/emulation/qemu-xtensa/qemu-xtensa.c new file mode 100644 index 000000000000..0ca83341c25c --- /dev/null +++ b/board/emulation/qemu-xtensa/qemu-xtensa.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Bin Meng bmeng.cn@gmail.com + */ + +#include <dm.h> +#include <cpu.h> +#include <log.h> +#include <init.h> +#include <usb.h> +#include <virtio_types.h> +#include <virtio.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + return 0; +} + +unsigned long get_board_sys_clk(void) +{ + return gd->cpu_clk ? gd->cpu_clk : 40000000; +} + +int dram_init(void) +{ + return fdtdec_setup_mem_size_base(); +} + +int board_early_init_f(void) +{ + struct cpu_plat *cpu_plat; + struct udevice *cpu = cpu_get_current_dev(); + + if (!cpu) + return -ENODEV; + + cpu_plat = dev_get_parent_plat(cpu); + if (!cpu_plat) + return -ENODEV; + + gd->cpu_clk = cpu_plat->timebase_freq; + return 0; +} + +int board_late_init(void) +{ + /* start usb so that usb keyboard can be used as input device */ + if (CONFIG_IS_ENABLED(USB_KEYBOARD)) + usb_init(); + + /* + * Make sure virtio bus is enumerated so that peripherals + * on the virtio bus can be discovered by their drivers + */ + virtio_init(); + + return 0; +} diff --git a/configs/qemu-xtensa-dc232b_defconfig b/configs/qemu-xtensa-dc232b_defconfig new file mode 100644 index 000000000000..12d5ca9399ae --- /dev/null +++ b/configs/qemu-xtensa-dc232b_defconfig @@ -0,0 +1,32 @@ +CONFIG_XTENSA=y +CONFIG_SYS_CPU="dc232b" +CONFIG_SYS_MALLOC_LEN=0x40000 +CONFIG_SYS_MALLOC_F_LEN=0x400 +CONFIG_ENV_SIZE=0x20000 +CONFIG_DEFAULT_DEVICE_TREE="virt" +CONFIG_SYS_MONITOR_LEN=262144 +CONFIG_SYS_LOAD_ADDR=0x02000000 +CONFIG_TARGET_QEMU_XTENSA=y +CONFIG_REMAKE_ELF=y +CONFIG_SYS_MONITOR_BASE=0xF6000000 +CONFIG_DYNAMIC_SYS_CLK_FREQ=y +CONFIG_SHOW_BOOT_PROGRESS=y +CONFIG_BOOTDELAY=10 +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Autobooting in %d seconds, press <SPACE> to stop\n" +CONFIG_AUTOBOOT_STOP_STR=" " +CONFIG_SYS_PBSIZE=1049 +CONFIG_SYS_MALLOC_BOOTPARAMS=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="U-Boot> " +CONFIG_CMD_ASKENV=y +CONFIG_CRC32_VERIFY=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_SAVES=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_DIAG=y +CONFIG_USE_BOOTFILE=y +CONFIG_BOOTFILE="uImage" +CONFIG_VERSION_VARIABLE=y +CONFIG_SYSRESET=y diff --git a/include/configs/qemu-xtensa.h b/include/configs/qemu-xtensa.h new file mode 100644 index 000000000000..505aa0646bc9 --- /dev/null +++ b/include/configs/qemu-xtensa.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2007-2013 Tensilica, Inc. + * Copyright (C) 2014 - 2016 Cadence Design Systems Inc. + * Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <asm/arch/core.h> +#include <asm/addrspace.h> +#include <asm/config.h> + +#if XCHAL_HAVE_PTP_MMU +#define CFG_SYS_MEMORY_BASE \ + (XCHAL_VECBASE_RESET_VADDR - XCHAL_VECBASE_RESET_PADDR) +#define CFG_SYS_IO_BASE 0xf0000000 +#define CFG_SYS_SDRAM_SIZE 0x80000000 /* xtensa.sysram0 */ +#else +#define CFG_SYS_MEMORY_BASE 0x60000000 +#define CFG_SYS_SDRAM_SIZE 0x08000000 /* xtensa.sysram0 */ +#endif + +#define CFG_SYS_SDRAM_BASE MEMADDR(0x00000000) + +#if defined(CFG_MAX_MEM_MAPPED) && \ + CFG_MAX_MEM_MAPPED < CFG_SYS_SDRAM_SIZE +#define XTENSA_SYS_TEXT_ADDR \ + (MEMADDR(CFG_MAX_MEM_MAPPED) - CONFIG_SYS_MONITOR_LEN) +#else +#define XTENSA_SYS_TEXT_ADDR \ + (MEMADDR(CFG_SYS_SDRAM_SIZE) - CONFIG_SYS_MONITOR_LEN) +#endif + +#endif /* __CONFIG_H */

Introduce the board and provide instructions on how to get it work.
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com --- doc/board/emulation/index.rst | 1 + doc/board/emulation/qemu-xtensa.rst | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst index d3d6b8f3d86b..98a0b26ad245 100644 --- a/doc/board/emulation/index.rst +++ b/doc/board/emulation/index.rst @@ -14,3 +14,4 @@ Emulation qemu-ppce500 qemu-riscv qemu-x86 + qemu-xtensa diff --git a/doc/board/emulation/qemu-xtensa.rst b/doc/board/emulation/qemu-xtensa.rst new file mode 100644 index 000000000000..fdab6d7c439d --- /dev/null +++ b/doc/board/emulation/qemu-xtensa.rst @@ -0,0 +1,33 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2024 Jiaxun Yang jiaxun.yang@flygoat.com + +QEMU Xtensa +=========== + +QEMU for Xtensa supports a special 'virt' machine designed for emulation and +virtualization purposes. This document describes how to run U-Boot under it. + +The QEMU virt machine models a generic Xtensa virtual machine with PCI Bus +and Xtensa ISS simcall semihosting support. It supports many different Xtensa +CPU configuration. Currently, only dc232b variant is tested against U-Boot. + +Building U-Boot +--------------- +Set the CROSS_COMPILE environment variable as usual, and run: + + make qemu-xtensa-dc232b_defconfig + make + +Note that Xtensa's toolchain is bounded to CPU configuration, you must use +the toolchain built for exactly the same CPU configuration as you selected +in U-Boot. + +Running U-Boot +-------------- +The minimal QEMU command line to get U-Boot up and running is: + + qemu-system-xtensa -nographic -machine virt -cpu dc232b -semihosting -kernel ./u-boot.elf + +You many change cpu option to match your U-Boot CPU type configuration. +semihosting option is mandatory because this is the only way to interact +with U-Boot in command line.

Hi Jiaxun,
On Wed, May 22, 2024 at 06:07:56PM +0100, Jiaxun Yang wrote:
This is a side product of me investigating architectures physical address != virtual address in U-Boot. Now we can get it covered under CI and regular tests.
VirtIO devices are not working as expected, due to U-Boot's assumption on VA == PA everywhere, I'm going to get this fixed later.
My Xtensa knowledge is pretty limited, Xtensa people please feel free to point out if I got anything wrong.
Thanks [1]: https://github.com/foss-xtensa/toolchain/releases/download/2020.07/x86_64-20...
Signed-off-by: Jiaxun Yang jiaxun.yang@flygoat.com
Changes in v2:
- Fix noMMU memory mappings
- Addressing Max's comments in other patches
- Link to v1: https://lore.kernel.org/r/20240519-qemu-xtensa-v1-0-8fff0cb11c19@flygoat.com
Tested-by: Max Filippov jcmvbkbc@gmail.com
As expected the build fails for big-endian cores and peripherals are non-functional on MMUv2 cores.
participants (2)
-
Jiaxun Yang
-
Max Filippov