From ed332e4aa91b2e60ff9175222423f0c8e72eff1f Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Sun, 1 Mar 2026 13:11:32 +0800 Subject: [PATCH] [bsp][qemu-virt64-aarch64] support full dm Signed-off-by: GuEe-GUI <2991707448@qq.com> --- bsp/qemu-virt64-aarch64/.config | 186 +++-- bsp/qemu-virt64-aarch64/.gitignore | 2 + bsp/qemu-virt64-aarch64/Kconfig | 13 +- bsp/qemu-virt64-aarch64/amp.dts | 111 +++ bsp/qemu-virt64-aarch64/amp.dtsi | 108 +++ .../applications/SConscript | 6 + bsp/qemu-virt64-aarch64/applications/amp.c | 277 +++++++ bsp/qemu-virt64-aarch64/applications/camera.c | 207 +++++ .../applications/console.c | 33 - .../applications/graphic.c | 224 ------ bsp/qemu-virt64-aarch64/applications/mnt.c | 41 - bsp/qemu-virt64-aarch64/applications/pin.c | 33 - bsp/qemu-virt64-aarch64/drivers/Kconfig | 91 +-- bsp/qemu-virt64-aarch64/drivers/SConscript | 8 +- bsp/qemu-virt64-aarch64/drivers/board.c | 6 - bsp/qemu-virt64-aarch64/drivers/board.h | 9 +- bsp/qemu-virt64-aarch64/drivers/drv_camera.c | 280 +++++++ bsp/qemu-virt64-aarch64/drivers/drv_camera.h | 21 + bsp/qemu-virt64-aarch64/drivers/drv_gpio.c | 318 -------- bsp/qemu-virt64-aarch64/drivers/drv_gpio.h | 16 - bsp/qemu-virt64-aarch64/drivers/drv_romfb.c | 17 + bsp/qemu-virt64-aarch64/drivers/drv_rtc.c | 126 ---- bsp/qemu-virt64-aarch64/drivers/drv_rtc.h | 25 - bsp/qemu-virt64-aarch64/drivers/drv_uart.c | 146 ---- bsp/qemu-virt64-aarch64/drivers/drv_uart.h | 16 - bsp/qemu-virt64-aarch64/drivers/drv_virtio.c | 93 --- bsp/qemu-virt64-aarch64/drivers/drv_virtio.h | 16 - bsp/qemu-virt64-aarch64/drivers/virt.h | 96 --- bsp/qemu-virt64-aarch64/qemu-debug.bat | 9 - bsp/qemu-virt64-aarch64/qemu-debug.sh | 8 - bsp/qemu-virt64-aarch64/qemu-device-camera.c | 709 ++++++++++++++++++ bsp/qemu-virt64-aarch64/qemu-graphic.bat | 13 - bsp/qemu-virt64-aarch64/qemu-graphic.sh | 12 - bsp/qemu-virt64-aarch64/qemu.bat | 9 - bsp/qemu-virt64-aarch64/qemu.py | 380 ++++++++++ bsp/qemu-virt64-aarch64/qemu.sh | 8 - bsp/qemu-virt64-aarch64/rtconfig.h | 123 ++- components/drivers/rpmsg/Kconfig | 6 + components/drivers/rpmsg/SConscript | 3 + .../drivers/rpmsg/rpmsg-rt-thread-virtio.c | 565 ++++++++++++++ 40 files changed, 2926 insertions(+), 1444 deletions(-) create mode 100755 bsp/qemu-virt64-aarch64/.gitignore create mode 100755 bsp/qemu-virt64-aarch64/amp.dts create mode 100755 bsp/qemu-virt64-aarch64/amp.dtsi create mode 100755 bsp/qemu-virt64-aarch64/applications/amp.c create mode 100755 bsp/qemu-virt64-aarch64/applications/camera.c delete mode 100644 bsp/qemu-virt64-aarch64/applications/console.c delete mode 100644 bsp/qemu-virt64-aarch64/applications/graphic.c delete mode 100644 bsp/qemu-virt64-aarch64/applications/mnt.c delete mode 100644 bsp/qemu-virt64-aarch64/applications/pin.c mode change 100644 => 100755 bsp/qemu-virt64-aarch64/drivers/Kconfig mode change 100644 => 100755 bsp/qemu-virt64-aarch64/drivers/SConscript create mode 100755 bsp/qemu-virt64-aarch64/drivers/drv_camera.c create mode 100755 bsp/qemu-virt64-aarch64/drivers/drv_camera.h delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_gpio.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_gpio.h create mode 100755 bsp/qemu-virt64-aarch64/drivers/drv_romfb.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_rtc.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_rtc.h delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_uart.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_uart.h delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_virtio.c delete mode 100644 bsp/qemu-virt64-aarch64/drivers/drv_virtio.h delete mode 100644 bsp/qemu-virt64-aarch64/drivers/virt.h delete mode 100644 bsp/qemu-virt64-aarch64/qemu-debug.bat delete mode 100644 bsp/qemu-virt64-aarch64/qemu-debug.sh create mode 100755 bsp/qemu-virt64-aarch64/qemu-device-camera.c delete mode 100644 bsp/qemu-virt64-aarch64/qemu-graphic.bat delete mode 100644 bsp/qemu-virt64-aarch64/qemu-graphic.sh delete mode 100644 bsp/qemu-virt64-aarch64/qemu.bat create mode 100755 bsp/qemu-virt64-aarch64/qemu.py delete mode 100755 bsp/qemu-virt64-aarch64/qemu.sh create mode 100644 components/drivers/rpmsg/rpmsg-rt-thread-virtio.c diff --git a/bsp/qemu-virt64-aarch64/.config b/bsp/qemu-virt64-aarch64/.config index 696b5c11ab..9aa0a43b0c 100644 --- a/bsp/qemu-virt64-aarch64/.config +++ b/bsp/qemu-virt64-aarch64/.config @@ -11,18 +11,8 @@ # rt_vsnprintf options # # CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y -CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y -# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set -CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32 -CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6 -CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9 -CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 +# CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG is not set +# CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD is not set # end of rt_vsnprintf options # @@ -292,7 +282,7 @@ CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000 # end of elm-chan's FatFs, Generic FAT Filesystem Module CONFIG_RT_USING_DFS_DEVFS=y -# CONFIG_RT_USING_DFS_9PFS is not set +CONFIG_RT_USING_DFS_9PFS=y # CONFIG_RT_USING_DFS_ISO9660 is not set CONFIG_RT_USING_DFS_ROMFS=y # CONFIG_RT_USING_DFS_ROMFS_USER_ROOT is not set @@ -321,11 +311,14 @@ CONFIG_RT_SERIAL_USING_DMA=y CONFIG_RT_SERIAL_RB_BUFSZ=256 # CONFIG_RT_USING_SERIAL_BYPASS is not set # CONFIG_RT_SERIAL_EARLY_HVC is not set -# CONFIG_RT_SERIAL_PL011 is not set -# CONFIG_RT_SERIAL_8250 is not set +CONFIG_RT_SERIAL_PL011=y +CONFIG_RT_SERIAL_8250=y +# CONFIG_RT_SERIAL_8250_DW is not set +CONFIG_RT_SERIAL_8250_PCI=y +# CONFIG_RT_SERIAL_VIRTUAL is not set # CONFIG_RT_USING_CAN is not set CONFIG_RT_USING_CLOCK_TIME=y -# CONFIG_RT_CLOCK_TIME_ARM_ARCH is not set +CONFIG_RT_CLOCK_TIME_ARM_ARCH=y # CONFIG_RT_USING_I2C is not set # CONFIG_RT_USING_PHY is not set # CONFIG_RT_USING_PHY_V2 is not set @@ -337,38 +330,94 @@ CONFIG_RT_USING_RANDOM=y # CONFIG_RT_USING_PWM is not set # CONFIG_RT_USING_PULSE_ENCODER is not set # CONFIG_RT_USING_INPUT_CAPTURE is not set -# CONFIG_RT_USING_MTD_NOR is not set +CONFIG_RT_USING_MTD_NOR=y +CONFIG_RT_USING_MTD_NOR_CFI=y # CONFIG_RT_USING_MTD_NAND is not set -CONFIG_RT_USING_PM=y -CONFIG_PM_TICKLESS_THRESHOLD_TIME=2 -# CONFIG_PM_USING_CUSTOM_CONFIG is not set -# CONFIG_PM_ENABLE_DEBUG is not set -# CONFIG_PM_ENABLE_SUSPEND_SLEEP_MODE is not set -# CONFIG_PM_ENABLE_THRESHOLD_SLEEP_MODE is not set +# CONFIG_RT_USING_PM is not set CONFIG_RT_USING_RTC=y -# CONFIG_RT_USING_ALARM is not set -CONFIG_RT_USING_SOFT_RTC=y +CONFIG_RT_USING_ALARM=y +CONFIG_RT_ALARM_STACK_SIZE=8192 +CONFIG_RT_ALARM_TIMESLICE=5 +CONFIG_RT_ALARM_PRIORITY=10 +# CONFIG_RT_ALARM_USING_LOCAL_TIME is not set +# CONFIG_RT_USING_SOFT_RTC is not set # CONFIG_RT_RTC_GOLDFISH is not set -# CONFIG_RT_RTC_PL031 is not set +CONFIG_RT_RTC_PL031=y # CONFIG_RT_USING_SDIO is not set # CONFIG_RT_USING_SPI is not set -# CONFIG_RT_USING_WDT is not set +CONFIG_RT_USING_WDT=y +CONFIG_RT_WDT_I6300ESB=y # CONFIG_RT_USING_AUDIO is not set # CONFIG_RT_USING_SENSOR is not set # CONFIG_RT_USING_TOUCH is not set -# CONFIG_RT_USING_GRAPHIC is not set -# CONFIG_RT_USING_HWCRYPTO is not set +CONFIG_RT_USING_LCD=y +CONFIG_RT_USING_GRAPHIC=y +# CONFIG_RT_GRAPHIC_BACKLIGHT is not set +CONFIG_RT_GRAPHIC_FB=y +# CONFIG_RT_GRAPHIC_FB_SIMPLE is not set +CONFIG_RT_GRAPHIC_LOGO=y +# CONFIG_RT_GRAPHIC_LOGO_NONE is not set +CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_CLUT224=y +# CONFIG_RT_GRAPHIC_LOGO_RT_THREAD_WHITE_CLUT224 is not set +CONFIG_RT_USING_HWCRYPTO=y +CONFIG_RT_HWCRYPTO_DEFAULT_NAME="hwcryto" +CONFIG_RT_HWCRYPTO_IV_MAX_SIZE=16 +CONFIG_RT_HWCRYPTO_KEYBIT_MAX_SIZE=256 +# CONFIG_RT_HWCRYPTO_USING_GCM is not set +CONFIG_RT_HWCRYPTO_USING_AES=y +CONFIG_RT_HWCRYPTO_USING_AES_ECB=y +CONFIG_RT_HWCRYPTO_USING_AES_CBC=y +# CONFIG_RT_HWCRYPTO_USING_AES_CFB is not set +CONFIG_RT_HWCRYPTO_USING_AES_CTR=y +# CONFIG_RT_HWCRYPTO_USING_AES_OFB is not set +CONFIG_RT_HWCRYPTO_USING_DES=y +CONFIG_RT_HWCRYPTO_USING_DES_ECB=y +CONFIG_RT_HWCRYPTO_USING_DES_CBC=y +CONFIG_RT_HWCRYPTO_USING_3DES=y +CONFIG_RT_HWCRYPTO_USING_3DES_ECB=y +CONFIG_RT_HWCRYPTO_USING_3DES_CBC=y +CONFIG_RT_HWCRYPTO_USING_RC4=y +# CONFIG_RT_HWCRYPTO_USING_MD5 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA1 is not set +# CONFIG_RT_HWCRYPTO_USING_SHA2 is not set +CONFIG_RT_HWCRYPTO_USING_RNG=y +# CONFIG_RT_HWCRYPTO_USING_CRC is not set +# CONFIG_RT_HWCRYPTO_USING_BIGNUM is not set # CONFIG_RT_USING_WIFI is not set # CONFIG_RT_USING_LED is not set -# CONFIG_RT_USING_INPUT is not set +CONFIG_RT_USING_INPUT=y +CONFIG_RT_INPUT_POWER=y +# CONFIG_RT_INPUT_UAPI is not set +# CONFIG_RT_INPUT_JOYSTICK is not set +CONFIG_RT_INPUT_KEYBOARD=y +CONFIG_RT_INPUT_KEYBOARD_GPIO=y +# CONFIG_RT_INPUT_MISC is not set +# CONFIG_RT_INPUT_TOUCHSCREEN is not set # CONFIG_RT_USING_MBOX is not set # CONFIG_RT_USING_HWSPINLOCK is not set # CONFIG_RT_USING_PHYE is not set -# CONFIG_RT_USING_BLK is not set -# CONFIG_RT_USING_SCSI is not set -# CONFIG_RT_USING_FIRMWARE is not set +CONFIG_RT_USING_ATA=y +CONFIG_RT_ATA_AHCI=y +CONFIG_RT_ATA_AHCI_PCI=y +# CONFIG_RT_USING_NVME is not set +CONFIG_RT_USING_BLK=y + +# +# Partition Types +# +CONFIG_RT_BLK_PARTITION_DFS=y +CONFIG_RT_BLK_PARTITION_EFI=y +# end of Partition Types + +CONFIG_RT_USING_SCSI=y +CONFIG_RT_SCSI_SD=y +CONFIG_RT_SCSI_CDROM=y +CONFIG_RT_USING_FIRMWARE=y +CONFIG_RT_FIRMWARE_QEMU_FW_CFG=y +# CONFIG_RT_FIRMWARE_ARM_SCMI is not set # CONFIG_RT_USING_HWCACHE is not set -# CONFIG_RT_USING_REGULATOR is not set +CONFIG_RT_USING_REGULATOR=y +# CONFIG_RT_REGULATOR_GPIO is not set # CONFIG_RT_USING_RESET is not set # @@ -380,24 +429,50 @@ CONFIG_RT_USING_SOFT_RTC=y # CONFIG_RT_USING_POWER_SUPPLY is not set # CONFIG_RT_USING_THERMAL is not set CONFIG_RT_USING_VIRTIO=y -CONFIG_RT_USING_VIRTIO10=y -CONFIG_RT_USING_VIRTIO_MMIO_ALIGN=y -CONFIG_RT_USING_VIRTIO_BLK=y -# CONFIG_RT_USING_VIRTIO_NET is not set -CONFIG_RT_USING_VIRTIO_CONSOLE=y -CONFIG_RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR=4 -CONFIG_RT_USING_VIRTIO_GPU=y -CONFIG_RT_USING_VIRTIO_INPUT=y +CONFIG_RT_VIRTIO_TRANSPORT_MMIO=y +CONFIG_RT_VIRTIO_TRANSPORT_PCI=y +CONFIG_RT_VIRTIO_BLK=y +CONFIG_RT_VIRTIO_CONSOLE=y +CONFIG_RT_VIRTIO_RNG=y +CONFIG_RT_VIRTIO_SCSI=y +# CONFIG_RT_VIRTIO_9P is not set +CONFIG_RT_VIRTIO_RPROC_SERIAL=y +CONFIG_RT_VIRTIO_GPU=y +CONFIG_RT_VIRTIO_CRYPTO=y # CONFIG_RT_USING_NVMEM is not set -# CONFIG_RT_USING_DMA is not set -# CONFIG_RT_USING_MFD is not set +CONFIG_RT_USING_DMA=y +CONFIG_RT_USING_MFD=y +CONFIG_RT_MFD_EDU=y +CONFIG_RT_MFD_SYSCON=y CONFIG_RT_USING_OFW=y # CONFIG_RT_USING_BUILTIN_FDT is not set CONFIG_RT_FDT_EARLYCON_MSG_SIZE=128 CONFIG_RT_USING_OFW_BUS_RANGES_NUMBER=8 -# CONFIG_RT_USING_PIC is not set +CONFIG_RT_USING_PCI=y +CONFIG_RT_PCI_MSI=y +# CONFIG_RT_PCI_ENDPOINT is not set +CONFIG_RT_PCI_SYS_64BIT=y +CONFIG_RT_PCI_CACHE_LINE_SIZE=8 +# CONFIG_RT_PCI_LOCKLESS is not set + +# +# PCI Device Drivers +# +CONFIG_RT_PCI_ECAM=y +CONFIG_RT_PCI_HOST_COMMON=y +CONFIG_RT_PCI_HOST_GENERIC=y +# CONFIG_RT_PCI_DW is not set +CONFIG_RT_USING_PIC=y +# CONFIG_RT_USING_PIC_STATISTICS is not set +CONFIG_MAX_HANDLERS=512 +CONFIG_RT_PIC_ARM_GIC=y +CONFIG_RT_PIC_ARM_GIC_V2M=y +CONFIG_RT_PIC_ARM_GIC_V3=y +CONFIG_RT_PIC_ARM_GIC_V3_ITS=y +CONFIG_RT_PIC_ARM_GIC_V3_ITS_IRQ_MAX=127 +CONFIG_RT_PIC_ARM_GIC_MAX_NR=1 CONFIG_RT_USING_PIN=y -# CONFIG_RT_PIN_PL061 is not set +CONFIG_RT_PIN_PL061=y # CONFIG_RT_USING_PINCTRL is not set CONFIG_RT_USING_CLK=y # CONFIG_RT_USING_CHERRYUSB is not set @@ -1593,22 +1668,3 @@ CONFIG_RT_INIT_MEMORY_REGIONS=128 # end of RT-Thread online packages CONFIG_SOC_VIRT64_AARCH64=y - -# -# AARCH64 qemu virt64 configs -# -CONFIG_BSP_SUPPORT_FPU=y -CONFIG_BSP_USING_UART=y -CONFIG_RT_USING_UART0=y -CONFIG_BSP_USING_RTC=y -# CONFIG_BSP_USING_ALARM is not set -CONFIG_BSP_USING_PIN=y -CONFIG_BSP_USING_VIRTIO_BLK=y -# CONFIG_BSP_USING_VIRTIO_NET is not set -CONFIG_BSP_USING_VIRTIO_CONSOLE=y -CONFIG_BSP_USING_VIRTIO_GPU=y -CONFIG_BSP_USING_VIRTIO_INPUT=y -CONFIG_BSP_USING_GIC=y -CONFIG_BSP_USING_GICV2=y -# CONFIG_BSP_USING_GICV3 is not set -# end of AARCH64 qemu virt64 configs diff --git a/bsp/qemu-virt64-aarch64/.gitignore b/bsp/qemu-virt64-aarch64/.gitignore new file mode 100755 index 0000000000..eb6cf13dde --- /dev/null +++ b/bsp/qemu-virt64-aarch64/.gitignore @@ -0,0 +1,2 @@ +*.qcow2 +*.dtb diff --git a/bsp/qemu-virt64-aarch64/Kconfig b/bsp/qemu-virt64-aarch64/Kconfig index 9a2d65614e..54597eb49e 100644 --- a/bsp/qemu-virt64-aarch64/Kconfig +++ b/bsp/qemu-virt64-aarch64/Kconfig @@ -6,20 +6,17 @@ RTT_DIR := ../../ PKGS_DIR := packages +SOC_DM_SOC_DIR := $(BSP_DIR)/drivers + source "$(RTT_DIR)/Kconfig" osource "$PKGS_DIR/Kconfig" config SOC_VIRT64_AARCH64 bool select ARCH_ARMV8 - select ARCH_CPU_64BIT - select ARCH_ARM_MMU - select RT_USING_CACHE select RT_USING_COMPONENTS_INIT select RT_USING_USER_MAIN - select RT_USING_GIC - select BSP_USING_GIC - select ARCH_MM_MMU + select ARCH_CPU_64BIT + select RT_USING_CACHE + select RT_USING_STDC_ATOMIC default y - -source "$(BSP_DIR)/drivers/Kconfig" diff --git a/bsp/qemu-virt64-aarch64/amp.dts b/bsp/qemu-virt64-aarch64/amp.dts new file mode 100755 index 0000000000..d01c5f81a2 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/amp.dts @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +/dts-v1/; +#define AMP_SLAVE +#include "amp.dtsi" +#include "amp.dt.h" + +/delete-node/ &_memory; + +&pic_mailbox1 { + interrupt-affinity = <&cpu0>; +}; + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "linux,dummy-virt"; + interrupt-parent = <&gic>; + + chosen { + bootargs = "rpmsg.mode=slave console=ttyAMA0 cma=8M coherent_pool=2M root=vda0 rootfstype=elm rw"; + stdout-path = "/pl011@9040000"; + }; + + memory { + reg = <0x0 (MEMORY_BASE + AMP_MEMORY_BASE) 0x0 AMP_MEMORY_SIZE>; + device_type = "memory"; + }; + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu0: cpu@CPU_ID { + compatible = ""; /* To be filled */ + reg = ; + device_type = "cpu"; + }; + }; + + timer { + compatible = "arm,armv8-timer","arm,armv7-timer"; + always-on; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@8000000 { + #if GIC_VERSION != 2 + compatible = "arm,gic-v3"; + reg = <0x0 0x8000000 0x0 0x010000>, /* GICD */ + <0x0 0x80a0000 0x0 0xf60000>; /* GICR */ + #redistributor-regions = <0x01>; + #else + compatible = "arm,cortex-a15-gic"; + reg = <0x0 0x8000000 0x0 0x010000>, /* GICD */ + <0x0 0x8010000 0x0 0x010000>; /* GICC */ + #endif + skip-init; + interrupt-controller; + #interrupt-cells = <3>; + }; + + clk24m: apb-pclk { + clock-output-names = "clk24mhz"; + clock-frequency = <24000000>; + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + pl011@9040000 { + clock-names = "uartclk", "apb_pclk"; + clocks = <&clk24m &clk24m>; + interrupts = ; + interrupt-affinity = <&cpu0>; + reg = <0x00 0x9040000 0x00 0x1000>; + compatible = "arm,pl011", "arm,primecell"; + }; + + virtio_blk { + compatible = "virtio,mmio"; + reg = <0 0 0 0>; /* To be filled */ + interrupts = ; /* To be filled */ + interrupt-affinity = <&cpu0>; + dma-coherent; + status = "disabled"; + }; + + /delete-node/ soc; + + amp_soc { + compatible = "simple-bus"; + /delete-property/ memory-region; + /delete-property/ dtb-entry; + /delete-property/ kernel-entry; + + virtio_rpmsg { + interrupt-affinity = <&cpu0>; + }; + }; +}; diff --git a/bsp/qemu-virt64-aarch64/amp.dtsi b/bsp/qemu-virt64-aarch64/amp.dtsi new file mode 100755 index 0000000000..2491d1b8a3 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/amp.dtsi @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#define MEMORY_BASE 0x48000000 +#define MEMORY_SIZE (130 * SIZE_MB) + +#define AMP_MEMORY_BASE 0x200000 +#define AMP_MEMORY_SIZE (128 * SIZE_MB) + +/* + * RUN COMMAND: ./qemu.py -dtbo amp.dtsi -mem 258 + * REMOTE: telnet localhost 4323 + */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 MEMORY_BASE 0x0 MEMORY_SIZE>; + + pic_mailbox@1ffe00 { + reg = <0x0 0x1ffe00 0x0 0x200>; + }; + + virtio_sram: virtio_sram@0 { + reg = <0x0 0x0 0x0 0x1ffe00>; + }; + + amp_memory: amp_memory@200000 { + reg = <0x0 AMP_MEMORY_BASE 0x0 AMP_MEMORY_SIZE>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 MEMORY_BASE 0x0 MEMORY_SIZE>; + + pic_mailbox0: pic_mailbox@1ffe00 { + compatible = "rt-thread,pic-mailbox"; + reg = <0x0 0x1ffe00 0x0 0x200>; + position = <0>; + interrupts = ; + peer-interrupts = <(32 + 10)>; + uid = <0>; + #mbox-cells = <1>; + }; + + virtio_rpmsg { + compatible = "rt-thread,virtio-rpmsg"; + shmem = <&virtio_sram>; + mboxes = <&pic_mailbox0 0>; + queue-max = <64>; + master; + }; + }; + +#ifndef AMP_SLAVE + /delete-node/ pl011@9040000; + + aliases { + /delete-property/ serial1; + }; +#endif + + amp_soc { + /* DO NOT set a 'compatible' property on this node */ + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 MEMORY_BASE 0x0 MEMORY_SIZE>; + memory-region = <&_memory>; + dtb-entry = <0x48200000>; + kernel-entry = <0x48480000>; + + pic_mailbox1: pic_mailbox@1ffe00 { + compatible = "rt-thread,pic-mailbox"; + reg = <0x0 0x1ffe00 0x0 0x200>; + position = <1>; + interrupts = ; + peer-interrupts = <(32 + 9)>; + uid = <1>; + #mbox-cells = <1>; + }; + + virtio_rpmsg { + compatible = "rt-thread,virtio-rpmsg"; + shmem = <&virtio_sram>; + mboxes = <&pic_mailbox1 0>; + queue-max = <64>; + slave; + }; + }; +}; diff --git a/bsp/qemu-virt64-aarch64/applications/SConscript b/bsp/qemu-virt64-aarch64/applications/SConscript index c583d3016e..19c43aa9bf 100644 --- a/bsp/qemu-virt64-aarch64/applications/SConscript +++ b/bsp/qemu-virt64-aarch64/applications/SConscript @@ -4,6 +4,12 @@ cwd = GetCurrentDir() src = Glob('*.c') + Glob('*.cpp') CPPPATH = [cwd] +if not GetDepend(['RT_RPMSG_RT_THREAD_VIRTIO']): + SrcRemove(src, ['amp.c']) + +if not GetDepend(['RT_SOC_CAMERA']): + SrcRemove(src, ['camera.c']) + group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/qemu-virt64-aarch64/applications/amp.c b/bsp/qemu-virt64-aarch64/applications/amp.c new file mode 100755 index 0000000000..e9b35971e3 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/applications/amp.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef RT_USING_RPMSG +static int rpmsg_write(int argc, char**argv) +{ + struct rt_device *dev; + + if (argc != 3 || !(dev = rt_device_find(argv[1]))) + { + rt_kprintf("Usage: %s \n", __func__); + return -1; + } + + if (!rt_device_open(dev, 0)) + { + rt_device_write(dev, 0, argv[2], rt_strlen(argv[2]) + 1); + rt_device_close(dev); + } + else + { + rt_kprintf("Open %s fail", argv[1]); + return -1; + } + + return 0; +} +MSH_CMD_EXPORT(rpmsg_write, rpmsg write msg to device); + +static int rpmsg_read(int argc, char**argv) +{ + struct rt_device *dev; + + if (argc != 2 || !(dev = rt_device_find(argv[1]))) + { + rt_kprintf("Usage: %s \n", __func__); + return -1; + } + + if (!rt_device_open(dev, 0)) + { + char msg[32]; + rt_ssize_t len; + + while ((len = rt_device_read(dev, 0, msg, sizeof(msg) - 1)) > 0) + { + msg[len] = '\0'; + rt_kputs(msg); + } + rt_kputs("\n"); + + rt_device_close(dev); + } + else + { + rt_kprintf("Open %s fail", argv[1]); + return -1; + } + + return 0; +} +MSH_CMD_EXPORT(rpmsg_read, rpmsg read all msg from device); + +static int rpmsg_startup(void) +{ + struct rt_rpmsg_endpoint_info info; + struct rt_device *dev = rt_device_find("rpmsg_char0"); + + if (dev && !rt_device_open(dev, 0)) + { + rt_strcpy(info.name, "rpmsg-char"); + info.src = 114; + info.dst = 514; + if (rt_rpmsg_mode() == RT_RPMSG_MODE_SLAVE) + { + info.src ^= info.dst; + info.dst ^= info.src; + info.src ^= info.dst; + } + rt_device_control(dev, RT_DEVICE_CTRL_RPMSG_CREATE_EPT, &info); + + rt_device_close(dev); + } + + return 0; +} +INIT_APP_EXPORT(rpmsg_startup); +#endif /* RT_USING_RPMSG */ + +struct compare +{ + struct rt_device *udev; + struct rt_device *vdev; +}; + +static int virtio_device_compare(rt_device_t dev, void *data) +{ + struct compare *cmp = data; + + if (dev->user_data == (cmp->udev->user_data ? : cmp->udev)) + { + cmp->vdev = dev; + + return RT_EOK; + } + + return -RT_EEMPTY; +} + +static void join_virtio(void *amp_dtb, struct rt_bus *virtio_bus, + const char *dev_name, const char *path) +{ + int dev_offset; + rt_ssize_t len; + const void *data; + struct compare cmp; + struct rt_device *dev; + struct rt_ofw_node *np; + + if (!(dev = rt_device_find(dev_name))) + { + return; + } + + cmp.udev = dev; + cmp.vdev = RT_NULL; + + rt_bus_for_each_dev(virtio_bus, &cmp, virtio_device_compare); + + if (!cmp.vdev) + { + return; + } + np = cmp.vdev->ofw_node; + dev_offset = fdt_path_offset(amp_dtb, path); + + data = rt_ofw_prop_read_raw(np, "reg", &len); + fdt_setprop(amp_dtb, dev_offset, "reg", data, len); + + data = rt_ofw_prop_read_raw(np, "interrupts", &len); + fdt_setprop(amp_dtb, dev_offset, "interrupts", data, len); + + fdt_setprop_cstring(amp_dtb, dev_offset, "status", "okay"); + + rt_bus_remove_device(cmp.vdev); +} + +static void join_cpu(void *amp_dtb, struct rt_ofw_node *cpu_np) +{ + int cpu_offset; + const char *string = RT_NULL; + + rt_ofw_prop_read_string(cpu_np, "compatible", &string); + + fdt_open_into(amp_dtb, amp_dtb, fdt_totalsize(amp_dtb) + FDT_PADDING_SIZE); + cpu_offset = fdt_path_offset(amp_dtb, "/cpus/cpu@" RT_STRINGIFY(RT_CPUS_NR)); + fdt_setprop_string(amp_dtb, cpu_offset, "compatible", string); +} + +static rt_bool_t match_cpu_hwid(int cpu, rt_uint64_t hwid) +{ + return cpu == hwid; +} + +static int amp_startup(void) +{ + rt_ubase_t level; + void *amp_kernel, *amp_dtb; + rt_uint32_t dtb_entry, amp_entry; + static rt_bool_t startup = RT_FALSE; + struct rt_bus *virtio_bus; + struct rt_ofw_node *amp_soc, *amp_mem, *amp_cpu; + + if (startup || rt_ofw_bootargs_select("amp_mode", 0)) + { + return -1; + } + + startup = RT_TRUE; + + if (!(amp_soc = rt_ofw_find_node_by_path("/amp_soc"))) + { + rt_kprintf("No AMP SoC node found\n"); + } + + /* Build DTB */ + rt_ofw_prop_read_u32(amp_soc, "dtb-entry", &dtb_entry); + amp_dtb = rt_ioremap_cached((void *)(rt_ubase_t)dtb_entry, ARCH_PAGE_SIZE); + + if (!amp_dtb) + { + return (int)-RT_ENOMEM; + } + + if (!(amp_mem = rt_ofw_parse_phandle(amp_soc, "memory-region", 0))) + { + rt_iounmap(amp_dtb); + return (int)-RT_EINVAL; + } + + virtio_bus = rt_bus_find_by_name("virtio"); + RT_ASSERT(virtio_bus != RT_NULL); + + join_virtio(amp_dtb, virtio_bus, "vdb", "/virtio_blk"); + + /* Ready to start the AMP OS */ + rt_ofw_prop_read_u32(amp_soc, "kernel-entry", &_entry); + + /* + * Add ARM64 load DTB code (MOV , #): + * sf [31]: 0b1 + * opc [30-29]: 0b10 + * code [28-23]: 0b100101 + * hw [22-21]: 0b01 (MOVZ X0, #> 16>, LSL #16) + * imm16 [20-5]: dtb_entry >> 16 + * Rd [4-0]: 0 (x0) + */ + amp_entry -= sizeof(rt_uint32_t); + amp_kernel = rt_ioremap_cached((void *)(rt_ubase_t)amp_entry, ARCH_PAGE_SIZE); + + if (!amp_kernel) + { + rt_iounmap(amp_dtb); + return (int)-RT_ENOMEM; + } + *(rt_uint32_t *)amp_kernel = RT_BIT(31); + *(rt_uint32_t *)amp_kernel |= 0x2 << 29; + *(rt_uint32_t *)amp_kernel |= 0x25 << 23; + *(rt_uint32_t *)amp_kernel |= 0x1 << 21; + *(rt_uint32_t *)amp_kernel |= (dtb_entry >> 16) << 5; + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, amp_kernel, sizeof(rt_uint32_t)); + + rt_iounmap(amp_kernel); + + level = rt_hw_interrupt_disable(); + /* + * This is a hack, rt_cpu_mpidr_table array size is RT_CPUS_NR + 1, + * We can call PSCI_CPU_ON for the last one, + * We just restore it to zero after the PSCI called. + */ + amp_cpu = rt_ofw_get_cpu_node(RT_CPUS_NR, RT_NULL, &match_cpu_hwid); + join_cpu(amp_dtb, amp_cpu); + rt_cpu_mpidr_table[RT_CPUS_NR] = rt_ofw_get_cpu_hwid(amp_cpu, 0); + rt_psci_cpu_on(RT_CPUS_NR, amp_entry); + rt_hw_rmb(); + + rt_cpu_mpidr_table[RT_CPUS_NR] = 0; + rt_hw_wmb(); + + rt_hw_interrupt_enable(level); + + rt_iounmap(amp_dtb); + + return 0; +} +#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH) +MSH_CMD_EXPORT(amp_startup, AMP system startup); +#else +INIT_APP_EXPORT(amp_startup); +#endif diff --git a/bsp/qemu-virt64-aarch64/applications/camera.c b/bsp/qemu-virt64-aarch64/applications/camera.c new file mode 100755 index 0000000000..b1593c461f --- /dev/null +++ b/bsp/qemu-virt64-aarch64/applications/camera.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-07 GuEe-GUI the first version + */ + +#include +#include + +#include + +/* Pixel format conversion - inlined for performance */ +#define DO_CONV_RGB565(r, g, b, dst) \ + do { *((rt_uint16_t*)(dst)) = (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3); } while(0) + +#define DO_CONV_ARGB888(r, g, b, dst) \ + do { *((rt_uint32_t*)(dst)) = (0xFF << 24) | ((r) << 16) | ((g) << 8) | (b); } while(0) + +#define DO_CONV_ABGR888(r, g, b, dst) \ + do { *((rt_uint32_t*)(dst)) = (0xFF << 24) | ((b) << 16) | ((g) << 8) | (r); } while(0) + +/* Blend camera frame into framebuffer at specified position */ +static void blend_camera_to_fb(rt_uint8_t *cam_fb, rt_uint8_t *fb, + int cam_w, int cam_h, + int fb_w, int fb_h, int fb_pitch, + int dst_x, int dst_y, + int pixel_format) +{ + int x, y; + rt_uint8_t *dst, *src_row; + /* Calculate actual draw region (clip to framebuffer bounds) */ + int draw_w = (dst_x + cam_w > fb_w) ? (fb_w - dst_x) : cam_w; + int draw_h = (dst_y + cam_h > fb_h) ? (fb_h - dst_y) : cam_h; + + if (draw_w <= 0 || draw_h <= 0) + { + return; + } + + /* Optimized conversion based on pixel format */ + switch (pixel_format) + { + case RTGRAPHIC_PIXEL_FORMAT_RGB565: + { + rt_uint16_t *dst_pixel; + for (y = 0; y < draw_h; ++y) + { + src_row = cam_fb + y * cam_w * 3; + dst = fb + (dst_y + y) * fb_pitch + dst_x * 2; + dst_pixel = (rt_uint16_t*)dst; + + for (x = 0; x < draw_w; ++x) + { + rt_uint8_t r = src_row[x * 3 + 0]; + rt_uint8_t g = src_row[x * 3 + 1]; + rt_uint8_t b = src_row[x * 3 + 2]; + DO_CONV_RGB565(r, g, b, dst_pixel + x); + } + } + break; + } + + case RTGRAPHIC_PIXEL_FORMAT_ARGB888: + { + rt_uint32_t *dst_pixel; + for (y = 0; y < draw_h; ++y) + { + src_row = cam_fb + y * cam_w * 3; + dst = fb + (dst_y + y) * fb_pitch + dst_x * 4; + dst_pixel = (rt_uint32_t*)dst; + + for (x = 0; x < draw_w; ++x) + { + rt_uint8_t r = src_row[x * 3 + 0]; + rt_uint8_t g = src_row[x * 3 + 1]; + rt_uint8_t b = src_row[x * 3 + 2]; + DO_CONV_ARGB888(r, g, b, dst_pixel + x); + } + } + break; + } + + case RTGRAPHIC_PIXEL_FORMAT_ABGR888: + { + rt_uint32_t *dst_pixel; + for (y = 0; y < draw_h; ++y) + { + src_row = cam_fb + y * cam_w * 3; + dst = fb + (dst_y + y) * fb_pitch + dst_x * 4; + dst_pixel = (rt_uint32_t*)dst; + + for (x = 0; x < draw_w; ++x) + { + rt_uint8_t r = src_row[x * 3 + 0]; + rt_uint8_t g = src_row[x * 3 + 1]; + rt_uint8_t b = src_row[x * 3 + 2]; + DO_CONV_ABGR888(r, g, b, dst_pixel + x); + } + } + break; + } + + default: + /* Fallback: direct copy for RGB888 */ + for (y = 0; y < draw_h; ++y) + { + src_row = cam_fb + y * cam_w * 3; + dst = fb + (dst_y + y) * fb_pitch + dst_x * 3; + rt_memcpy(dst, src_row, draw_w * 3); + } + break; + } +} + +static int camera(int argc, char**argv) +{ + rt_err_t err; + struct rt_device *cdev, *gdev; + struct rt_device_graphic_info info; + int cam_w, cam_h; + void *cam_fb; + int dst_x, dst_y; + + cdev = rt_device_find(argc > 1 ? argv[1] : "camera0"); + if (!cdev) + { + rt_kputs("Camera device not found\n"); + return -1; + } + + gdev = rt_device_find(argc > 2 ? argv[2] : "fb0"); + if (!gdev) + { + rt_kputs("Framebuffer device not found\n"); + return -1; + } + + if ((err = rt_device_open(cdev, 0))) + { + rt_kprintf("Open camera failed: %d\n", err); + return (int)err; + } + + if ((err = rt_device_open(gdev, 0))) + { + rt_kprintf("Open framebuffer failed: %d\n", err); + goto _close_camera; + } + + if ((err = rt_device_control(gdev, RTGRAPHIC_CTRL_GET_INFO, &info))) + { + rt_kprintf("Get framebuffer info failed: %d\n", err); + goto _close_fb; + } + + /* Get camera resolution */ + rt_device_control(cdev, RT_DEVICE_CTRL_CAMERA_GET_WIDTH, &cam_w); + rt_device_control(cdev, RT_DEVICE_CTRL_CAMERA_GET_HEIGHT, &cam_h); + + /* Check pixel format support */ + if (info.pixel_format != RTGRAPHIC_PIXEL_FORMAT_RGB565 && + info.pixel_format != RTGRAPHIC_PIXEL_FORMAT_ARGB888 && + info.pixel_format != RTGRAPHIC_PIXEL_FORMAT_ABGR888 && + info.pixel_format != RTGRAPHIC_PIXEL_FORMAT_RGB888) + { + rt_kprintf("Unsupported pixel format: %d\n", info.pixel_format); + goto _close_fb; + } + + /* Get direct framebuffer access */ + rt_device_control(cdev, RT_DEVICE_CTRL_CAMERA_GET_FRAMEBUFFER, &cam_fb); + + /* Center camera on framebuffer */ + dst_x = (info.width - cam_w) / 2; + dst_y = (info.height - cam_h) / 2; + if (dst_x < 0) dst_x = 0; + if (dst_y < 0) dst_y = 0; + + /* Main loop - read and display frames: ~10 seconds at 30 FPS */ + for (int frame_count = 0; frame_count < 300;) + { + /* Wait for new frame (short timeout for low latency) */ + if (rt_device_read(cdev, 0, RT_NULL, 0) > 0) + { + /* Blend camera into framebuffer */ + blend_camera_to_fb(cam_fb, info.framebuffer, + cam_w, cam_h, + info.width, info.height, info.pitch, + dst_x, dst_y, + info.pixel_format); + ++frame_count; + } + } + +_close_fb: + rt_device_close(gdev); + +_close_camera: + rt_device_close(cdev); + + return err; +} +MSH_CMD_EXPORT(camera, camera show in framebuffer); diff --git a/bsp/qemu-virt64-aarch64/applications/console.c b/bsp/qemu-virt64-aarch64/applications/console.c deleted file mode 100644 index 3f8be48189..0000000000 --- a/bsp/qemu-virt64-aarch64/applications/console.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include - -#include - -static int console_init() -{ - rt_err_t status = RT_EOK; - rt_device_t device = rt_device_find("virtio-console0"); - - if (device != RT_NULL && rt_device_open(device, 0) == RT_EOK) - { - /* Create vport0p1 */ - status = rt_device_control(device, VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE, RT_NULL); - } - - if (device != RT_NULL) - { - rt_device_close(device); - } - - return status; -} -INIT_ENV_EXPORT(console_init); diff --git a/bsp/qemu-virt64-aarch64/applications/graphic.c b/bsp/qemu-virt64-aarch64/applications/graphic.c deleted file mode 100644 index c54132bb73..0000000000 --- a/bsp/qemu-virt64-aarch64/applications/graphic.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include -#include - -#include -#include - -#define GRAPHIC_THREAD_PRIORITY 25 -#define GRAPHIC_THREAD_STACK_SIZE 4096 -#define GRAPHIC_THREAD_TIMESLICE 5 - -static rt_uint32_t cur_min[2]; -static rt_uint32_t cur_max[2]; -static rt_uint32_t cur_range[2]; -static rt_uint32_t cur_points[2]; -static rt_uint32_t cur_last_points[2]; -static rt_bool_t cur_event_sync; -static rt_uint32_t color[2] = { 0xff0000, 0x0000ff }; -static rt_uint8_t cursor[VIRTIO_GPU_CURSOR_IMG_SIZE] rt_align(VIRTIO_PAGE_SIZE); - -void tablet_event_handler(struct virtio_input_event event) -{ - static rt_bool_t cur_btn_down = RT_FALSE; - - if (event.type == EV_ABS) - { - if (event.code == 0) - { - cur_points[0] = (cur_max[0] * (event.value - cur_min[0]) + cur_range[0] / 2) / cur_range[0]; - } - else if (event.code == 1) - { - cur_points[1] = (cur_max[1] * (event.value - cur_min[1]) + cur_range[1] / 2) / cur_range[1]; - } - } - else if (event.type == EV_KEY) - { - if (event.code == BTN_LEFT) - { - if (cur_btn_down && event.value == 0) - { - color[0] ^= color[1]; - color[1] ^= color[0]; - color[0] ^= color[1]; - cur_btn_down = RT_FALSE; - cur_event_sync = RT_TRUE; - } - else - { - cur_btn_down = RT_TRUE; - } - } - } - else if (event.type == EV_SYN) - { - cur_event_sync = RT_TRUE; - } -} - -void graphic_thread(void *param) -{ - int i; - char dev_name[RT_NAME_MAX]; - rt_device_t device = RT_NULL; - - rt_device_t tablet_dev = RT_NULL; - struct virtio_input_config tablet_config; - - rt_uint32_t white = 0xffffff; - rt_device_t gpu_dev = RT_NULL; - struct rt_device_rect_info rect_info; - struct rt_device_graphic_info graphic_info; - struct rt_device_graphic_ops *virtio_gpu_graphic_ops; - - /* GPU */ - device = rt_device_find("virtio-gpu0"); - - if (device != RT_NULL && rt_device_open(device, 0) == RT_EOK) - { - virtio_gpu_graphic_ops = rt_graphix_ops(device); - - rt_memset(&rect_info, 0, sizeof(rect_info)); - rt_memset(&graphic_info, 0, sizeof(graphic_info)); - - rt_device_control(device, VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY, RT_NULL); - rt_device_control(device, VIRTIO_DEVICE_CTRL_GPU_CREATE_2D, (void *)RTGRAPHIC_PIXEL_FORMAT_RGB888); - rt_device_control(device, RTGRAPHIC_CTRL_GET_INFO, &graphic_info); - - rect_info.x = 0; - rect_info.y = 0; - rect_info.width = graphic_info.width; - rect_info.height = graphic_info.height; - - if (graphic_info.framebuffer != RT_NULL) - { - int i = 0; - - rt_memset(graphic_info.framebuffer, 0xff, graphic_info.pitch * graphic_info.height); - - cur_last_points[0] = graphic_info.width / 2; - cur_last_points[1] = graphic_info.height / 2; - - virtio_gpu_graphic_ops->draw_hline((char *)&color[0], 0, graphic_info.width, cur_last_points[1]); - virtio_gpu_graphic_ops->draw_vline((char *)&color[1], cur_last_points[0], 0, graphic_info.height); - - rt_device_control(device, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info); - - while (i < sizeof(cursor) / 4) - { - /* R: 0x4c G: 0xaf B: 0x50 A: 0.8 */ - ((rt_uint32_t *)cursor)[i] = 0xcc4caf50; - ++i; - } - - rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_SETUP, cursor); - rt_device_control(device, VIRTIO_DEVICE_CTRL_CURSOR_MOVE, (rt_uint32_t[]){0, 0}); - - gpu_dev = device; - } - } - - /* Keyboard, Mouse, Tablet */ - for (i = 0; i < 3; ++i) - { - rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", i); - - device = rt_device_find(dev_name); - - if (device != RT_NULL && rt_device_open(device, 0) == RT_EOK) - { - enum virtio_input_type type; - rt_device_control(device, VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE, &type); - - if (type == VIRTIO_INPUT_TYPE_TABLET) - { - tablet_dev = device; - } - else - { - rt_device_close(device); - } - } - } - - if (tablet_dev == RT_NULL || gpu_dev == RT_NULL) - { - goto _graphic_fail; - } - - cur_max[0] = graphic_info.width; - cur_max[1] = graphic_info.height; - - rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO, &tablet_config); - - cur_min[0] = tablet_config.abs.min; - cur_range[0] = tablet_config.abs.max - cur_min[0]; - - rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO, &tablet_config); - - cur_min[1] = tablet_config.abs.min; - cur_range[1] = tablet_config.abs.max - cur_min[1]; - - cur_event_sync = RT_FALSE; - - rt_device_control(tablet_dev, VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER, tablet_event_handler); - - for (;;) - { - while (cur_event_sync) - { - virtio_gpu_graphic_ops->draw_hline((char *)&white, 0, graphic_info.width, cur_last_points[1]); - virtio_gpu_graphic_ops->draw_vline((char *)&white, cur_last_points[0], 0, graphic_info.height); - - cur_last_points[0] = cur_points[0]; - cur_last_points[1] = cur_points[1]; - - virtio_gpu_graphic_ops->draw_hline((char *)&color[0], 0, graphic_info.width, cur_last_points[1]); - virtio_gpu_graphic_ops->draw_vline((char *)&color[1], cur_last_points[0], 0, graphic_info.height); - - rt_device_control(gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info); - - cur_event_sync = RT_FALSE; - - rt_thread_mdelay(1); - } - } - -_graphic_fail: - - if (gpu_dev != RT_NULL) - { - rt_device_close(gpu_dev); - } - - if (tablet_dev != RT_NULL) - { - rt_device_close(tablet_dev); - } -} - -int graphic_test(void) -{ - rt_thread_t graphic_tid = rt_thread_create("graphic work", graphic_thread, RT_NULL, - GRAPHIC_THREAD_STACK_SIZE, GRAPHIC_THREAD_PRIORITY, GRAPHIC_THREAD_TIMESLICE); - - if (graphic_tid != RT_NULL) - { - rt_thread_startup(graphic_tid); - - return RT_EOK; - } - - return -RT_ERROR; -} -MSH_CMD_EXPORT(graphic_test, Graphic test); diff --git a/bsp/qemu-virt64-aarch64/applications/mnt.c b/bsp/qemu-virt64-aarch64/applications/mnt.c deleted file mode 100644 index 262c19c4f7..0000000000 --- a/bsp/qemu-virt64-aarch64/applications/mnt.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021/08/19 bernard the first version - */ - -#include - -#ifdef RT_USING_DFS -#include - -int mnt_init(void) -{ - if (rt_device_find("virtio-blk0")) - { - /* mount virtio-blk as root directory */ - if (dfs_mount("virtio-blk0", "/", "elm", 0, RT_NULL) == 0) - { - rt_kprintf("file system initialization done!\n"); - } - else - { - if (dfs_mount("virtio-blk0", "/", "ext", 0, RT_NULL) == 0) - { - rt_kprintf("file system initialization done!\n"); - } - else - { - rt_kprintf("file system initialization fail!\n"); - } - } - } - - return 0; -} -INIT_ENV_EXPORT(mnt_init); -#endif diff --git a/bsp/qemu-virt64-aarch64/applications/pin.c b/bsp/qemu-virt64-aarch64/applications/pin.c deleted file mode 100644 index 37d1927b00..0000000000 --- a/bsp/qemu-virt64-aarch64/applications/pin.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-6-30 GuEe-GUI first version - */ - -#include -#include -#include - -#ifdef RT_USING_PIN - -void qemu_gpio3_key_poweroff(void *args) -{ - rt_kprintf("\nYou power off the machine.\n"); - - rt_hw_cpu_shutdown(); -} - -static int pin_init() -{ - rt_pin_attach_irq(3, PIN_IRQ_MODE_FALLING, qemu_gpio3_key_poweroff, RT_NULL); - rt_pin_irq_enable(3, RT_TRUE); - - return 0; -} -INIT_ENV_EXPORT(pin_init); - -#endif /* RT_USING_PIN */ diff --git a/bsp/qemu-virt64-aarch64/drivers/Kconfig b/bsp/qemu-virt64-aarch64/drivers/Kconfig old mode 100644 new mode 100755 index f14fc73fc1..d42783b16c --- a/bsp/qemu-virt64-aarch64/drivers/Kconfig +++ b/bsp/qemu-virt64-aarch64/drivers/Kconfig @@ -1,80 +1,15 @@ +config RT_GRAPHIC_ROMFB_WIDTH + int "ROM FB width" + depends on RT_GRAPHIC_FB + default 800 -menu "AARCH64 qemu virt64 configs" - menuconfig BSP_SUPPORT_FPU - bool "Using Float" - default y +config RT_GRAPHIC_ROMFB_HEIGHT + int "ROM FB height" + depends on RT_GRAPHIC_FB + default 600 - menuconfig BSP_USING_UART - bool "Using UART" - select RT_USING_SERIAL - default y - - if BSP_USING_UART - config RT_USING_UART0 - bool "Enabel UART 0" - default y - endif - - menuconfig BSP_USING_RTC - bool "Using RTC" - select RT_USING_RTC - default y - - if BSP_USING_RTC - config BSP_USING_ALARM - bool "Enable Alarm" - select RT_USING_ALARM - default n - endif - - config BSP_USING_PIN - bool "Using PIN" - select RT_USING_PIN - default y - - config BSP_USING_VIRTIO_BLK - bool "Using VirtIO BLK" - select RT_USING_VIRTIO - select RT_USING_VIRTIO_BLK - default y - - config BSP_USING_VIRTIO_NET - bool "Using VirtIO NET" - select RT_USING_VIRTIO - select RT_USING_VIRTIO_NET - default y - - config BSP_USING_VIRTIO_CONSOLE - bool "Using VirtIO Console" - select RT_USING_VIRTIO - select RT_USING_VIRTIO_CONSOLE - default y - - config BSP_USING_VIRTIO_GPU - bool "Using VirtIO GPU" - select RT_USING_VIRTIO - select RT_USING_VIRTIO_GPU - default y - - config BSP_USING_VIRTIO_INPUT - bool "Using VirtIO Input" - select RT_USING_VIRTIO - select RT_USING_VIRTIO_INPUT - default y - - config BSP_USING_GIC - bool - default y - - choice - prompt "GIC Version" - default BSP_USING_GICV2 - - config BSP_USING_GICV2 - bool "GICv2" - - config BSP_USING_GICV3 - bool "GICv3" - endchoice - -endmenu +config RT_SOC_CAMERA + bool "Camera" + depends on RT_GRAPHIC_FB + depends on RT_USING_PCI + default y \ No newline at end of file diff --git a/bsp/qemu-virt64-aarch64/drivers/SConscript b/bsp/qemu-virt64-aarch64/drivers/SConscript old mode 100644 new mode 100755 index 56a5855113..13f67c1e68 --- a/bsp/qemu-virt64-aarch64/drivers/SConscript +++ b/bsp/qemu-virt64-aarch64/drivers/SConscript @@ -3,9 +3,15 @@ from building import * cwd = GetCurrentDir() -src = Glob('*.c') +src = ['board.c'] CPPPATH = [cwd] +if GetDepend(['RT_GRAPHIC_FB']): + src += ['drv_romfb.c'] + +if GetDepend(['RT_SOC_CAMERA']): + src += ['drv_camera.c'] + group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/bsp/qemu-virt64-aarch64/drivers/board.c b/bsp/qemu-virt64-aarch64/drivers/board.c index 3bccfad195..489eb0b99e 100644 --- a/bsp/qemu-virt64-aarch64/drivers/board.c +++ b/bsp/qemu-virt64-aarch64/drivers/board.c @@ -11,14 +11,8 @@ * add smp ipi init */ -#include -#include -#include -#include #include -extern size_t MMUTable[]; - void rt_hw_board_init(void) { rt_hw_common_setup(); diff --git a/bsp/qemu-virt64-aarch64/drivers/board.h b/bsp/qemu-virt64-aarch64/drivers/board.h index e9fc17a283..23148a28a5 100644 --- a/bsp/qemu-virt64-aarch64/drivers/board.h +++ b/bsp/qemu-virt64-aarch64/drivers/board.h @@ -12,16 +12,9 @@ #ifndef __BOARD_H__ #define __BOARD_H__ -#include - extern unsigned char __bss_start; extern unsigned char __bss_end; -#define HEAP_BEGIN (void *)&__bss_end -#define HEAP_END ((void *)HEAP_BEGIN + 64 * 1024 * 1024) - void rt_hw_board_init(void); -int rt_hw_uart_init(void); - -#endif +#endif /* __BOARD_H__ */ diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_camera.c b/bsp/qemu-virt64-aarch64/drivers/drv_camera.c new file mode 100755 index 0000000000..37fd05d804 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/drivers/drv_camera.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-07 GuEe-GUI the first version + */ + +#include +#include + +#define DBG_TAG "vfio.camera" +#define DBG_LVL DBG_INFO +#include + +#include + +#define VFIO_CAMERA_WIDTH_BAR 0 +#define VFIO_CAMERA_HEIGHT_BAR 1 +#define VFIO_CAMERA_FRAMEBUFFER_BAR 2 +#define VFIO_CAMERA_STATUS_BAR 3 + +/* Status register */ +#define BAR3_FRAME_COUNT_OFFSET 0x00 +#define BAR3_FRAME_READY_OFFSET 0x04 + +struct vfio_camera +{ + struct rt_device parent; + void *framebuffer; + void *status_regs; /* BAR3: status registers */ + int width; + int height; + rt_uint32_t last_frame_count; + struct rt_semaphore frame_sem; /* Frame ready notification */ +}; + +static rt_uint32_t vfio_camera_get_frame_count(struct vfio_camera *vc) +{ + return HWREG32(vc->status_regs + BAR3_FRAME_COUNT_OFFSET); +} + +static rt_bool_t vfio_camera_wait_frame(struct vfio_camera *vc, rt_int32_t timeout_ms) +{ + rt_uint32_t current_count; + rt_tick_t start_tick, timeout_tick; + + /* Fast path: check frame count first */ + current_count = vfio_camera_get_frame_count(vc); + if (current_count != vc->last_frame_count) + { + vc->last_frame_count = current_count; + return RT_TRUE; + } + + start_tick = rt_tick_get(); + timeout_tick = rt_tick_from_millisecond(timeout_ms); + + /* Poll with small sleep - allow frame dropping */ + do { + current_count = vfio_camera_get_frame_count(vc); + + if (current_count != vc->last_frame_count) + { + vc->last_frame_count = current_count; + return RT_TRUE; + } + + /* Short sleep to reduce CPU usage */ + rt_thread_mdelay(1); + + /* Check overall timeout */ + if ((rt_tick_get() - start_tick) >= timeout_tick) + { + /* Timeout */ + return RT_FALSE; + } + } while (RT_TRUE); +} + +static rt_ssize_t vfio_camera_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + struct vfio_camera *vc = rt_container_of(dev, struct vfio_camera, parent); + + /* Wait for new frame (up to 30ms - about 1 frame at 30fps) */ + if (!vfio_camera_wait_frame(vc, 30)) + { + return 0; + } + + /* If buffer is NULL, just return success (frame is ready) */ + if (buffer == RT_NULL) + { + return 1; /* Frame ready */ + } + + /* Direct memory access - no memcpy overhead */ + rt_memcpy(buffer, vc->framebuffer + pos, size); + return size; +} + +static rt_err_t vfio_camera_control(rt_device_t dev, int cmd, void *args) +{ + struct vfio_camera *vc = rt_container_of(dev, struct vfio_camera, parent); + + switch (cmd) + { + case RT_DEVICE_CTRL_CAMERA_GET_WIDTH: + if (args) + { + *(int *)args = vc->width; + } + break; + + case RT_DEVICE_CTRL_CAMERA_GET_HEIGHT: + if (args) + { + *(int *)args = vc->height; + } + break; + + case RT_DEVICE_CTRL_CAMERA_GET_FRAMEBUFFER: + if (args) + { + *(void **)args = vc->framebuffer; + } + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops vfio_camera_ops = +{ + .read = vfio_camera_read, + .control = vfio_camera_control, +}; +#endif + +static void vfio_camera_isr(int irqno, void *args) +{ + struct vfio_camera *vc = args; + + /* Frame ready interrupt from backend */ + rt_sem_release(&vc->frame_sem); +} + +static rt_err_t vfio_camera_probe(struct rt_pci_device *pdev) +{ + rt_err_t err; + void *fmt_regs; + const char *dev_name; + struct vfio_camera *vc = rt_calloc(1, sizeof(*vc)); + + if (!vc) + { + LOG_E("Failed to allocate vfio_camera"); + return -RT_ENOMEM; + } + + /* Initialize semaphore for frame notification */ + rt_sem_init(&vc->frame_sem, "cam_frm", 0, RT_IPC_FLAG_PRIO); + + fmt_regs = rt_pci_iomap(pdev, VFIO_CAMERA_WIDTH_BAR); + if (!fmt_regs) + { + LOG_E("Failed to map BAR0 (width)"); + goto _fail; + } + vc->width = HWREG32(fmt_regs); + rt_iounmap(fmt_regs); + + fmt_regs = rt_pci_iomap(pdev, VFIO_CAMERA_HEIGHT_BAR); + if (!fmt_regs) + { + LOG_E("Failed to map BAR1 (height)"); + goto _fail; + } + vc->height = HWREG32(fmt_regs); + rt_iounmap(fmt_regs); + + vc->framebuffer = rt_pci_iomap(pdev, VFIO_CAMERA_FRAMEBUFFER_BAR); + if (!vc->framebuffer) + { + LOG_E("Failed to map BAR2 (framebuffer)"); + goto _fail; + } + + vc->status_regs = rt_pci_iomap(pdev, VFIO_CAMERA_STATUS_BAR); + if (!vc->status_regs) + { + LOG_E("Failed to map BAR3 (status)"); + goto _fail; + } + + /* Initialize frame count */ + vc->last_frame_count = vfio_camera_get_frame_count(vc); + + vc->parent.type = RT_Device_Class_Miscellaneous; +#ifdef RT_USING_DEVICE_OPS + vc->parent.ops = &vfio_camera_ops; +#else + vc->parent.read = vfio_camera_read; + vc->parent.control = vfio_camera_control; +#endif + + rt_dm_dev_set_name_auto(&vc->parent, "camera"); + dev_name = rt_dm_dev_get_name(&vc->parent); + + if ((err = rt_device_register(&vc->parent, dev_name, RT_DEVICE_FLAG_RDONLY))) + { + LOG_E("Failed to register device: %d", err); + goto _fail; + } + + rt_hw_interrupt_install(pdev->irq, vfio_camera_isr, vc, dev_name); + rt_hw_interrupt_umask(pdev->irq); + rt_pci_irq_unmask(pdev); + + pdev->parent.user_data = vc; + + LOG_I("%s %ux%u %s", dev_name, vc->width, vc->height, "RGB24"); + + return RT_EOK; + +_fail: + if (vc->status_regs) + { + rt_iounmap(vc->status_regs); + } + if (vc->framebuffer) + { + rt_iounmap(vc->framebuffer); + } + rt_sem_detach(&vc->frame_sem); + rt_free(vc); + + return err; +} + +static rt_err_t vfio_camera_remove(struct rt_pci_device *pdev) +{ + struct vfio_camera *vc = pdev->parent.user_data; + + /* INTx is shared, don't mask all */ + rt_hw_interrupt_umask(pdev->irq); + rt_pci_irq_mask(pdev); + rt_pci_clear_master(pdev); + + rt_device_unregister(&vc->parent); + + rt_iounmap(vc->status_regs); + rt_iounmap(vc->framebuffer); + rt_sem_detach(&vc->frame_sem); + rt_free(vc); + + return RT_EOK; +} + +static const struct rt_pci_device_id vfio_camera_pci_ids[] = +{ + { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_QEMU, 0x5678), }, + { /* sentinel */ } +}; + +static struct rt_pci_driver vfio_camera_driver = +{ + .name = "vfio-camera", + + .ids = vfio_camera_pci_ids, + .probe = vfio_camera_probe, + .remove = vfio_camera_remove, +}; +RT_PCI_DRIVER_EXPORT(vfio_camera_driver); diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_camera.h b/bsp/qemu-virt64-aarch64/drivers/drv_camera.h new file mode 100755 index 0000000000..a9c03aeb6d --- /dev/null +++ b/bsp/qemu-virt64-aarch64/drivers/drv_camera.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-07 GuEe-GUI the first version + */ + +#ifndef __DRV_CAMERA_H__ +#define __DRV_CAMERA_H__ + +#include +#include + +#define RT_DEVICE_CTRL_CAMERA_GET_WIDTH (RT_DEVICE_CTRL_BASE(Char) + 'V' + 1) +#define RT_DEVICE_CTRL_CAMERA_GET_HEIGHT (RT_DEVICE_CTRL_BASE(Char) + 'V' + 2) +#define RT_DEVICE_CTRL_CAMERA_GET_FRAMEBUFFER (RT_DEVICE_CTRL_BASE(Char) + 'V' + 3) + +#endif /* __DRV_CAMERA_H__ */ diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_gpio.c b/bsp/qemu-virt64-aarch64/drivers/drv_gpio.c deleted file mode 100644 index bcf6677d2c..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_gpio.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-6-30 GuEe-GUI first version - */ - -#include -#include -#include -#include - -#include "drv_gpio.h" - -#ifdef BSP_USING_PIN - -#define GPIODIR 0x400 -#define GPIOIS 0x404 -#define GPIOIBE 0x408 -#define GPIOIEV 0x40c -#define GPIOIE 0x410 -#define GPIORIS 0x414 -#define GPIOMIS 0x418 -#define GPIOIC 0x41c - -#define BIT(x) (1UL << (x)) - -#define PL061_GPIO_NR 8 - -static struct pl061 -{ -#ifdef RT_USING_SMP - struct rt_spinlock spinlock; -#endif - void (*(hdr[PL061_GPIO_NR]))(void *args); - void *args[PL061_GPIO_NR]; -} _pl061; - -static rt_ubase_t pl061_gpio_base = PL061_GPIO_BASE; - -rt_inline rt_uint8_t pl061_read8(rt_ubase_t offset) -{ - return HWREG8(pl061_gpio_base + offset); -} - -rt_inline void pl061_write8(rt_ubase_t offset, rt_uint8_t value) -{ - HWREG8(pl061_gpio_base + offset) = value; -} - -static void pl061_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode) -{ - int value; - rt_uint8_t gpiodir; - -#ifdef RT_USING_SMP - rt_base_t level; -#endif - - if (pin < 0 || pin >= PL061_GPIO_NR) - { - return; - } - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&_pl061.spinlock); -#endif - - switch (mode) - { - case PIN_MODE_OUTPUT: - - value = !!pl061_read8((BIT(pin + 2))); - - pl061_write8(BIT(pin + 2), 0 << pin); - gpiodir = pl061_read8(GPIODIR); - gpiodir |= BIT(pin); - pl061_write8(GPIODIR, gpiodir); - - /* - * gpio value is set again, because pl061 doesn't allow to set value of - * a gpio pin before configuring it in OUT mode. - */ - pl061_write8((BIT(pin + 2)), value << pin); - - break; - case PIN_MODE_INPUT: - - gpiodir = pl061_read8(GPIODIR); - gpiodir &= ~(BIT(pin)); - pl061_write8(GPIODIR, gpiodir); - - break; - } - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&_pl061.spinlock, level); -#endif -} - -static void pl061_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value) -{ - pl061_write8(BIT(pin + 2), !!value << pin); -} - -static rt_ssize_t pl061_pin_read(struct rt_device *device, rt_base_t pin) -{ - return !!pl061_read8((BIT(pin + 2))); -} - -static rt_err_t pl061_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args) -{ - rt_uint8_t gpiois, gpioibe, gpioiev; - rt_uint8_t bit = BIT(mode); -#ifdef RT_USING_SMP - rt_base_t level; -#endif - - if (pin < 0 || pin >= PL061_GPIO_NR) - { - return -RT_EINVAL; - } - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&_pl061.spinlock); -#endif - - gpioiev = pl061_read8(GPIOIEV); - gpiois = pl061_read8(GPIOIS); - gpioibe = pl061_read8(GPIOIBE); - - if (mode == PIN_IRQ_MODE_HIGH_LEVEL || pin == PIN_IRQ_MODE_LOW_LEVEL) - { - rt_bool_t polarity = (mode == PIN_IRQ_MODE_HIGH_LEVEL); - - /* Disable edge detection */ - gpioibe &= ~bit; - /* Enable level detection */ - gpiois |= bit; - - /* Select polarity */ - if (polarity) - { - gpioiev |= bit; - } - else - { - gpioiev &= ~bit; - } - } - else if (mode == PIN_IRQ_MODE_RISING_FALLING) - { - /* Disable level detection */ - gpiois &= ~bit; - /* Select both edges, setting this makes GPIOEV be ignored */ - gpioibe |= bit; - } - else if (mode == PIN_IRQ_MODE_RISING || mode == PIN_IRQ_MODE_FALLING) - { - rt_bool_t rising = (mode == PIN_IRQ_MODE_RISING); - - /* Disable level detection */ - gpiois &= ~bit; - /* Clear detection on both edges */ - gpioibe &= ~bit; - - /* Select edge */ - if (rising) - { - gpioiev |= bit; - } - else - { - gpioiev &= ~bit; - } - } - else - { - /* No trigger: disable everything */ - gpiois &= ~bit; - gpioibe &= ~bit; - gpioiev &= ~bit; - } - - pl061_write8(GPIOIS, gpiois); - pl061_write8(GPIOIBE, gpioibe); - pl061_write8(GPIOIEV, gpioiev); - - _pl061.hdr[pin] = hdr; - _pl061.args[pin] = args; - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&_pl061.spinlock, level); -#endif - - return RT_EOK; -} - -static rt_err_t pl061_pin_detach_irq(struct rt_device *device, rt_base_t pin) -{ - if (pin < 0 || pin >= PL061_GPIO_NR) - { - return -RT_EINVAL; - } - - _pl061.hdr[pin] = RT_NULL; - _pl061.args[pin] = RT_NULL; - - return RT_EOK; -} - -static rt_err_t pl061_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled) -{ - rt_uint8_t mask = BIT(pin); - rt_uint8_t gpioie; - -#ifdef RT_USING_SMP - rt_base_t level; -#endif - - if (pin < 0 || pin >= PL061_GPIO_NR) - { - return -RT_EINVAL; - } - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&_pl061.spinlock); -#endif - - if (enabled) - { - gpioie = pl061_read8(GPIOIE) | mask; - } - else - { - gpioie = pl061_read8(GPIOIE) & ~mask; - } - - pl061_write8(GPIOIE, gpioie); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&_pl061.spinlock, level); -#endif - - return RT_EOK; -} - -static const struct rt_pin_ops ops = -{ - pl061_pin_mode, - pl061_pin_write, - pl061_pin_read, - pl061_pin_attach_irq, - pl061_pin_detach_irq, - pl061_pin_irq_enable, - RT_NULL, -}; - -static void rt_hw_gpio_isr(int irqno, void *param) -{ - rt_uint8_t mask; - unsigned long pending; - -#ifdef RT_USING_SMP - rt_base_t level; -#endif - - pending = pl061_read8(GPIOMIS); - - if (pending) - { - rt_base_t pin; - - for (pin = 0; pin < PL061_GPIO_NR; ++pin) - { - if (pending & BIT(pin)) - { - mask |= BIT(pin); - - if (_pl061.hdr[pin] != RT_NULL) - { - _pl061.hdr[pin](_pl061.args[pin]); - } - } - } - } - -#ifdef RT_USING_SMP - level = rt_spin_lock_irqsave(&_pl061.spinlock); -#endif - - pl061_write8(GPIOIC, mask); - -#ifdef RT_USING_SMP - rt_spin_unlock_irqrestore(&_pl061.spinlock, level); -#endif -} - -int rt_hw_gpio_init(void) -{ -#ifdef RT_USING_SMP - rt_spin_lock_init(&_pl061.spinlock); -#endif - - pl061_gpio_base = (rt_size_t)rt_ioremap((void *)pl061_gpio_base, PL061_GPIO_SIZE); - - rt_device_pin_register("gpio", &ops, RT_NULL); - rt_hw_interrupt_install(PL061_GPIO_IRQNUM, rt_hw_gpio_isr, RT_NULL, "gpio"); - rt_hw_interrupt_umask(PL061_GPIO_IRQNUM); - - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_gpio_init); - -#endif /* BSP_USING_PIN */ diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_gpio.h b/bsp/qemu-virt64-aarch64/drivers/drv_gpio.h deleted file mode 100644 index 3f3e014f11..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_gpio.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-6-30 GuEe-GUI first version - */ - -#ifndef DRV_GPIO_H__ -#define DRV_GPIO_H__ - -int rt_hw_gpio_init(void); - -#endif diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_romfb.c b/bsp/qemu-virt64-aarch64/drivers/drv_romfb.c new file mode 100755 index 0000000000..15ad89f443 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/drivers/drv_romfb.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include + +void platform_get_ramfb_params(rt_uint32_t *width, rt_uint32_t *height) +{ + *width = RT_GRAPHIC_ROMFB_WIDTH; + *height = RT_GRAPHIC_ROMFB_HEIGHT; +} diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c b/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c deleted file mode 100644 index f0a041b70d..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-4 GuEe-GUI first version - */ - -#include -#include -#include -#include - -#include "drv_rtc.h" - -#ifdef BSP_USING_RTC - -#define RTC_DR 0x00 /* data read register */ -#define RTC_MR 0x04 /* match register */ -#define RTC_LR 0x08 /* data load register */ -#define RTC_CR 0x0c /* control register */ -#define RTC_IMSC 0x10 /* interrupt mask and set register */ -#define RTC_RIS 0x14 /* raw interrupt status register */ -#define RTC_MIS 0x18 /* masked interrupt status register */ -#define RTC_ICR 0x1c /* interrupt clear register */ - -#define RTC_CR_OPEN 1 -#define RTC_CR_CLOSE 0 - -static struct hw_rtc_device rtc_device; -static rt_ubase_t pl031_rtc_base = PL031_RTC_BASE; - -rt_inline rt_uint32_t pl031_read32(rt_ubase_t offset) -{ - return (*((volatile unsigned int *)(pl031_rtc_base + offset))); -} - -rt_inline void pl031_write32(rt_ubase_t offset, rt_uint32_t value) -{ - (*((volatile unsigned int *)(pl031_rtc_base + offset))) = value; -} - -static rt_err_t pl031_rtc_init(rt_device_t dev) -{ - return RT_EOK; -} - -static rt_err_t pl031_rtc_open(rt_device_t dev, rt_uint16_t oflag) -{ - pl031_write32(RTC_CR, RTC_CR_OPEN); - return RT_EOK; -} - -static rt_err_t pl031_rtc_close(rt_device_t dev) -{ - pl031_write32(RTC_CR, RTC_CR_CLOSE); - return RT_EOK; -} - -static rt_err_t pl031_rtc_control(rt_device_t dev, int cmd, void *args) -{ - - RT_ASSERT(dev != RT_NULL); - - if (args == RT_NULL) - { - return -RT_EINVAL; - } - - switch (cmd) - { - case RT_DEVICE_CTRL_RTC_GET_TIME: - *(time_t *)args = pl031_read32(RTC_DR); - break; - case RT_DEVICE_CTRL_RTC_SET_TIME: - pl031_write32(RTC_LR, *(time_t *)args); - break; - default: - return -RT_EINVAL; - } - return RT_EOK; -} - -static rt_ssize_t pl031_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer); - return size; -} - -static rt_ssize_t pl031_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer); - return size; -} - -const static struct rt_device_ops pl031_rtc_ops = -{ - .init = pl031_rtc_init, - .open = pl031_rtc_open, - .close = pl031_rtc_close, - .read = pl031_rtc_read, - .write = pl031_rtc_write, - .control = pl031_rtc_control -}; - -int rt_hw_rtc_init(void) -{ - pl031_rtc_base = (rt_size_t)rt_ioremap((void *)pl031_rtc_base, PL031_RTC_SIZE); - - rt_memset(&rtc_device, 0, sizeof(rtc_device)); - - rtc_device.device.type = RT_Device_Class_RTC; - rtc_device.device.rx_indicate = RT_NULL; - rtc_device.device.tx_complete = RT_NULL; - rtc_device.device.ops = &pl031_rtc_ops; - rtc_device.device.user_data = RT_NULL; - - /* register a rtc device */ - rt_device_register(&rtc_device.device, "rtc0", RT_DEVICE_FLAG_RDWR); - rt_soft_rtc_set_source("rtc0"); - return 0; -} -INIT_DEVICE_EXPORT(rt_hw_rtc_init); -#endif /* BSP_USING_RTC */ diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.h b/bsp/qemu-virt64-aarch64/drivers/drv_rtc.h deleted file mode 100644 index 15d4f01a9c..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_rtc.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-4 GuEe-GUI first version - */ - -#ifndef DRV_RTC_H__ -#define DRV_RTC_H__ - -#include -#include -#include - -struct hw_rtc_device -{ - struct rt_device device; -}; - -int rt_hw_rtc_init(void); - -#endif diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_uart.c b/bsp/qemu-virt64-aarch64/drivers/drv_uart.c deleted file mode 100644 index 12005d297d..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_uart.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * serial.c UART driver - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-03-30 Bernard the first verion - */ - -#include -#include - -#include "board.h" -#include "mmu.h" - -struct hw_uart_device -{ - rt_size_t hw_base; - rt_size_t irqno; -}; - -#define UART_DR(base) __REG32(base + 0x00) -#define UART_FR(base) __REG32(base + 0x18) -#define UART_CR(base) __REG32(base + 0x30) -#define UART_IMSC(base) __REG32(base + 0x38) -#define UART_ICR(base) __REG32(base + 0x44) - -#define UARTFR_RXFE 0x10 -#define UARTFR_TXFF 0x20 -#define UARTIMSC_RXIM 0x10 -#define UARTIMSC_TXIM 0x20 -#define UARTICR_RXIC 0x10 -#define UARTICR_TXIC 0x20 - -static void rt_hw_uart_isr(int irqno, void *param) -{ - struct rt_serial_device *serial = (struct rt_serial_device *)param; - - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); -} - -static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) -{ - return RT_EOK; -} - -static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - switch (cmd) - { - case RT_DEVICE_CTRL_CLR_INT: - /* disable rx irq */ - UART_IMSC(uart->hw_base) &= ~UARTIMSC_RXIM; - break; - - case RT_DEVICE_CTRL_SET_INT: - /* enable rx irq */ - UART_IMSC(uart->hw_base) |= UARTIMSC_RXIM; - rt_hw_interrupt_umask(uart->irqno); - break; - - default: - return -1; - } - - return RT_EOK; -} - -static int uart_putc(struct rt_serial_device *serial, char c) -{ - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - while (UART_FR(uart->hw_base) & UARTFR_TXFF); - UART_DR(uart->hw_base) = c; - - return 1; -} - -static int uart_getc(struct rt_serial_device *serial) -{ - int ch; - struct hw_uart_device *uart; - - RT_ASSERT(serial != RT_NULL); - uart = (struct hw_uart_device *)serial->parent.user_data; - - ch = -1; - if (!(UART_FR(uart->hw_base) & UARTFR_RXFE)) - { - ch = UART_DR(uart->hw_base) & 0xff; - } - - return ch; -} - -static const struct rt_uart_ops _uart_ops = -{ - uart_configure, - uart_control, - uart_putc, - uart_getc, -}; - -#ifdef RT_USING_UART0 -/* UART device driver structure */ -static struct hw_uart_device _uart0_device = -{ - PL011_UART0_BASE, - PL011_UART0_IRQNUM, -}; -static struct rt_serial_device _serial0; -#endif - -int rt_hw_uart_init(void) -{ - struct hw_uart_device *uart; - struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; - -#ifdef RT_USING_UART0 - _uart0_device.hw_base = (rt_size_t)rt_ioremap((void*)_uart0_device.hw_base, PL011_UART0_SIZE); - uart = &_uart0_device; - - _serial0.ops = &_uart_ops; - _serial0.config = config; - - /* register UART1 device */ - rt_hw_serial_register(&_serial0, "uart0", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, - uart); - rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, &_serial0, "uart0"); - /* enable Rx and Tx of UART */ - UART_CR(uart->hw_base) = (1 << 0) | (1 << 8) | (1 << 9); -#endif - - return 0; -} diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_uart.h b/bsp/qemu-virt64-aarch64/drivers/drv_uart.h deleted file mode 100644 index 1cd7a583ff..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_uart.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2013-03-30 Bernard the first verion - */ - -#ifndef __DRV_UART_H__ -#define __DRV_UART_H__ - -int rt_hw_uart_init(void); - -#endif /* __DRV_UART_H__ */ diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_virtio.c b/bsp/qemu-virt64-aarch64/drivers/drv_virtio.c deleted file mode 100644 index 2634da6773..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_virtio.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#include - -#include -#ifdef BSP_USING_VIRTIO_BLK -#include -#endif -#ifdef BSP_USING_VIRTIO_NET -#include -#endif -#ifdef BSP_USING_VIRTIO_CONSOLE -#include -#endif -#ifdef BSP_USING_VIRTIO_GPU -#include -#endif -#ifdef BSP_USING_VIRTIO_INPUT -#include -#endif - -#include - -static virtio_device_init_handler virtio_device_init_handlers[] = -{ -#ifdef BSP_USING_VIRTIO_BLK - [VIRTIO_DEVICE_ID_BLOCK] = rt_virtio_blk_init, -#endif -#ifdef BSP_USING_VIRTIO_NET - [VIRTIO_DEVICE_ID_NET] = rt_virtio_net_init, -#endif -#ifdef BSP_USING_VIRTIO_CONSOLE - [VIRTIO_DEVICE_ID_CONSOLE] = rt_virtio_console_init, -#endif -#ifdef BSP_USING_VIRTIO_GPU - [VIRTIO_DEVICE_ID_GPU] = rt_virtio_gpu_init, -#endif -#ifdef BSP_USING_VIRTIO_INPUT - [VIRTIO_DEVICE_ID_INPUT] = rt_virtio_input_init, -#endif -}; - -int rt_virtio_devices_init(void) -{ - int i; - rt_uint32_t irq = VIRTIO_IRQ_BASE; - rt_ubase_t mmio_base = VIRTIO_MMIO_BASE; - struct virtio_mmio_config *mmio_config; - virtio_device_init_handler init_handler; - - if (sizeof(virtio_device_init_handlers) == 0) - { - /* The compiler will optimize the codes after here. */ - return 0; - } - - mmio_base = (rt_ubase_t)rt_ioremap((void *)mmio_base, VIRTIO_MMIO_SIZE * VIRTIO_MAX_NR); - - if (mmio_base == RT_NULL) - { - return -RT_ERROR; - } - - for (i = 0; i < VIRTIO_MAX_NR; ++i, ++irq, mmio_base += VIRTIO_MMIO_SIZE) - { - mmio_config = (struct virtio_mmio_config *)mmio_base; - - if (mmio_config->magic != VIRTIO_MAGIC_VALUE || - mmio_config->version != RT_USING_VIRTIO_VERSION || - mmio_config->vendor_id != VIRTIO_VENDOR_ID) - { - continue; - } - - init_handler = virtio_device_init_handlers[mmio_config->device_id]; - - if (init_handler != RT_NULL) - { - init_handler((rt_ubase_t *)mmio_base, irq); - } - } - - return 0; -} -INIT_DEVICE_EXPORT(rt_virtio_devices_init); diff --git a/bsp/qemu-virt64-aarch64/drivers/drv_virtio.h b/bsp/qemu-virt64-aarch64/drivers/drv_virtio.h deleted file mode 100644 index 954338a386..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/drv_virtio.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-11-11 GuEe-GUI the first version - */ - -#ifndef __DRV_VIRTIO_H__ -#define __DRV_VIRTIO_H__ - -int rt_virtio_devices_init(void); - -#endif /* __DRV_VIRTIO_H__ */ diff --git a/bsp/qemu-virt64-aarch64/drivers/virt.h b/bsp/qemu-virt64-aarch64/drivers/virt.h deleted file mode 100644 index 801e889bff..0000000000 --- a/bsp/qemu-virt64-aarch64/drivers/virt.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2021-02-17 GuEe-GUI the first version - */ - -#ifndef VIRT_H__ -#define VIRT_H__ - -#include -#include - -#ifdef RT_USING_SMART -#include -#endif - -#define __REG32(x) (*((volatile unsigned int *)(x))) -#define __REG16(x) (*((volatile unsigned short *)(x))) - -/* UART */ -#define PL011_UART0_BASE 0x09000000 -#define PL011_UART0_SIZE 0x00001000 -#define PL011_UART0_IRQNUM (32 + 1) - -/* RTC */ -#define PL031_RTC_BASE 0x9010000 -#define PL031_RTC_SIZE 0x00001000 -#define PL031_RTC_IRQNUM (32 + 2) - -/* GPIO */ -#define PL061_GPIO_BASE 0x09030000 -#define PL061_GPIO_SIZE 0x00001000 -#define PL061_GPIO_IRQNUM (32 + 7) - -/* VirtIO */ -#define VIRTIO_MMIO_BASE 0x0a000000 -#define VIRTIO_MMIO_SIZE 0x00000200 -#define VIRTIO_MAX_NR 32 -#define VIRTIO_IRQ_BASE (32 + 16) -#define VIRTIO_VENDOR_ID 0x554d4551 /* "QEMU" */ - -/* GIC */ -#define MAX_HANDLERS 96 -#define GIC_IRQ_START 0 -#define ARM_GIC_NR_IRQS 96 -#define ARM_GIC_MAX_NR 1 - -#define IRQ_ARM_IPI_KICK 0 -#define IRQ_ARM_IPI_CALL 1 - -/* GICv2 */ -#define GIC_PL390_DISTRIBUTOR_PPTR 0x08000000 -#define GIC_PL390_CONTROLLER_PPTR 0x08010000 -#define GIC_PL390_HYPERVISOR_BASE 0x08030000 -#define GIC_PL390_VIRTUAL_CPU_BASE 0x08040000 - -/* GICv3 */ -#define GIC_PL500_DISTRIBUTOR_PPTR GIC_PL390_DISTRIBUTOR_PPTR -#define GIC_PL500_REDISTRIBUTOR_PPTR 0x080a0000 -#define GIC_PL500_CONTROLLER_PPTR GIC_PL390_CONTROLLER_PPTR -#define GIC_PL500_ITS_PPTR 0x08080000 - -/* the basic constants and interfaces needed by gic */ -rt_inline rt_ubase_t platform_get_gic_dist_base(void) -{ -#ifdef BSP_USING_GICV2 - return GIC_PL390_DISTRIBUTOR_PPTR; -#else - return GIC_PL500_DISTRIBUTOR_PPTR; -#endif -} - -rt_inline rt_ubase_t platform_get_gic_redist_base(void) -{ - return GIC_PL500_REDISTRIBUTOR_PPTR; -} - -rt_inline rt_ubase_t platform_get_gic_cpu_base(void) -{ -#ifdef BSP_USING_GICV2 - return GIC_PL390_CONTROLLER_PPTR; -#else - return GIC_PL500_CONTROLLER_PPTR; -#endif -} - -rt_inline rt_ubase_t platform_get_gic_its_base(void) -{ - return GIC_PL500_ITS_PPTR; -} - -#endif diff --git a/bsp/qemu-virt64-aarch64/qemu-debug.bat b/bsp/qemu-virt64-aarch64/qemu-debug.bat deleted file mode 100644 index 8d47286bd2..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu-debug.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -if exist sd.bin goto run -qemu-img create -f raw sd.bin 64M - -:run -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.bin -nographic ^ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 ^ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 -s -S ^ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/qemu-debug.sh b/bsp/qemu-virt64-aarch64/qemu-debug.sh deleted file mode 100644 index 6e60986085..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu-debug.sh +++ /dev/null @@ -1,8 +0,0 @@ -if [ ! -f "sd.bin" ]; then -dd if=/dev/zero of=sd.bin bs=1024 count=65536 -mkfs.fat sd.bin -fi -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -m 128M -smp 4 -kernel rtthread.bin -nographic \ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 -s -S \ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/qemu-device-camera.c b/bsp/qemu-virt64-aarch64/qemu-device-camera.c new file mode 100755 index 0000000000..494fb7275e --- /dev/null +++ b/bsp/qemu-virt64-aarch64/qemu-device-camera.c @@ -0,0 +1,709 @@ +#if 0 +rm -f /tmp/qemu-device-camera.sock +gcc $0 -o qemu-device-camera -lvfio-user && LD_LIBRARY_PATH=/usr/local/lib/ ./qemu-device-camera $1 +rm -f /tmp/qemu-device-camera.sock qemu-device-camera +exit +#endif +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-07 GuEe-GUI the first version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif + +#define DEBUG 0 +#define SOCKET_PATH "/tmp/qemu-device-camera.sock" + +#define BAR3_FRAME_COUNT_OFFSET 0x00 +#define BAR3_FRAME_READY_OFFSET 0x04 +#define BAR3_SIZE 0x1000 + +struct vfio_camera +{ + void *bar0_width; + size_t bar0_width_size; + void *bar1_height; + size_t bar1_height_size; + void *bar2_framebuffer; + size_t bar2_framebuffer_size; + int bar2_fd; /* Shared memory fd for zero-copy */ + void *bar3_status; + size_t bar3_status_size; + uint32_t frame_count; + uint32_t frame_ready; + int fd; + enum v4l2_buf_type type; + struct v4l2_format fmt; + struct video_buffer *buffers; + int buffer_count; + bool streaming; +}; + +struct video_buffer +{ + void *start; + size_t length; +}; + +static volatile sig_atomic_t running = 1; + +static void handle_signal(int sig) +{ + running = 0; +} + +static void setup_signal(void) +{ + struct sigaction sa; + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + +/* Create shared memory file descriptor */ +static int create_shmem_fd(size_t size) +{ + int fd; + + /* Try memfd_create first (Linux 3.17+) */ +#ifdef __NR_memfd_create + fd = syscall(__NR_memfd_create, "camera_fb", MFD_CLOEXEC); + if (fd >= 0) + { + if (ftruncate(fd, size) == 0) + { + return fd; + } + close(fd); + } +#endif + + /* Fallback: use shm_open */ + fd = shm_open("/camera_framebuffer", O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) + { + /* Unlink but keep fd */ + shm_unlink("/camera_framebuffer"); + if (ftruncate(fd, size) == 0) + { + return fd; + } + close(fd); + } + + return -1; +} + +static inline uint64_t round_up_pow2_u64(uint64_t x) +{ + if (x <= 1) + { + return 1; + } + return 1ULL << (64 - __builtin_clzll(x - 1)); +} + +static inline unsigned char clamp(int v) +{ + if (v < 0) + { + return 0; + } + if (v > 255) + { + return 255; + } + return v; +} + +static inline void yuyv_to_rgb_pair(unsigned char *src, unsigned char *dst) +{ + int y0 = src[0]; + int u = src[1] - 128; + int y1 = src[2]; + int v = src[3] - 128; + int r, g, b; + + /* pixel 0 */ + r = y0 + ((1436 * v) >> 10); + g = y0 - ((352 * u + 731 * v) >> 10); + b = y0 + ((1815 * u) >> 10); + dst[0] = clamp(r); + dst[1] = clamp(g); + dst[2] = clamp(b); + + /* pixel 1 */ + r = y1 + ((1436 * v) >> 10); + g = y1 - ((352 * u + 731 * v) >> 10); + b = y1 + ((1815 * u) >> 10); + dst[3] = clamp(r); + dst[4] = clamp(g); + dst[5] = clamp(b); +} + +/* Try to capture one frame (non-blocking) */ +static void try_capture_frame(struct vfio_camera *vc) +{ + struct v4l2_buffer buf; + unsigned char *src, *dst; + int pixels; + + if (!vc->streaming) + { + return; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = vc->type; + buf.memory = V4L2_MEMORY_MMAP; + + /* Non-blocking dequeue */ + if (ioctl(vc->fd, VIDIOC_DQBUF, &buf) < 0) + { + if (errno == EAGAIN) + { + /* No frame ready */ + return; + } + perror("DQBUF"); + return; + } + + /* Convert YUYV to RGB24 */ + if (buf.bytesused > 0) + { + src = vc->buffers[buf.index].start; + dst = vc->bar2_framebuffer; + pixels = vc->fmt.fmt.pix.width * vc->fmt.fmt.pix.height; + + for (int i = 0; i < pixels; i += 2) + { + yuyv_to_rgb_pair(src, dst); + src += 4; + dst += 6; + } + + /* Update frame status */ + vc->frame_count++; + vc->frame_ready = 1; + memcpy((char *)vc->bar3_status + BAR3_FRAME_COUNT_OFFSET, &vc->frame_count, sizeof(uint32_t)); + memcpy((char *)vc->bar3_status + BAR3_FRAME_READY_OFFSET, &vc->frame_ready, sizeof(uint32_t)); + } + + /* Re-queue buffer */ + if (ioctl(vc->fd, VIDIOC_QBUF, &buf) < 0) + { + perror("QBUF"); + } +} + +static void get_max_resolution(int fd, uint32_t pixfmt, int *max_w, int *max_h) +{ + struct v4l2_frmsizeenum fsize; + + memset(&fsize, 0, sizeof(fsize)); + + for (int i = 0; ; ++i) + { + fsize.index = i; + fsize.pixel_format = pixfmt; + + if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) + { + break; + } + + if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) + { + if (fsize.discrete.width * fsize.discrete.height > (*max_w) * (*max_h)) + { + *max_w = fsize.discrete.width; + *max_h = fsize.discrete.height; + } + } + else if (fsize.type == V4L2_FRMSIZE_TYPE_STEPWISE || + fsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) + { + *max_w = fsize.stepwise.max_width; + *max_h = fsize.stepwise.max_height; + break; + } + } +} + +static void vfio_log_cb(vfu_ctx_t *vfu_ctx, int level, const char *msg) +{ + fprintf(stderr, "[VFIO] %s", msg); +} + +static ssize_t bar0_width_access(vfu_ctx_t *vfu_ctx, char *buf, size_t count, + loff_t offset, bool is_write) +{ + struct vfio_camera *vc = vfu_get_private(vfu_ctx); + +#if DEBUG + fprintf(stderr, "BAR0 access: offset=0x%lx, count=%zu, is_write=%d\n", + (unsigned long)offset, count, is_write); +#endif + + if (offset + count > vc->bar0_width_size) + { + errno = EINVAL; + return -1; + } + + if (!is_write) + { + memcpy(buf, (char *)vc->bar0_width + offset, count); + } + + return (ssize_t)count; +} + +static ssize_t bar1_height_access(vfu_ctx_t *vfu_ctx, char *buf, size_t count, + loff_t offset, bool is_write) +{ + struct vfio_camera *vc = vfu_get_private(vfu_ctx); + +#if DEBUG + fprintf(stderr, "BAR1 access: offset=0x%lx, count=%zu, is_write=%d\n", + (unsigned long)offset, count, is_write); +#endif + + if (offset + count > vc->bar1_height_size) + { + errno = EINVAL; + return -1; + } + + if (!is_write) + { + memcpy(buf, (char *)vc->bar1_height + offset, count); + } + + return (ssize_t)count; +} + +static ssize_t bar2_framebuffer_access(vfu_ctx_t *vfu_ctx, char *buf, size_t count, + loff_t offset, bool is_write) +{ + struct vfio_camera *vc = vfu_get_private(vfu_ctx); + +#if DEBUG + fprintf(stderr, "BAR2 access: offset=0x%lx, count=%zu, is_write=%d\n", + (unsigned long)offset, count, is_write); +#endif + + /* Try to capture a frame when framebuffer is accessed */ + try_capture_frame(vc); + + if (offset + count > vc->bar2_framebuffer_size) + { + errno = EINVAL; + return -1; + } + + if (!is_write) + { + memcpy(buf, (char *)vc->bar2_framebuffer + offset, count); + } + + return (ssize_t)count; +} + +static ssize_t bar3_status_access(vfu_ctx_t *vfu_ctx, char *buf, size_t count, + loff_t offset, bool is_write) +{ + struct vfio_camera *vc = vfu_get_private(vfu_ctx); + +#if DEBUG + fprintf(stderr, "BAR3 access: offset=0x%lx, count=%zu, is_write=%d\n", + (unsigned long)offset, count, is_write); +#endif + + /* Try to capture frame when status is read */ + if (!is_write) + { + try_capture_frame(vc); + } + + if (offset + count > vc->bar3_status_size) + { + errno = EINVAL; + return -1; + } + + if (!is_write) + { + memcpy(buf, (char *)vc->bar3_status + offset, count); + } + else + { + /* Allow RT-Thread to clear frame_ready flag */ + memcpy((char *)vc->bar3_status + offset, buf, count); + if (offset <= BAR3_FRAME_READY_OFFSET && offset + count >= BAR3_FRAME_READY_OFFSET + sizeof(uint32_t)) + { + memcpy(&vc->frame_ready, (char *)vc->bar3_status + BAR3_FRAME_READY_OFFSET, sizeof(uint32_t)); + } + } + + return (ssize_t)count; +} + +static int device_reset(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type) +{ + vfu_log(vfu_ctx, LOG_DEBUG, "Device reset"); + return 0; +} + +static void cleanup_buffers(struct video_buffer *buffers, int count) +{ + if (!buffers) return; + + for (int i = 0; i < count; ++i) + { + if (buffers[i].start && buffers[i].start != MAP_FAILED) + { + munmap(buffers[i].start, buffers[i].length); + } + } + free(buffers); +} + +int main(int argc, char *argv[]) +{ + int fd, ret; + vfu_ctx_t *vfu_ctx; + struct vfio_camera vc; + struct v4l2_buffer buf; + struct v4l2_requestbuffers req; + size_t expected_frame_size; + + memset(&vc, 0, sizeof(vc)); + vc.bar2_fd = -1; + + /* Open camera device */ + fd = open(argc > 1 ? argv[1] : "/dev/video0", O_RDWR | O_NONBLOCK); + if (fd < 0) + { + perror("open camera"); + return -1; + } + vc.fd = fd; + + /* Set format */ + memset(&vc.fmt, 0, sizeof(vc.fmt)); + vc.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vc.fmt.fmt.pix.width = 640; + vc.fmt.fmt.pix.height = 480; + vc.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + vc.fmt.fmt.pix.field = V4L2_FIELD_ANY; + + get_max_resolution(fd, vc.fmt.fmt.pix.pixelformat, + &vc.fmt.fmt.pix.width, &vc.fmt.fmt.pix.height); + + if (ioctl(fd, VIDIOC_S_FMT, &vc.fmt) < 0) + { + perror("VIDIOC_S_FMT"); + goto _err_close; + } + + /* Request buffers */ + memset(&req, 0, sizeof(req)); + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) + { + perror("REQBUFS"); + goto _err_close; + } + + vc.buffers = calloc(req.count, sizeof(*vc.buffers)); + if (!vc.buffers) + { + perror("calloc buffers"); + goto _err_close; + } + vc.buffer_count = req.count; + + /* Map buffers */ + for (int i = 0; i < req.count; ++i) + { + memset(&buf, 0, sizeof(buf)); + buf.type = req.type; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + + if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) + { + perror("QUERYBUF"); + goto _err_cleanup; + } + + vc.buffers[i].length = buf.length; + vc.buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, buf.m.offset); + if (vc.buffers[i].start == MAP_FAILED) + { + perror("mmap"); + goto _err_cleanup; + } + } + + /* Queue buffers */ + for (int i = 0; i < req.count; ++i) + { + memset(&buf, 0, sizeof(buf)); + buf.type = req.type; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + + if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) + { + perror("QBUF"); + goto _err_streamoff; + } + } + + /* Start streaming */ + vc.type = req.type; + if (ioctl(fd, VIDIOC_STREAMON, &vc.type) < 0) + { + perror("STREAMON"); + goto _err_streamoff; + } + vc.streaming = true; + + /* Setup BARs */ + expected_frame_size = vc.fmt.fmt.pix.width * vc.fmt.fmt.pix.height * 3; + + vc.bar0_width_size = 0x1000; + vc.bar0_width = mmap(NULL, vc.bar0_width_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (vc.bar0_width == MAP_FAILED) + { + perror("mmap bar0"); + goto _err_streamoff; + } + memcpy(vc.bar0_width, &vc.fmt.fmt.pix.width, sizeof(uint32_t)); + + vc.bar1_height_size = 0x1000; + vc.bar1_height = mmap(NULL, vc.bar1_height_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (vc.bar1_height == MAP_FAILED) + { + perror("mmap bar1"); + goto _err_unmap_bar0; + } + memcpy(vc.bar1_height, &vc.fmt.fmt.pix.height, sizeof(uint32_t)); + + /* Allocate framebuffer with shared memory for zero-copy */ + vc.bar2_framebuffer_size = round_up_pow2_u64(expected_frame_size); + vc.bar2_fd = create_shmem_fd(vc.bar2_framebuffer_size); + if (vc.bar2_fd < 0) + { + perror("create_shmem_fd"); + goto _err_unmap_bar1; + } + + vc.bar2_framebuffer = mmap(NULL, vc.bar2_framebuffer_size, PROT_READ | PROT_WRITE, + MAP_SHARED, vc.bar2_fd, 0); + if (vc.bar2_framebuffer == MAP_FAILED) + { + perror("mmap bar2"); + close(vc.bar2_fd); + goto _err_unmap_bar1; + } + memset(vc.bar2_framebuffer, 0, vc.bar2_framebuffer_size); + + vc.bar3_status_size = BAR3_SIZE; + vc.bar3_status = mmap(NULL, vc.bar3_status_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (vc.bar3_status == MAP_FAILED) + { + perror("mmap bar3"); + goto _err_unmap_bar2; + } + vc.frame_count = 0; + vc.frame_ready = 0; + memcpy((char *)vc.bar3_status + BAR3_FRAME_COUNT_OFFSET, &vc.frame_count, sizeof(uint32_t)); + memcpy((char *)vc.bar3_status + BAR3_FRAME_READY_OFFSET, &vc.frame_ready, sizeof(uint32_t)); + + /* Create VFIO context */ + vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, SOCKET_PATH, 0, &vc, VFU_DEV_TYPE_PCI); + if (!vfu_ctx) + { + perror("vfu_create_ctx"); + goto _err_unmap_bar3; + } + + ret = vfu_setup_log(vfu_ctx, vfio_log_cb, DEBUG ? LOG_DEBUG : LOG_ERR); + if (ret < 0) + { + perror("vfu_setup_log"); + goto _err_destroy_ctx; + } + + ret = vfu_pci_init(vfu_ctx, VFU_PCI_TYPE_CONVENTIONAL, PCI_HEADER_TYPE_NORMAL, 0); + if (ret < 0) + { + perror("vfu_pci_init"); + goto _err_destroy_ctx; + } + + vfu_pci_set_id(vfu_ctx, 0x1234, 0x5678, 0x0000, 0x0000); + vfu_pci_set_class(vfu_ctx, 0xff, 0x00, 0x00); + + /* Setup BAR regions */ + ret = vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR0_REGION_IDX, vc.bar0_width_size, + bar0_width_access, VFU_REGION_FLAG_READ | VFU_REGION_FLAG_MEM, + NULL, 0, -1, 0); + if (ret < 0) + { + perror("vfu_setup_region BAR0"); + goto _err_destroy_ctx; + } + + ret = vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR1_REGION_IDX, vc.bar1_height_size, + bar1_height_access, VFU_REGION_FLAG_READ | VFU_REGION_FLAG_MEM, + NULL, 0, -1, 0); + if (ret < 0) + { + perror("vfu_setup_region BAR1"); + goto _err_destroy_ctx; + } + + /* BAR2: Framebuffer region with zero-copy mmap */ + struct iovec bar2_mmap_areas[1] = + { + { .iov_base = 0, .iov_len = expected_frame_size } + }; + + ret = vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR2_REGION_IDX, vc.bar2_framebuffer_size, + bar2_framebuffer_access, /* Fallback callback for non-mmap access */ + VFU_REGION_FLAG_READ | VFU_REGION_FLAG_MEM, + bar2_mmap_areas, 1, vc.bar2_fd, 0); + if (ret < 0) + { + perror("vfu_setup_region BAR2"); + goto _err_destroy_ctx; + } + + ret = vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR3_REGION_IDX, vc.bar3_status_size, + bar3_status_access, VFU_REGION_FLAG_READ | VFU_REGION_FLAG_MEM, + NULL, 0, -1, 0); + if (ret < 0) + { + perror("vfu_setup_region BAR3"); + goto _err_destroy_ctx; + } + + ret = vfu_setup_device_reset_cb(vfu_ctx, device_reset); + if (ret < 0) + { + perror("vfu_setup_device_reset_cb"); + goto _err_destroy_ctx; + } + + ret = vfu_setup_device_nr_irqs(vfu_ctx, VFU_DEV_INTX_IRQ, 1); + if (ret < 0) + { + perror("vfu_setup_device_nr_irqs"); + goto _err_destroy_ctx; + } + + ret = vfu_realize_ctx(vfu_ctx); + if (ret < 0) + { + perror("vfu_realize_ctx"); + goto _err_destroy_ctx; + } + + ret = vfu_attach_ctx(vfu_ctx); + if (ret < 0) + { + perror("vfu_attach_ctx"); + goto _err_destroy_ctx; + } + + setup_signal(); + + /* Main loop */ + while (running) + { + ret = vfu_run_ctx(vfu_ctx); + if (ret < 0) + { + if (errno == ENOTCONN) + { + #if DEBUG + fprintf(stderr, "QEMU disconnected\n"); + #endif + + ret = vfu_attach_ctx(vfu_ctx); + if (ret < 0) + { + #if DEBUG + fprintf(stderr, "Failed to re-attach: %s\n", strerror(errno)); + #endif + break; + } + #if DEBUG + fprintf(stderr, "Re-attached to QEMU\n"); + #endif + continue; + } + perror("vfu_run_ctx"); + break; + } + } + +_err_destroy_ctx: + vfu_destroy_ctx(vfu_ctx); +_err_unmap_bar3: + munmap(vc.bar3_status, vc.bar3_status_size); +_err_unmap_bar2: + if (vc.bar2_fd >= 0) + { + close(vc.bar2_fd); + } + munmap(vc.bar2_framebuffer, vc.bar2_framebuffer_size); +_err_unmap_bar1: + munmap(vc.bar1_height, vc.bar1_height_size); +_err_unmap_bar0: + munmap(vc.bar0_width, vc.bar0_width_size); +_err_streamoff: + ioctl(fd, VIDIOC_STREAMOFF, &vc.type); +_err_cleanup: + cleanup_buffers(vc.buffers, vc.buffer_count); +_err_close: + close(fd); + + return 0; +} diff --git a/bsp/qemu-virt64-aarch64/qemu-graphic.bat b/bsp/qemu-virt64-aarch64/qemu-graphic.bat deleted file mode 100644 index 74332bb5ee..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu-graphic.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -if exist sd.bin goto run -qemu-img create -f raw sd.bin 64M - -:run -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.bin -serial stdio ^ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 ^ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 ^ --device virtio-gpu-device,xres=800,yres=600,bus=virtio-mmio-bus.2 ^ --device virtio-keyboard-device,bus=virtio-mmio-bus.3 ^ --device virtio-mouse-device,bus=virtio-mmio-bus.4 ^ --device virtio-tablet-device,bus=virtio-mmio-bus.5 ^ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/qemu-graphic.sh b/bsp/qemu-virt64-aarch64/qemu-graphic.sh deleted file mode 100644 index 52e78ba177..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu-graphic.sh +++ /dev/null @@ -1,12 +0,0 @@ -if [ ! -f "sd.bin" ]; then -dd if=/dev/zero of=sd.bin bs=1024 count=65536 -mkfs.fat sd.bin -fi -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.bin -serial stdio \ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 \ --device virtio-gpu-device,xres=800,yres=600,bus=virtio-mmio-bus.2 \ --device virtio-keyboard-device,bus=virtio-mmio-bus.3 \ --device virtio-mouse-device,bus=virtio-mmio-bus.4 \ --device virtio-tablet-device,bus=virtio-mmio-bus.5 \ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/qemu.bat b/bsp/qemu-virt64-aarch64/qemu.bat deleted file mode 100644 index de95884493..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -if exist sd.bin goto run -qemu-img create -f raw sd.bin 64M - -:run -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.bin -nographic ^ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 ^ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 ^ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/qemu.py b/bsp/qemu-virt64-aarch64/qemu.py new file mode 100755 index 0000000000..91b1ed1e33 --- /dev/null +++ b/bsp/qemu-virt64-aarch64/qemu.py @@ -0,0 +1,380 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import os, sys, re, shutil + +with open('rtconfig.h', 'r') as file: + rtconfig_header = file.read() + +if os.getenv('RTT_QEMU_ROOT'): + RTT_QEMU_ROOT = os.getenv('RTT_QEMU_ROOT') +else: + RTT_QEMU_ROOT = "" + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.join(os.getcwd(), '..', '..') + +sys.path.append(RTT_ROOT + '/tools') + +from building import * +import dtc + +# WSL? +is_windows = sys.platform.startswith('win') or \ + os.popen('which qemu-system-aarch64 | xargs file').read().find('PE') >= 0 or \ + (os.system("readlink `which qemu-system-aarch64` > /dev/null") == 0 and \ + os.popen('readlink `which qemu-system-aarch64` | xargs file').read().find('PE') >= 0) + +class QEMU_VERSION: + def __init__(self): + cmd = os.popen(RTT_QEMU_ROOT + "qemu-system-aarch64 --version").readlines()[0] + version = cmd[cmd.find("version ") + 8: -1].split('.') + + self.major = version[0] + self.minor = version[1] + self.revision = version[2] + # == + def __eq__(self, version_in): + version = version_in.split('.') + return self.major == version[0] and self.minor == version[1] and self.revision == version[2] + # >= + def __ge__(self, version_in): + return self.__gt__(version_in) or self.__eq__(version_in) + # > + def __gt__(self, version_in): + version = version_in.split('.') + return int(self.major) > int(version[0]) or \ + (int(self.major) == int(version[0]) and int(self.minor) > int(version[1])) or \ + (int(self.major) == int(version[0]) and int(self.minor) == int(version[1]) and int(self.revision) > int(version[2])) + # <= + def __le__(self, version_in): + return self.__lt__(version_in) or self.__eq__(version_in) + # < + def __lt__(self, version_in): + return not self.__ge__(version_in) + # != + def __ne__(self, version_in): + return not self.__eq__(version_in) + + def toString(self): + return self.major + '.' + self.minor + '.' + self.revision + +qemu_version = QEMU_VERSION() + +opt = sys.argv + +graphic_cfg = """ \ + -device ramfb \ + -device virtio-keyboard-device \ + -device virtio-tablet-device \ +""" + +smmu_cfg = "" +iommu_cfg = "" +cdrom_cfg = "" +virtfs_cfg = "" +ufs_cfg = "" +camera_cfg = "" +amp_cfg = "" + +q_gic = 2 +q_dumpdtb = "" +q_el = 1 +q_smp = int(re.findall(r'#define\s+RT_CPUS_NR\s+(\d+)', rtconfig_header)[0]) +q_mem = 128 +q_graphic = "-nographic" +q_debug = "" +q_bootargs = "console=ttyAMA0 earlycon cma=8M coherent_pool=2M root=vda0 rootfstype=elm rootwait rw" +q_initrd = "" +q_block = "virtio" +q_net = "user" +q_ssh = 12055 +q_scsi = "scsi" +q_cdrom = "" +q_flash = "flash" +q_emmc = "emmc" +q_nvme = "nvme" +q_ahci = "ahci" +q_gl = None +q_9p = "" +q_ufs = "ufs" +q_camera = "" +q_dtbo = [] +q_dtb = "" + +def is_opt(key, inkey): + if str("-" + key) == inkey: + return True + return False + +for i in range(len(opt)): + if i == 0: + continue + inkey = opt[i] + + if is_opt("gic", inkey): q_gic = int(opt[i + 1]) + if is_opt("dumpdtb", inkey): q_dumpdtb = str(",dumpdtb=" + opt[i + 1]) + if is_opt("el", inkey): q_el = int(opt[i + 1]) + if is_opt("smp", inkey): q_smp = int(opt[i + 1]) + if is_opt("mem", inkey): q_mem = int(opt[i + 1]) + if is_opt("debug", inkey): q_debug = "-S -s" + if is_opt("bootargs", inkey): q_bootargs = opt[i + 1] + if is_opt("initrd", inkey): q_initrd = str("-initrd " + opt[i + 1]) + if is_opt("graphic", inkey): q_graphic = graphic_cfg + if is_opt("virtio-block", inkey): q_block = opt[i + 1] + if is_opt("tap", inkey): q_net = "tap,ifname=tap0" + if is_opt("ssh", inkey): q_ssh = int(opt[i + 1]) + if is_opt("cdrom", inkey): q_cdrom = opt[i + 1] + if is_opt("flash", inkey): q_flash = opt[i + 1] + if is_opt("emmc", inkey): q_emmc = opt[i + 1] + if is_opt("nvme", inkey): q_nvme = opt[i + 1] + if is_opt("gl", inkey): q_gl = "-device virtio-gpu-gl-pci -display {},gl=on ".format(opt[i + 1]) + if is_opt("9p", inkey): q_9p = opt[i + 1] + if is_opt("ufs", inkey): q_ufs = opt[i + 1] + if is_opt("camera", inkey): q_camera = opt[i + 1] + if is_opt("dtb", inkey): q_dtb = "-dtb " + opt[i + 1] + if is_opt("dtbo", inkey): q_dtbo += [opt[i + 1]] + +# SMP +if q_smp > 8: + q_gic = 3 + +# Exception Level +if q_el == 1: + q_el = "" +elif q_el == 2: + q_el = ",virtualization=on" + if q_gic == 3: + q_gic = "max" +elif q_el == 3: + q_el = ",secure=on" +else: + print("Error: Invalid -el {}".format(q_el)) + exit(-1) + +# Display +# --enable-opengl --enable-virglrenderer +if q_graphic != "-nographic": + if q_gl: + q_graphic += q_gl + else: + q_graphic += "-device virtio-gpu-device " +elif q_gl != None: + print("Error: GL should in graphic mode") + exit(-1) + +# Net +# --enable-slirp +# Enable TAP in example (not support in Windows, Maybe WSL2): +# ETH0=`/sbin/route -n | awk '$1 == "0.0.0.0" {print $NF}'` +# ip link add br0 type bridge +# ip link set br0 up +# echo 1 | tee /proc/sys/net/ipv4/ip_forward > /dev/null +# ip link set ${ETH0} up +# ip link set ${ETH0} master br0 +# dhclient br0 +# ip tuntap add dev tap0 mode tap +# ip link set dev tap0 up +# ip link set tap0 master br0 +# +# Disable TAP in example (not support in Windows, Maybe WSL2): +# ip link set tap0 down +# ip tuntap del dev tap0 mod tap +# echo 0 | tee /proc/sys/net/ipv4/ip_forward > /dev/null +# ip link set br0 down +# ip link del br0 type bridge +if q_net.find("user") >= 0: + q_net += ",hostfwd=tcp::{}-:22".format(q_ssh) +else: + if not is_windows: + q_net += ",script=no,downscript=no" + print("Warning: SSH not set in TAP") + +# Storage +# pflash have pflash0 and pflash1, pflash0 is used for BootROMs such as UEFI +# if we load file to pflash0, QEMU will boot from it, so we only use pflash1. +# Well, we can R/W in pflash0 by CFI driver, but the data will lost after QEMU exits. +# +# partitions (not support in Windows, Maybe WSL2): +# modprobe nbd max_part=12 +# qemu-nbd --connect=/dev/nbdX ABC.qcow2 +# fdisk /dev/nbdX +# ... +# qemu-nbd --disconnect /dev/nbdX +disk_list = [q_block, q_scsi, q_flash, q_emmc, q_nvme, q_ahci] + +if qemu_version >= '8.2.0': + disk_list += [q_ufs] + ufs_cfg = """ \ + -drive if=none,file={}.qcow2,format=qcow2,id=ufs \ + -device ufs,serial=deadbeef \ + -device ufs-lu,drive=ufs \ + """.format(q_ufs) + +for disk in disk_list: + disk += ".qcow2" + if not os.path.exists(disk): + os.system("qemu-img create -f qcow2 {} 64M".format(disk)) + +if len(q_cdrom) > 0: + cdrom_cfg = """ \ + -device scsi-cd,channel=0,scsi-id=0,lun=1,drive=scsi1 \ + -drive file={},format=raw,if=none,id=scsi1 \ + """.format(q_cdrom) + +# Share File System +# --enable-virtfs +if len(q_9p) > 0: + p9_tag = "hostshare" + virtfs_cfg = """ \ + -fsdev local,security_model=passthrough,id=fsdev0,path={} \ + -device virtio-9p-device,fsdev=fsdev0,mount_tag={} \ + """.format(q_9p, p9_tag) + q_bootargs += " 9p.tag={} 9p.mount=host".format(p9_tag) + +# Camera (Linux only) +if len(q_camera) > 0: + if is_windows: + print("Camera is supported only on Linux") + exit(-1) + camera_cfg = """ --device '{"driver": "vfio-user-pci","socket": {"path": "/tmp/qemu-device-camera.sock", "type": "unix"}}'""" + +# Note +# Hot-plug / Hot-unplug in QEMU monitor: +# (qemu) chardev-add socket,host=127.0.0.1,port=4323,server=on,wait=off,telnet=on,id=console2 +# (qemu) device_add virtserialport,chardev=console2,name=org.rt-thread.port,id=port2 +# (qemu) device_del port2 +# (qemu) chardev-remove console2 +# +# VirtIO version disable legacy to set version >= 1.0: +# -global virtio-mmio.force-legacy=false +# +# VirtIO used virtqueue packed (version >= 1.0) +# -device virtio-XYZ-device,packed=on +# +# VirtIO used PCI/PCIe bus (version >= 1.0) +# -device virtio-XYZ-pci,disable-legacy=on + +cmd_base = """ +{}qemu-system-aarch64 \ + -M virt,acpi=on,its=on,gic-version={}{}{} \ + -cpu max \ + -smp {} \ + -m {} \ + -kernel rtthread.bin \ + -append "{}" \ + {} \ + {} \ + -serial mon:stdio \ + {} \ + {} \ + -drive if=none,file={}.qcow2,format=qcow2,id=blk0 \ + -device virtio-blk-device,drive=blk0 \ + -netdev {},id=net0 \ + -device virtio-net-device,netdev=net0,speed=800000 \ + -device virtio-rng-device \ + -device virtio-scsi-pci,disable-legacy=on \ + -device scsi-hd,channel=0,scsi-id=0,lun=0,drive=scsi0 \ + -drive file={}.qcow2,format=qcow2,if=none,id=scsi0 \ + {} \ + {} \ + -device virtio-crypto-device,cryptodev=vcrypto0 \ + -object cryptodev-backend-builtin,id=vcrypto0 \ + -device virtio-serial-device \ + -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 \ + -device virtserialport,chardev=console0,name=org.rt-thread.console \ + -drive if=pflash,file={}.qcow2,format=qcow2,index=1 \ + -device pci-serial,chardev=console1 \ + -chardev socket,host=127.0.0.1,port=4322,server=on,wait=off,telnet=on,id=console1 \ + -device sdhci-pci -device sd-card,drive=emmc0 \ + -drive if=none,file={}.qcow2,format=qcow2,id=emmc0 \ + -device nvme,id=nvme-ctrl-0,serial=deadbeef \ + -drive if=none,file={}.qcow2,format=qcow2,id=nvme0 \ + -device nvme-ns,drive=nvme0 \ + -device ahci,id=ahci-ctrl-0 \ + -drive if=none,file={}.qcow2,format=qcow2,id=ahci0 \ + -device ide-hd,drive=ahci0 \ + -device i6300esb -watchdog-action reset \ + {} \ + {} \ + {} \ + -device edu,dma_mask=0xffffffff +""" +def cmd(): + return cmd_base.format(RTT_QEMU_ROOT, q_gic, q_dumpdtb, q_el, q_smp, q_mem, q_bootargs, q_dtb, q_initrd, + q_graphic, q_debug, q_block, q_net, q_scsi, cdrom_cfg, virtfs_cfg, + q_flash, q_emmc, q_nvme, q_ahci, ufs_cfg, camera_cfg, amp_cfg) + +def dumpdtb(): + dtb = q_dumpdtb.split('=')[-1] + dtc.dtb_to_dts(RTT_ROOT, dtb) + +if len(q_camera) > 0: + shell = os.environ.get('SHELL', '/bin/bash') + os.system("{} ./qemu-device-camera.c {} &".format(shell, q_camera)) + + import time + start_time = time.time() + while not os.path.exists("/tmp/qemu-device-camera.sock"): + if time.time() - start_time > 5: + print("qemu-device-camera timeout") + exit(-1) + time.sleep(1) + +if len(q_dtbo) > 0: + amp_mode = False + q_bootargs = "rpmsg.mode=master " + q_bootargs + # Read all dtbo + with open("qemu.run.dtsi", 'w') as run_dtsi: + for dtsi in q_dtbo: + with open(dtsi) as dtsi: + dts_content = dtsi.read() + if not amp_mode and len(re.findall('amp_soc', dts_content)) > 0: + amp_cfg += " -device loader,file=amp.dtb,addr={}".format(re.findall(r'dtb-entry\s*=\s*<(\S+)>;', dts_content)[0]) + amp_cfg += " -device loader,file=rtthread.bin,addr={}".format(re.findall(r'kernel-entry\s*=\s*<(\S+)>;', dts_content)[0]) + q_smp += 1 + amp_mode = True + run_dtsi.write(dts_content) + # Add Console for AMP + amp_cfg += " -serial telnet:localhost:4323,server,nowait" + # Add Storage for AMP + q_amp_block = q_block + ".amp.qcow2" + if not os.path.exists(q_amp_block): + shutil.copyfile(q_block + ".qcow2", q_amp_block) + amp_cfg += " -drive if=none,file={},format=qcow2,id=blk1 -device virtio-blk-device,drive=blk1".format(q_amp_block) + # Keep vda0 is root + cmd_base = cmd_base.replace(",drive=blk0", ",drive=blk0,bus=virtio-mmio-bus.0") + # Build AMP dtb + with open("amp.dt.h", 'w') as gic_inc: + gic_inc.write("#define GIC_VERSION {}\n\r".format(q_gic)) + gic_inc.write("#define CPU_ID {}\n\r".format(q_smp - 1)) + dtc.dts_to_dtb(RTT_ROOT, ["amp.dts"], ignore_warning = ["simple_bus_reg", "unit_address_vs_reg", "clocks_is_cell", "gpios_property"]) + os.remove("amp.dt.h") + # Dump raw QEMU dts + q_dumpdtb = ",dumpdtb=qemu.run.dtb" + os.system(cmd()) + dumpdtb() + os.remove("qemu.run.dtb") + q_dumpdtb = "" + # Merge all dtsi + with open("qemu.run.dts", 'a') as dts: + with open("qemu.run.dtsi", 'r') as dtsi: + dts.write(dtsi.read()) + os.remove("qemu.run.dtsi") + # Build runtime dtb + dtc.dts_to_dtb(RTT_ROOT, ["qemu.run.dts"], ignore_warning = ["simple_bus_reg", "unit_address_vs_reg", "clocks_is_cell", "gpios_property"]) + os.remove("qemu.run.dts") + # Run QEMU + q_dtb = "-dtb qemu.run.dtb" + os.system(cmd()) + os.remove("amp.dtb") + os.remove("qemu.run.dtb") +else: + os.system(cmd()) + + if len(q_dumpdtb) != 0: + dumpdtb() + +if len(q_camera) > 0: + os.system("kill -15 `pidof qemu-device-camera`") diff --git a/bsp/qemu-virt64-aarch64/qemu.sh b/bsp/qemu-virt64-aarch64/qemu.sh deleted file mode 100755 index 4f07acaad4..0000000000 --- a/bsp/qemu-virt64-aarch64/qemu.sh +++ /dev/null @@ -1,8 +0,0 @@ -if [ ! -f "sd.bin" ]; then -dd if=/dev/zero of=sd.bin bs=1024 count=65536 -mkfs.fat sd.bin -fi -qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -m 128M -smp 4 -kernel rtthread.bin -nographic \ --drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0 \ --netdev user,id=net0 -device virtio-net-device,netdev=net0,bus=virtio-mmio-bus.1 \ --device virtio-serial-device -chardev socket,host=127.0.0.1,port=4321,server=on,wait=off,telnet=on,id=console0 -device virtserialport,chardev=console0 diff --git a/bsp/qemu-virt64-aarch64/rtconfig.h b/bsp/qemu-virt64-aarch64/rtconfig.h index ef33e3ed82..9de8955219 100644 --- a/bsp/qemu-virt64-aarch64/rtconfig.h +++ b/bsp/qemu-virt64-aarch64/rtconfig.h @@ -7,17 +7,6 @@ /* rt_vsnprintf options */ -#define RT_KLIBC_USING_VSNPRINTF_LONGLONG -#define RT_KLIBC_USING_VSNPRINTF_STANDARD -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS -#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER -#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32 -#define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6 -#define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 -#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4 /* end of rt_vsnprintf options */ /* rt_vsscanf options */ @@ -198,6 +187,7 @@ #define RT_DFS_ELM_MUTEX_TIMEOUT 3000 /* end of elm-chan's FatFs, Generic FAT Filesystem Module */ #define RT_USING_DFS_DEVFS +#define RT_USING_DFS_9PFS #define RT_USING_DFS_ROMFS /* end of DFS: device virtual file system */ @@ -214,30 +204,106 @@ #define RT_USING_SERIAL_V1 #define RT_SERIAL_USING_DMA #define RT_SERIAL_RB_BUFSZ 256 +#define RT_SERIAL_PL011 +#define RT_SERIAL_8250 +#define RT_SERIAL_8250_PCI #define RT_USING_CLOCK_TIME +#define RT_CLOCK_TIME_ARM_ARCH #define RT_USING_NULL #define RT_USING_ZERO #define RT_USING_RANDOM -#define RT_USING_PM -#define PM_TICKLESS_THRESHOLD_TIME 2 +#define RT_USING_MTD_NOR +#define RT_USING_MTD_NOR_CFI #define RT_USING_RTC -#define RT_USING_SOFT_RTC +#define RT_USING_ALARM +#define RT_ALARM_STACK_SIZE 8192 +#define RT_ALARM_TIMESLICE 5 +#define RT_ALARM_PRIORITY 10 +#define RT_RTC_PL031 +#define RT_USING_WDT +#define RT_WDT_I6300ESB +#define RT_USING_LCD +#define RT_USING_GRAPHIC +#define RT_GRAPHIC_FB +#define RT_GRAPHIC_LOGO +#define RT_GRAPHIC_LOGO_RT_THREAD_CLUT224 +#define RT_USING_HWCRYPTO +#define RT_HWCRYPTO_DEFAULT_NAME "hwcryto" +#define RT_HWCRYPTO_IV_MAX_SIZE 16 +#define RT_HWCRYPTO_KEYBIT_MAX_SIZE 256 +#define RT_HWCRYPTO_USING_AES +#define RT_HWCRYPTO_USING_AES_ECB +#define RT_HWCRYPTO_USING_AES_CBC +#define RT_HWCRYPTO_USING_AES_CTR +#define RT_HWCRYPTO_USING_DES +#define RT_HWCRYPTO_USING_DES_ECB +#define RT_HWCRYPTO_USING_DES_CBC +#define RT_HWCRYPTO_USING_3DES +#define RT_HWCRYPTO_USING_3DES_ECB +#define RT_HWCRYPTO_USING_3DES_CBC +#define RT_HWCRYPTO_USING_RC4 +#define RT_HWCRYPTO_USING_RNG +#define RT_USING_INPUT +#define RT_INPUT_POWER +#define RT_INPUT_KEYBOARD +#define RT_INPUT_KEYBOARD_GPIO +#define RT_USING_ATA +#define RT_ATA_AHCI +#define RT_ATA_AHCI_PCI +#define RT_USING_BLK + +/* Partition Types */ + +#define RT_BLK_PARTITION_DFS +#define RT_BLK_PARTITION_EFI +/* end of Partition Types */ +#define RT_USING_SCSI +#define RT_SCSI_SD +#define RT_SCSI_CDROM +#define RT_USING_FIRMWARE +#define RT_FIRMWARE_QEMU_FW_CFG +#define RT_USING_REGULATOR /* Power Management (PM) Domains device drivers */ /* end of Power Management (PM) Domains device drivers */ #define RT_USING_VIRTIO -#define RT_USING_VIRTIO10 -#define RT_USING_VIRTIO_MMIO_ALIGN -#define RT_USING_VIRTIO_BLK -#define RT_USING_VIRTIO_CONSOLE -#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4 -#define RT_USING_VIRTIO_GPU -#define RT_USING_VIRTIO_INPUT +#define RT_VIRTIO_TRANSPORT_MMIO +#define RT_VIRTIO_TRANSPORT_PCI +#define RT_VIRTIO_BLK +#define RT_VIRTIO_CONSOLE +#define RT_VIRTIO_RNG +#define RT_VIRTIO_SCSI +#define RT_VIRTIO_RPROC_SERIAL +#define RT_VIRTIO_GPU +#define RT_VIRTIO_CRYPTO +#define RT_USING_DMA +#define RT_USING_MFD +#define RT_MFD_EDU +#define RT_MFD_SYSCON #define RT_USING_OFW #define RT_FDT_EARLYCON_MSG_SIZE 128 #define RT_USING_OFW_BUS_RANGES_NUMBER 8 +#define RT_USING_PCI +#define RT_PCI_MSI +#define RT_PCI_SYS_64BIT +#define RT_PCI_CACHE_LINE_SIZE 8 + +/* PCI Device Drivers */ + +#define RT_PCI_ECAM +#define RT_PCI_HOST_COMMON +#define RT_PCI_HOST_GENERIC +#define RT_USING_PIC +#define MAX_HANDLERS 512 +#define RT_PIC_ARM_GIC +#define RT_PIC_ARM_GIC_V2M +#define RT_PIC_ARM_GIC_V3 +#define RT_PIC_ARM_GIC_V3_ITS +#define RT_PIC_ARM_GIC_V3_ITS_IRQ_MAX 127 +#define RT_PIC_ARM_GIC_MAX_NR 1 #define RT_USING_PIN +#define RT_PIN_PL061 #define RT_USING_CLK /* SoC (System on Chip) Drivers */ @@ -528,19 +594,4 @@ /* end of RT-Thread online packages */ #define SOC_VIRT64_AARCH64 -/* AARCH64 qemu virt64 configs */ - -#define BSP_SUPPORT_FPU -#define BSP_USING_UART -#define RT_USING_UART0 -#define BSP_USING_RTC -#define BSP_USING_PIN -#define BSP_USING_VIRTIO_BLK -#define BSP_USING_VIRTIO_CONSOLE -#define BSP_USING_VIRTIO_GPU -#define BSP_USING_VIRTIO_INPUT -#define BSP_USING_GIC -#define BSP_USING_GICV2 -/* end of AARCH64 qemu virt64 configs */ - #endif diff --git a/components/drivers/rpmsg/Kconfig b/components/drivers/rpmsg/Kconfig index 4d886af13c..2833208880 100755 --- a/components/drivers/rpmsg/Kconfig +++ b/components/drivers/rpmsg/Kconfig @@ -14,6 +14,12 @@ config RT_RPMSG_CHAR_MSG_SIZE_MAX depends on RT_USING_RPMSG default 256 +config RT_RPMSG_RT_THREAD_VIRTIO + bool "RT-Thread common VirtIO RPMSG" + depends on RT_USING_RPMSG + select RT_USING_SLAB + default y + if RT_USING_RPMSG osource "$(SOC_DM_RPMSG_DIR)/Kconfig" endif diff --git a/components/drivers/rpmsg/SConscript b/components/drivers/rpmsg/SConscript index a328d68ea3..370f2d8892 100755 --- a/components/drivers/rpmsg/SConscript +++ b/components/drivers/rpmsg/SConscript @@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include'] src = ['rpmsg.c', 'rpmsg_char.c', 'rpmsg_ns.c'] +if GetDepend(['RT_RPMSG_RT_THREAD_VIRTIO']): + src += ['rpmsg-rt-thread-virtio.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/rpmsg/rpmsg-rt-thread-virtio.c b/components/drivers/rpmsg/rpmsg-rt-thread-virtio.c new file mode 100644 index 0000000000..cae8234f66 --- /dev/null +++ b/components/drivers/rpmsg/rpmsg-rt-thread-virtio.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#include +#include + +#include + +#define DBG_TAG "rpmsg.rt-thread.virtio" +#define DBG_LVL DBG_INFO +#include + +#include "../virtio/virtio_config/virtio-rpmsg.h" +#include "../virtio/virtio_internal.h" + +/* + * RPMsg virtio AMP device driver + * + * The AMP OS device(s) may be instantiated in one of three equivalent way: + * + * Device Tree node, eg.: + * + * rpmsg_virtio_master { + * compatible = "rt-thread,virtio-rpmsg"; + * shmem = <&soc_sram>; + * mboxes = <&soc_mailbox 0>; + * queue-max = <64>; + * master; + * } + * + * rpmsg_virtio_slave { + * compatible = "rt-thread,virtio-rpmsg"; + * shmem = <&soc_sram>; + * mboxes = <&soc_mailbox 1>; + * queue-max = <64>; + * slave; + * } + * + * The property "queue-max" must be equal. + */ + +#define RPMSG_VIRTIO_REG_MASTER_QUEUE_DESC 0x00 /* Virtual queue's master TX descriptor Area offset from share memory */ +#define RPMSG_VIRTIO_REG_MASTER_QUEUE_AVAIL 0x04 /* Virtual queue's master TX available Ring (Driver Area) offset from share memory */ +#define RPMSG_VIRTIO_REG_MASTER_QUEUE_USED 0x08 /* Virtual queue's master TX used Ring (Device Area) offset from share memory */ +#define RPMSG_VIRTIO_REG_SLAVE_QUEUE_DESC 0x0c /* ... slave TX ... */ +#define RPMSG_VIRTIO_REG_SLAVE_QUEUE_AVAIL 0x10 /* ... slave TX ... */ +#define RPMSG_VIRTIO_REG_SLAVE_QUEUE_USED 0x14 /* ... slave TX ... */ + +#define RPMSG_VIRTIO_EVENT_LINK RT_BIT(0) +#define RPMSG_VIRTIO_EVENT_QUEUE RT_BIT(1) + +typedef rt_uint32_t rpmsg_dma_tag; + +struct rpmsg_virtio +{ + struct rt_virtio_device parent; + struct rt_mbox_client mbox_client; + + rt_bool_t is_master; + rt_uint8_t status; + rt_uint32_t queue_max; + + void *shmem; + void *regs; + struct rt_mbox_chan *chan; + + void *pool; + rt_slab_t slab; + + rt_uint16_t next_idx; + struct virtq rx_virtq, peer_tx_virtq; + + struct rt_spinlock spinlock; +}; + +#define raw_to_rpmsg_virtio(raw) rt_container_of(raw, struct rpmsg_virtio, parent) + +#define rpmsg_virtio_readl(rv, name) \ + rt_le32_to_cpu(HWREG32((rv)->regs + RPMSG_VIRTIO_REG_##name)) +#define rpmsg_virtio_writel(rv, name, value) \ + HWREG32((rv)->regs + RPMSG_VIRTIO_REG_##name) = rt_cpu_to_le32(value) + +static void rpmsg_virtio_rx_callback(struct rt_mbox_client *client, void *data) +{ + rt_ubase_t level; + rt_uint16_t idx_inc = 0; + rt_uint32_t *event = data; + struct rt_virtqueue *vq; + struct rt_virtio_device *vdev; + struct virtq *rx_virtq, *tx_virtq; + struct rpmsg_virtio *rv = rt_container_of(client, struct rpmsg_virtio, mbox_client); + + if (*event & RPMSG_VIRTIO_EVENT_LINK) + { + rt_ubase_t desc, avail, used; + + if (rv->is_master) + { + desc = rpmsg_virtio_readl(rv, SLAVE_QUEUE_DESC); + avail = rpmsg_virtio_readl(rv, SLAVE_QUEUE_AVAIL); + used = rpmsg_virtio_readl(rv, SLAVE_QUEUE_USED); + } + else + { + desc = rpmsg_virtio_readl(rv, MASTER_QUEUE_DESC); + avail = rpmsg_virtio_readl(rv, MASTER_QUEUE_AVAIL); + used = rpmsg_virtio_readl(rv, MASTER_QUEUE_USED); + } + + rv->peer_tx_virtq.desc = (void *)rv->shmem + desc; + rv->peer_tx_virtq.avail = (void *)rv->shmem + avail; + rv->peer_tx_virtq.used = (void *)rv->shmem + used; + rv->next_idx = 0; + } + + rx_virtq = &rv->rx_virtq; + tx_virtq = &rv->peer_tx_virtq; + vdev = &rv->parent; + + /* Process local RX queue */ + while (tx_virtq->avail && rv->next_idx != tx_virtq->avail->idx) + { + rt_uint16_t tx_idx, rx_idx, tx_used_idx, rx_used_idx; + struct virtq_desc *tx_desc, *rx_desc; + + tx_idx = virtio16_to_cpu(vdev, tx_virtq->avail->ring[rv->next_idx % tx_virtq->num]); + rx_idx = virtio16_to_cpu(vdev, rx_virtq->avail->ring[rv->next_idx % rx_virtq->num]); + tx_used_idx = virtio16_to_cpu(vdev, tx_virtq->used->idx) % tx_virtq->num; + rx_used_idx = virtio16_to_cpu(vdev, rx_virtq->used->idx) % rx_virtq->num; + rt_hw_rmb(); + + tx_desc = &tx_virtq->desc[tx_idx]; + rx_desc = &rx_virtq->desc[rx_idx]; + + *(rpmsg_dma_tag *)(rv->shmem + + virtio64_to_cpu(vdev, rx_desc->addr) + + virtio32_to_cpu(vdev, rx_desc->len)) = virtio64_to_cpu(vdev, tx_desc->addr); + + tx_virtq->used->ring[tx_used_idx].id = tx_idx; + tx_virtq->used->ring[tx_used_idx].len = cpu_to_virtio32(vdev, 0); + rx_virtq->used->ring[rx_used_idx].id = rx_idx; + rx_virtq->used->ring[rx_used_idx].len = rx_virtq->desc[rx_idx].len; + + ++rx_virtq->used->idx; + ++rv->next_idx; + ++idx_inc; + rt_hw_wmb(); + } + + if (*event & RPMSG_VIRTIO_EVENT_QUEUE) + { + level = rt_spin_lock_irqsave(&rv->spinlock); + + rt_list_for_each_entry(vq, &rv->parent.vq_node, list) + { + rt_virtqueue_isr(vq->index, vq); + } + + rt_spin_unlock_irqrestore(&rv->spinlock, level); + } + + /* Process peer TX queue */ + if (idx_inc) + { + tx_virtq->used->idx += cpu_to_virtio16(vdev, idx_inc); + rt_hw_wmb(); + } +} + +static rt_bool_t rpmsg_virtio_notify(struct rt_virtqueue *vq) +{ + rt_uint32_t event; + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vq->vdev); + + event = RPMSG_VIRTIO_EVENT_QUEUE; + rt_mbox_send(rv->chan, &event, RT_WAITING_FOREVER); + + return RT_TRUE; +} + +static rt_err_t rpmsg_virtio_get_status(struct rt_virtio_device *vdev, + rt_uint8_t *out_status) +{ + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + *out_status = rv->status; + + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_set_status(struct rt_virtio_device *vdev, + rt_uint8_t status) +{ + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + rv->status = status; + + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_get_features(struct rt_virtio_device *vdev, + rt_uint64_t *out_features) +{ + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + *out_features = RT_BIT_ULL(VIRTIO_F_VERSION_1) | RT_BIT_ULL(VIRTIO_F_ANY_LAYOUT); + + if (rv->is_master) + { + *out_features |= RT_BIT_ULL(VIRTIO_RPMSG_F_NS); + } + + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_set_features(struct rt_virtio_device *vdev) +{ + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_get_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, void *dst, int length) +{ + return -RT_ENOSYS; +} + +static rt_err_t rpmsg_virtio_set_config(struct rt_virtio_device *vdev, + rt_uint32_t offset, const void *src, int length) +{ + return -RT_ENOSYS; +} + +static rt_err_t rpmsg_virtio_install_vqs(struct rt_virtio_device *vdev, int vqs_nr, + struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]) +{ + rt_uint32_t event; + struct rt_virtqueue *vq; + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + if (vqs_nr != 2) + { + return -RT_EINVAL; + } + + /* Master TX or slave RX */ + vq = rt_virtqueue_create(vdev, names[0], 0, rv->queue_max, ARCH_PAGE_SIZE, + rpmsg_virtio_notify, cbs[0], RT_NULL); + + if (!vq) + { + goto _fail; + } + vqs[0] = vq; + + /* Master RX or slave TX */ + vq = rt_virtqueue_create(vdev, names[1], 1, rv->queue_max, ARCH_PAGE_SIZE, + rpmsg_virtio_notify, cbs[1], RT_NULL); + + if (!vq) + { + goto _fail; + } + vqs[1] = vq; + + if (rv->is_master) + { + rv->rx_virtq.desc = (void *)rt_virtqueue_get_desc_addr(vqs[1]); + rv->rx_virtq.avail = (void *)rt_virtqueue_get_avail_addr(vqs[1]); + rv->rx_virtq.used = (void *)rt_virtqueue_get_used_addr(vqs[1]); + + rpmsg_virtio_writel(rv, MASTER_QUEUE_DESC, + (rt_ubase_t)rt_virtqueue_get_desc_addr(vqs[0]) - (rt_ubase_t)rv->shmem); + rpmsg_virtio_writel(rv, MASTER_QUEUE_AVAIL, + (rt_ubase_t)rt_virtqueue_get_avail_addr(vqs[0]) - (rt_ubase_t)rv->shmem); + rpmsg_virtio_writel(rv, MASTER_QUEUE_USED, + (rt_ubase_t)rt_virtqueue_get_used_addr(vqs[0]) - (rt_ubase_t)rv->shmem); + } + else + { + rv->rx_virtq.desc = (void *)rt_virtqueue_get_desc_addr(vqs[0]); + rv->rx_virtq.avail = (void *)rt_virtqueue_get_avail_addr(vqs[0]); + rv->rx_virtq.used = (void *)rt_virtqueue_get_used_addr(vqs[0]); + + rpmsg_virtio_writel(rv, SLAVE_QUEUE_DESC, + (rt_ubase_t)rt_virtqueue_get_desc_addr(vqs[1]) - (rt_ubase_t)rv->shmem); + rpmsg_virtio_writel(rv, SLAVE_QUEUE_AVAIL, + (rt_ubase_t)rt_virtqueue_get_avail_addr(vqs[1]) - (rt_ubase_t)rv->shmem); + rpmsg_virtio_writel(rv, SLAVE_QUEUE_USED, + (rt_ubase_t)rt_virtqueue_get_used_addr(vqs[1]) - (rt_ubase_t)rv->shmem); + + rv->peer_tx_virtq.desc = (void *)rv->shmem + rpmsg_virtio_readl(rv, MASTER_QUEUE_DESC); + rv->peer_tx_virtq.avail = (void *)rv->shmem + rpmsg_virtio_readl(rv, MASTER_QUEUE_AVAIL); + rv->peer_tx_virtq.used = (void *)rv->shmem + rpmsg_virtio_readl(rv, MASTER_QUEUE_USED); + } + rv->rx_virtq.num = rv->queue_max; + rv->peer_tx_virtq.num = rv->queue_max; + + /* Ask peer to link */ + event = RPMSG_VIRTIO_EVENT_LINK; + rt_mbox_send(rv->chan, &event, RT_WAITING_FOREVER); + + return RT_EOK; + +_fail: + rt_virtio_virtqueue_release(vdev); + + return -RT_ERROR; +} + +static rt_err_t rpmsg_virtio_release_vqs(struct rt_virtio_device *vdev) +{ + struct rt_virtqueue *vq, *vq_next; + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + rt_list_for_each_entry_safe(vq, vq_next, &rv->parent.vq_node, list) + { + rt_virtqueue_delete(&rv->parent, vq); + } + + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_control_vqs(struct rt_virtio_device *vdev, + rt_uint32_t cfg, void *data) +{ + return -RT_ENOSYS; +} + +static rt_err_t rpmsg_virtio_generation(struct rt_virtio_device *vdev, + rt_uint32_t *out_counter) +{ + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_reset(struct rt_virtio_device *vdev) +{ + struct rpmsg_virtio *rv = raw_to_rpmsg_virtio(vdev); + + rv->status = 0; + + return RT_EOK; +} + +static const struct rt_virtio_transport rpmsg_virtio_trans = +{ + .get_status = rpmsg_virtio_get_status, + .set_status = rpmsg_virtio_set_status, + .get_features = rpmsg_virtio_get_features, + .set_features = rpmsg_virtio_set_features, + .get_config = rpmsg_virtio_get_config, + .set_config = rpmsg_virtio_set_config, + .install_vqs = rpmsg_virtio_install_vqs, + .release_vqs = rpmsg_virtio_release_vqs, + .control_vqs = rpmsg_virtio_control_vqs, + .generation = rpmsg_virtio_generation, + .reset = rpmsg_virtio_reset, +}; + +static void *rpmsg_virtio_dma_alloc(struct rt_device *dev, rt_size_t size, + rt_ubase_t *dma_handle, rt_ubase_t flags) +{ + void *dma_buffer; + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); + struct rpmsg_virtio *rv = rt_container_of(vdev, struct rpmsg_virtio, parent); + + /* Ignore flags */ + if (!(dma_buffer = rt_slab_alloc(rv->slab, size))) + { + return dma_buffer; + } + + if (dma_handle) + { + *dma_handle = (rt_ubase_t)(dma_buffer - rv->shmem); + } + + return dma_buffer; +} + +static void rpmsg_virtio_dma_free(struct rt_device *dev, rt_size_t size, + void *cpu_addr, rt_ubase_t dma_handle, rt_ubase_t flags) +{ + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); + struct rpmsg_virtio *rv = rt_container_of(vdev, struct rpmsg_virtio, parent); + + rt_slab_free(rv->slab, cpu_addr); +} + +static rt_err_t rpmsg_virtio_dma_sync_out_data(struct rt_device *dev, + void *data, rt_size_t size, rt_ubase_t *dma_handle, rt_ubase_t flags) +{ + void *dma_buffer; + + dma_buffer = rpmsg_virtio_dma_alloc(dev, size + sizeof(rpmsg_dma_tag), dma_handle, flags); + + if (!dma_buffer) + { + return -RT_ENOMEM; + } + + rt_memcpy(dma_buffer, data, size); + + return RT_EOK; +} + +static rt_err_t rpmsg_virtio_dma_sync_in_data(struct rt_device *dev, + void *out_data, rt_size_t size, rt_ubase_t dma_handle, rt_ubase_t flags) +{ + void *dma_buffer; + rpmsg_dma_tag dma_tag; + struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent); + struct rpmsg_virtio *rv = rt_container_of(vdev, struct rpmsg_virtio, parent); + + dma_buffer = rv->shmem + dma_handle; + dma_tag = *(rpmsg_dma_tag *)(dma_buffer + size); + + rt_memcpy(out_data, rv->shmem + dma_tag, size); + + size += sizeof(rpmsg_dma_tag); + rpmsg_virtio_dma_free(dev, size, dma_buffer, dma_handle, flags); + + return RT_EOK; +} + +static const struct rt_dma_map_ops rpmsg_virtio_dma_ops = +{ + .alloc = rpmsg_virtio_dma_alloc, + .free = rpmsg_virtio_dma_free, + .sync_out_data = rpmsg_virtio_dma_sync_out_data, + .sync_in_data = rpmsg_virtio_dma_sync_in_data, +}; + +static rt_err_t rpmsg_virtio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint64_t addr, size; + struct rt_ofw_node *shmem_np; + struct rt_virtio_device *vdev; + struct rt_device *dev = &pdev->parent; + struct rpmsg_virtio *rv = rt_calloc(1, sizeof(*rv)); + + if (!rv) + { + return -RT_ENOMEM; + } + + rv->mbox_client.dev = dev; + rv->mbox_client.rx_callback = rpmsg_virtio_rx_callback; + + rv->chan = rt_mbox_request_by_index(&rv->mbox_client, 0); + + if (rt_is_err_or_null(rv->chan)) + { + err = -RT_EINVAL; + LOG_E("Request mailbox fail"); + + goto _fail; + } + + vdev = &rv->parent; + + if ((err = rt_dm_dev_prop_read_u32(dev, "queue-max", &rv->queue_max))) + { + goto _fail; + } + + shmem_np = rt_ofw_parse_phandle(dev->ofw_node, "shmem", 0); + rt_ofw_get_address(shmem_np, 0, &addr, &size); + rt_ofw_node_put(shmem_np); + + rv->shmem = rt_ioremap_cached((void *)addr, size); + + if (!rv->shmem) + { + err = -RT_EIO; + goto _fail; + } + + rv->is_master = rt_dm_dev_prop_read_bool(dev, "master"); + rv->regs = rv->shmem; + rv->pool = rv->shmem + ARCH_PAGE_SIZE; + + size = (size - ARCH_PAGE_SIZE) >> 1; + + if (!rv->is_master) + { + rv->pool += size; + } + + if (!(rv->slab = rt_slab_init(rt_dm_dev_get_name(dev), rv->pool, size))) + { + LOG_E("Create AMP dma pool fail"); + + err = -RT_ENOMEM; + goto _fail; + } + rt_dma_device_set_ops(&vdev->parent, &rpmsg_virtio_dma_ops); + vdev->dma_dispatch = RT_TRUE; + + rt_spin_lock_init(&rv->spinlock); + + vdev->id.device = VIRTIO_DEVICE_ID_RPMSG; + vdev->id.vendor = 0x534f5452; /* RTOS */ + vdev->trans = &rpmsg_virtio_trans; + vdev->parent.ofw_node = dev->ofw_node; + + if ((err = rt_virtio_device_register(vdev))) + { + goto _fail; + } + + dev->user_data = rv; + + return RT_EOK; + +_fail: + if (!rt_is_err_or_null(rv->chan)) + { + rt_mbox_release(rv->chan); + } + if (rv->shmem) + { + rt_iounmap(rv->shmem); + } + rt_free(rv); + + return err; +} + +static rt_err_t rpmsg_virtio_remove(struct rt_platform_device *pdev) +{ + struct rpmsg_virtio *rv = pdev->parent.user_data; + + rt_bus_remove_device(&rv->parent.parent); + + rt_slab_detach(rv->slab); + rt_mbox_release(rv->chan); + rt_iounmap(rv->shmem); + rt_free(rv); + + return RT_EOK; +} + +static const struct rt_ofw_node_id rpmsg_virtio_ofw_ids[] = +{ + { .compatible = "rt-thread,virtio-rpmsg" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver rpmsg_virtio_driver = +{ + .name = "rt-thread-virtio-rpmsg", + .ids = rpmsg_virtio_ofw_ids, + + .probe = rpmsg_virtio_probe, + .remove = rpmsg_virtio_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(rpmsg_virtio_driver);