diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index fff78785ee9..cf1ace44144 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -237,7 +237,7 @@ stages: # the below corresponds to .gitlab-ci.yml "before_script" cd \${WORK_DIR} git config --global --add safe.directory \${WORK_DIR} - git clone --depth=1 https://source.denx.de/u-boot/u-boot-test-hooks /tmp/uboot-test-hooks + git clone --depth=1 https://github.com/FlyGoat/u-boot-test-hooks.git /tmp/uboot-test-hooks ln -s travis-ci /tmp/uboot-test-hooks/bin/\`hostname\` ln -s travis-ci /tmp/uboot-test-hooks/py/\`hostname\` grub-mkimage --prefix=\"\" -o ~/grub_x86.efi -O i386-efi normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd @@ -457,6 +457,9 @@ stages: qemu_x86_64: TEST_PY_BD: "qemu-x86_64" TEST_PY_TEST_SPEC: "not sleep" + qemu_xtensa_dc233c: + TEST_PY_BD: "qemu-xtensa-dc233c" + TEST_PY_TEST_SPEC: "not sleep and not efi" r2dplus_i82557c: TEST_PY_BD: "r2dplus" TEST_PY_ID: "--id i82557c_qemu" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a6c5040239a..0a15b7352cd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -422,6 +422,12 @@ qemu-x86_64 test.py: TEST_PY_TEST_SPEC: "not sleep" <<: *buildman_and_testpy_dfn +qemu-xtensa-dc233c test.py: + variables: + TEST_PY_BD: "qemu-xtensa-dc233c" + TEST_PY_TEST_SPEC: "not sleep and not efi" + <<: *buildman_and_testpy_dfn + r2dplus_i82557c test.py: variables: TEST_PY_BD: "r2dplus" diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 8f668cc67ed..70eebb4bd22 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 @@ -41,6 +45,34 @@ 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" +source "board/emulation/qemu-xtensa/Kconfig" endmenu diff --git a/arch/xtensa/config.mk b/arch/xtensa/config.mk index b0809999e40..200b66f8504 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 diff --git a/arch/xtensa/cpu/cpu.c b/arch/xtensa/cpu/cpu.c index abcd8f7984f..d2266812229 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/arch/xtensa/cpu/u-boot.lds b/arch/xtensa/cpu/u-boot.lds index 84ba32c0444..72e4b9a706e 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/dts/virt-u-boot.dtsi b/arch/xtensa/dts/virt-u-boot.dtsi new file mode 100644 index 00000000000..22b4683e761 --- /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 + */ + +#include + +/ { + memory@0 { + device_type = "memory"; +#if XCHAL_HAVE_PTP_MMU + reg = <0x00000000 CFG_SYS_SDRAM_SIZE>; +#else + reg = ; +#endif + }; +}; diff --git a/arch/xtensa/include/asm/addrspace.h b/arch/xtensa/include/asm/addrspace.h index 920b5fd26b2..c8bed8834b5 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 + #include /* diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h index 87ad9faa299..ab2438b829a 100644 --- a/arch/xtensa/include/asm/io.h +++ b/arch/xtensa/include/asm/io.h @@ -12,6 +12,8 @@ #include #include +#include + /* * 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 #endif /* _XTENSA_IO_H */ diff --git a/arch/xtensa/include/asm/ldscript.h b/arch/xtensa/include/asm/ldscript.h index 78a0b230bda..bcf0fd5a744 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); \ } 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 00000000000..e642860e25a --- /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 00000000000..5a1e7a1f182 --- /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 00000000000..a1cb269e68f --- /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 + +#ifdef CONFIG_XTENSA_SIMCALL_ISS +#include +#endif +#ifdef CONFIG_XTENSA_SIMCALL_GDBIO +#include +#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 */ diff --git a/board/cadence/xtfpga/xtfpga.c b/board/cadence/xtfpga/xtfpga.c index 5110fed3119..6b92fe31c0e 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(); diff --git a/board/emulation/qemu-xtensa/Kconfig b/board/emulation/qemu-xtensa/Kconfig new file mode 100644 index 00000000000..8767b6fabbd --- /dev/null +++ b/board/emulation/qemu-xtensa/Kconfig @@ -0,0 +1,43 @@ +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 + imply CMD_PCI + +endif diff --git a/board/emulation/qemu-xtensa/MAINTAINERS b/board/emulation/qemu-xtensa/MAINTAINERS new file mode 100644 index 00000000000..6ffdfe85dee --- /dev/null +++ b/board/emulation/qemu-xtensa/MAINTAINERS @@ -0,0 +1,8 @@ +QEMU XTENSA 'VIRT' BOARD +M: Jiaxun Yang +M: Max Filippov +S: Maintained +F: board/emulation/qemu-xtensa/ +F: board/emulation/common/ +F: include/configs/qemu-xtensa.h +F: configs/qemu-xtensa-dc233c_defconfig diff --git a/board/emulation/qemu-xtensa/Makefile b/board/emulation/qemu-xtensa/Makefile new file mode 100644 index 00000000000..0f33a65f6c6 --- /dev/null +++ b/board/emulation/qemu-xtensa/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2024, Jiaxun Yang + +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 00000000000..0ca83341c25 --- /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 + */ + +#include +#include +#include +#include +#include +#include +#include + +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-dc233c_defconfig b/configs/qemu-xtensa-dc233c_defconfig new file mode 100644 index 00000000000..e6f40b37ed8 --- /dev/null +++ b/configs/qemu-xtensa-dc233c_defconfig @@ -0,0 +1,32 @@ +CONFIG_XTENSA=y +CONFIG_SYS_CPU="dc233c" +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 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/doc/board/emulation/index.rst b/doc/board/emulation/index.rst index d3d6b8f3d86..98a0b26ad24 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 00000000000..fff23c1a9b0 --- /dev/null +++ b/doc/board/emulation/qemu-xtensa.rst @@ -0,0 +1,33 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2024 Jiaxun Yang + +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 dc233c variant is tested against U-Boot. + +Building U-Boot +--------------- +Set the CROSS_COMPILE environment variable as usual, and run: + + make qemu-xtensa-dc233c_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 dc233c -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. diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 1c3c810651e..5c06cd9f60e 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 d4bbf6fa5e0..bc75d9b974e 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 00000000000..fbb561dd612 --- /dev/null +++ b/drivers/cpu/xtensa_cpu.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang + */ + +#include +#include +#include +#include +#include +#include + +#include + +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, +}; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1fe4607598e..3a1e5a6f287 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 dbe598b7406..78810f98367 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 00000000000..0e59a9bfdc7 --- /dev/null +++ b/drivers/serial/serial_xtensa_semihosting.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Jiaxun Yang + */ + +#include +#include +#include + +#include + +/** + * 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 + +static inline void _debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int c) +{ + simc_serial_putc(NULL, c); +} + +DEBUG_UART_FUNCS +#endif diff --git a/dts/upstream/src/xtensa/Makefile b/dts/upstream/src/xtensa/Makefile new file mode 100644 index 00000000000..2a81acb32bc --- /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 diff --git a/include/configs/qemu-xtensa.h b/include/configs/qemu-xtensa.h new file mode 100644 index 00000000000..505aa0646bc --- /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 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include +#include +#include + +#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 */