未验证 提交 f587a55b 编写于 作者: G GUI 提交者: GitHub

[libcpu/aarch64] add gicv3 support and bsp/rockchip/rk3568 (#5722)

* [libcpu/aarch64] add smp support

* [libcpu/aarch64] rt_hw_trap_irq get irq instead of iar when using gicv2

* [libcpu/aarch64] disable irq/fiq when switch thread

* [libcpu/aarch64] add gtimer frq set and stack align

* [libcpu/aarch64] add gicv3 support and bsp/rockchip/rk3568
上级 d23493d0
......@@ -167,6 +167,7 @@ jobs:
- {RTT_BSP: "qemu-virt64-aarch64", RTT_TOOL_CHAIN: "sourcery-aarch64"}
- {RTT_BSP: "raspberry-pi/raspi3-64", RTT_TOOL_CHAIN: "sourcery-aarch64"}
- {RTT_BSP: "raspberry-pi/raspi4-64", RTT_TOOL_CHAIN: "sourcery-aarch64"}
- {RTT_BSP: "rockchip/rk3568", RTT_TOOL_CHAIN: "sourcery-aarch64"}
steps:
- uses: actions/checkout@v2
- name: Set up Python
......
......@@ -96,17 +96,8 @@ CONFIG_RT_USING_USER_MAIN=y
CONFIG_RT_MAIN_THREAD_STACK_SIZE=8192
CONFIG_RT_MAIN_THREAD_PRIORITY=10
# CONFIG_RT_USING_LEGACY is not set
#
# C++ features
#
# CONFIG_RT_USING_CPLUSPLUS is not set
#
# Command shell
#
CONFIG_RT_USING_FINSH=y
CONFIG_RT_USING_MSH=y
CONFIG_RT_USING_FINSH=y
CONFIG_FINSH_USING_MSH=y
CONFIG_FINSH_THREAD_NAME="tshell"
CONFIG_FINSH_THREAD_PRIORITY=20
......@@ -120,10 +111,6 @@ CONFIG_FINSH_USING_DESCRIPTION=y
# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
# CONFIG_FINSH_USING_AUTH is not set
CONFIG_FINSH_ARG_MAX=10
#
# Device virtual file system
#
CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_POSIX=y
CONFIG_DFS_USING_WORKDIR=y
......@@ -157,12 +144,15 @@ CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000
CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_FAL is not set
#
# Device Drivers
#
CONFIG_RT_USING_DEVICE_IPC=y
# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=2048
CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
CONFIG_RT_USING_SERIAL=y
CONFIG_RT_USING_SERIAL_V1=y
# CONFIG_RT_USING_SERIAL_V2 is not set
......@@ -202,7 +192,7 @@ CONFIG_RT_USING_ALARM=y
# CONFIG_RT_USING_USB_DEVICE is not set
#
# POSIX layer and C standard library
# C/C++ and POSIX layer
#
CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
......@@ -226,36 +216,16 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
#
# Socket is in the 'Network' category
#
# CONFIG_RT_USING_CPLUSPLUS is not set
#
# Network
#
#
# Socket abstraction layer
#
# CONFIG_RT_USING_SAL is not set
#
# Network interface device
#
# CONFIG_RT_USING_NETDEV is not set
#
# light weight TCP/IP stack
#
# CONFIG_RT_USING_LWIP is not set
#
# AT commands
#
# CONFIG_RT_USING_AT is not set
#
# VBUS(Virtual Software BUS)
#
# CONFIG_RT_USING_VBUS is not set
#
# Utilities
#
......@@ -264,6 +234,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_RT_USING_UTEST is not set
# CONFIG_RT_USING_VAR_EXPORT is not set
# CONFIG_RT_USING_RT_LINK is not set
# CONFIG_RT_USING_VBUS is not set
#
# RT-Thread Utestcases
......@@ -277,6 +248,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
#
# IoT - internet of things
#
# CONFIG_PKG_USING_LWIP is not set
# CONFIG_PKG_USING_LORAWAN_DRIVER is not set
# CONFIG_PKG_USING_PAHOMQTT is not set
# CONFIG_PKG_USING_UMQTT is not set
......@@ -293,6 +265,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_FREEMODBUS is not set
# CONFIG_PKG_USING_LJSON is not set
# CONFIG_PKG_USING_EZXML is not set
# CONFIG_PKG_USING_SIMPLE_XML is not set
# CONFIG_PKG_USING_NANOPB is not set
#
......@@ -332,6 +305,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_JOYLINK is not set
# CONFIG_PKG_USING_EZ_IOT_OS is not set
# CONFIG_PKG_USING_NIMBLE is not set
# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set
# CONFIG_PKG_USING_OTA_DOWNLOADER is not set
# CONFIG_PKG_USING_IPMSG is not set
# CONFIG_PKG_USING_LSSDP is not set
......@@ -539,7 +513,8 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_ARM_2D is not set
# CONFIG_PKG_USING_MCUBOOT is not set
# CONFIG_PKG_USING_TINYUSB is not set
# CONFIG_PKG_USING_USB_STACK is not set
# CONFIG_PKG_USING_CHERRYUSB is not set
# CONFIG_PKG_USING_KMULTI_RTIMER is not set
#
# peripheral libraries and drivers
......@@ -563,6 +538,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_WM_LIBRARIES is not set
# CONFIG_PKG_USING_KENDRYTE_SDK is not set
# CONFIG_PKG_USING_INFRARED is not set
# CONFIG_PKG_USING_MULTI_INFRARED is not set
# CONFIG_PKG_USING_AGILE_BUTTON is not set
# CONFIG_PKG_USING_AGILE_LED is not set
# CONFIG_PKG_USING_AT24CXX is not set
......@@ -619,6 +595,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_SOFT_SERIAL is not set
# CONFIG_PKG_USING_MB85RS16 is not set
# CONFIG_PKG_USING_CW2015 is not set
# CONFIG_PKG_USING_RFM300 is not set
#
# AI packages
......@@ -637,6 +614,10 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# miscellaneous packages
#
#
# project laboratory
#
#
# samples: kernel and components samples
#
......@@ -669,6 +650,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_CANFESTIVAL is not set
# CONFIG_PKG_USING_ZLIB is not set
# CONFIG_PKG_USING_MINIZIP is not set
# CONFIG_PKG_USING_HEATSHRINK is not set
# CONFIG_PKG_USING_DSTR is not set
# CONFIG_PKG_USING_TINYFRAME is not set
# CONFIG_PKG_USING_KENDRYTE_DEMO is not set
......@@ -686,6 +668,7 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
# CONFIG_PKG_USING_DESIGN_PATTERN is not set
# CONFIG_PKG_USING_CONTROLLER is not set
# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set
# CONFIG_PKG_USING_MFBD is not set
CONFIG_SOC_VIRT64_AARCH64=y
#
......@@ -696,5 +679,6 @@ CONFIG_RT_USING_UART0=y
CONFIG_BSP_USING_RTC=y
CONFIG_BSP_USING_ALARM=y
CONFIG_BSP_USING_VIRTIO_BLK=y
CONFIG_RT_USING_VIRTIO_BLK0=y
CONFIG_BSP_USING_GIC=y
CONFIG_BSP_USING_GICV2=y
# CONFIG_BSP_USING_GICV3 is not set
......@@ -19,9 +19,9 @@ Enter directory `rt-thread/bsp/qemu-virt64-aarch64` and input:
scons
```
## 2. Execution
## 3. Execution
The project execution tool is `qemu-system-aarch64`
The project execution tool is `qemu-system-aarch64`, the project can be configured to `Cortex-A53/A57/A72`, GIC supports `V2/V3` version, and `V2` of GIC can use 8 processors max.
Download Windows platform from website:
```
......@@ -33,7 +33,7 @@ sudo apt update
sudo apt install qemu-system-arm
```
Run qemu.bat or qemu.sh in terminal:
Please fixup the exec scripts if modify the default configuration of the project. Run qemu.bat or qemu.sh in terminal:
```
heap: [0x40042aa0 - 0x40142aa0]
......@@ -45,10 +45,10 @@ Hi, this is RT-Thread!!
msh />
```
## 3. Condition
## 4. Condition
| Driver | Condition | Remark |
| ------ | --------- | ------ |
| UART | Support | UART0 |
| RTC | Support | - |
| VIRTIO BLK | Support | VIRTIO BLK0 |
\ No newline at end of file
| VIRTIO BLK | Support | - |
\ No newline at end of file
......@@ -22,7 +22,7 @@ scons
## 3. 执行
本工程执行环境为`qemu-system-aarch64`模拟器
本工程执行环境为`qemu-system-aarch64`模拟器,工程可配置为使用`Cortex-A53/A57/A72`等芯片,GIC支持`V2/V3`版本,其中`V2`最多可配置8个处理器。
Windows平台下,可以在此获取到QEMU:
```
......@@ -34,7 +34,7 @@ sudo apt update
sudo apt install qemu-system-arm
```
在终端执行qemu.bat或qemu.sh可以看到程序运行:
工程默认配置修改后请注意修改运行脚本。在终端执行qemu.bat或qemu.sh可以看到程序运行:
```
heap: [0x40042aa0 - 0x40142aa0]
......@@ -52,4 +52,4 @@ msh />
| ------ | ---- | :------: |
| UART | 支持 | UART0 |
| RTC | 支持 | - |
| VIRTIO BLK | 支持 | VIRTIO BLK0 |
\ No newline at end of file
| VIRTIO BLK | 支持 | - |
\ No newline at end of file
......@@ -28,13 +28,19 @@ menu "AARCH64 qemu virt64 configs"
bool "Using VirtIO BLK"
default y
if BSP_USING_VIRTIO_BLK
config RT_USING_VIRTIO_BLK0
bool "Enabel VirtIO BLK 0"
default y
endif
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
......@@ -17,6 +17,7 @@
#include "board.h"
#include <mmu.h>
#include <gic.h>
#include <gicv3.h>
#include <psci.h>
#include <gtimer.h>
#include <cpuport.h>
......@@ -29,8 +30,14 @@ struct mem_desc platform_mem_desc[] =
{0x40000000, 0x80000000, 0x40000000, NORMAL_MEM},
{PL031_RTC_BASE, PL031_RTC_BASE + 0x1000, PL031_RTC_BASE, DEVICE_MEM},
{PL011_UART0_BASE, PL011_UART0_BASE + 0x1000, PL011_UART0_BASE, DEVICE_MEM},
{VIRTIO_MMIO_BLK0_BASE, VIRTIO_MMIO_BLK0_BASE + 0x1000, VIRTIO_MMIO_BLK0_BASE, DEVICE_MEM},
{VIRTIO_MMIO_BASE, VIRTIO_MMIO_BASE + VIRTIO_MAX_NR * VIRTIO_MMIO_SIZE, VIRTIO_MMIO_BASE, DEVICE_MEM},
#ifdef BSP_USING_GICV2
{GIC_PL390_DISTRIBUTOR_PPTR, GIC_PL390_DISTRIBUTOR_PPTR + 0x1000, GIC_PL390_DISTRIBUTOR_PPTR, DEVICE_MEM},
#endif
#ifdef BSP_USING_GICV3
{GIC_PL500_DISTRIBUTOR_PPTR, GIC_PL500_DISTRIBUTOR_PPTR + 0x1000, GIC_PL500_DISTRIBUTOR_PPTR, DEVICE_MEM},
{GIC_PL500_REDISTRIBUTOR_PPTR, GIC_PL500_REDISTRIBUTOR_PPTR + 0xf60000, GIC_PL500_REDISTRIBUTOR_PPTR, DEVICE_MEM},
#endif
};
const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc)/sizeof(platform_mem_desc[0]);
......@@ -58,7 +65,7 @@ void rt_hw_board_init(void)
rt_hw_gtimer_init();
rt_thread_idle_sethook(idle_wfi);
arm_psci_init(RT_NULL, RT_NULL);
arm_psci_init(PSCI_METHOD_HVC, RT_NULL, RT_NULL);
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
/* set console device */
......@@ -113,6 +120,9 @@ void secondary_cpu_c_start(void)
rt_hw_spin_lock(&_cpus_lock);
arm_gic_cpu_init(0, platform_get_gic_cpu_base());
#ifdef BSP_USING_GICV3
arm_gic_redist_init(0, platform_get_gic_redist_base());
#endif
rt_hw_vector_init();
rt_hw_gtimer_local_enable();
arm_gic_umask(0, IRQ_ARM_IPI_KICK);
......
......@@ -6,72 +6,18 @@
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
* 2021-07-31 GuEe-GUI add ARM GIC definitions
* 2021-09-11 GuEe-GUI rename right macros for gic
*/
#ifndef BOARD_H__
#define BOARD_H__
#include <rthw.h>
#include <rtdef.h>
#include <stdint.h>
#include <virt.h>
extern unsigned char __bss_start;
extern unsigned char __bss_end;
#define RT_HW_HEAP_BEGIN (void*)&__bss_end
#define RT_HW_HEAP_END (void*)(RT_HW_HEAP_BEGIN + 1 * 1024 * 1024)
#define __REG32(x) (*((volatile unsigned int *)(x)))
#define VIRTIO_SPI_IRQ_BASE 32
/* Virtio BLK */
#define VIRTIO_MMIO_BLK0_BASE 0x0a000000
#define VIRTIO_MMIO_BLK0_SIZE 0x00000200
#define VIRTIO_MMIO_BLK0_IRQ (VIRTIO_SPI_IRQ_BASE + 0x10)
/* UART */
#define PL011_UARTDR 0x000
#define PL011_UARTFR 0x018
#define PL011_UARTFR_TXFF_BIT 5
#define PL011_UART0_BASE 0x09000000
#define PL011_UART0_SIZE 0x00001000
#define PL011_UART0_IRQNUM (VIRTIO_SPI_IRQ_BASE + 1)
/* RTC */
#define PL031_RTC_BASE 0x9010000
#define PL031_RTC_SIZE 0x00001000
#define PL031_RTC_IRQNUM (VIRTIO_SPI_IRQ_BASE + 2)
/* DIST and CPU */
#define GIC_PL390_DISTRIBUTOR_PPTR 0x08000000
#define GIC_PL390_CONTROLLER_PPTR 0x08010000
#define MAX_HANDLERS 96
#define GIC_IRQ_START 0
/* number of interrupts on board */
#define ARM_GIC_NR_IRQS 96
/* only one GIC available */
#define ARM_GIC_MAX_NR 1
/* ipi interrupt number */
#define IRQ_ARM_IPI_KICK 0
#define IRQ_ARM_IPI_CALL 1
#define IRQ_ARM_VTIMER 27
/* the basic constants and interfaces needed by gic */
rt_inline rt_uint32_t platform_get_gic_dist_base(void)
{
return GIC_PL390_DISTRIBUTOR_PPTR;
}
rt_inline rt_uint32_t platform_get_gic_cpu_base(void)
{
return GIC_PL390_CONTROLLER_PPTR;
}
#define RT_HW_HEAP_END (void*)(RT_HW_HEAP_BEGIN + 64 * 1024 * 1024)
void rt_hw_board_init(void);
......
......@@ -14,6 +14,10 @@
#include "board.h"
#define PL011_UARTDR 0x000
#define PL011_UARTFR 0x018
#define PL011_UARTFR_TXFF_BIT 5
unsigned int readl(volatile void *addr)
{
return *(volatile unsigned int *)addr;
......
/*
* 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 <rtthread.h>
#include <virtio.h>
#ifdef BSP_USING_VIRTIO_BLK
#include <virtio_blk.h>
#endif
#include <board.h>
static virtio_device_init_handler virtio_device_init_handlers[] =
{
#ifdef BSP_USING_VIRTIO_BLK
[VIRTIO_DEVICE_ID_BLOCK] = rt_virtio_blk_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;
}
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);
/*
* 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__ */
/*
* 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 <rtdef.h>
/* 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)
/* 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
/* 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_uint32_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_uint32_t platform_get_gic_redist_base(void)
{
return GIC_PL500_REDISTRIBUTOR_PPTR;
}
rt_inline rt_uint32_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_uint32_t platform_get_gic_its_base(void)
{
return GIC_PL500_ITS_PPTR;
}
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
*/
#include <rtconfig.h>
#include <rtthread.h>
#include <rthw.h>
#include <cpuport.h>
#include <board.h>
#include "virtio.h"
#include "virtio_mmio.h"
#include "drv_virtio_blk.h"
#ifdef BSP_USING_VIRTIO_BLK
#ifdef RT_USING_VIRTIO_BLK0
static struct virtio_blk blk0;
static struct virtio_blk_device virtio_blk_dev0;
#endif /* RT_USING_VIRTIO_BLK0 */
static int alloc_desc(struct virtio_blk *blk)
{
int i;
for(i = 0; i < QUEUE_SIZE; i++)
{
if (blk->free[i])
{
blk->free[i] = 0;
return i;
}
}
return -RT_ERROR;
}
static void free_desc(struct virtio_blk *blk, int i)
{
if (i >= QUEUE_SIZE)
{
rt_kprintf("Out of queue number");
RT_ASSERT(0);
}
if (blk0.free[i])
{
rt_kprintf("Already freed");
RT_ASSERT(0);
}
blk->desc[i].addr = 0;
blk->desc[i].len = 0;
blk->desc[i].flags = 0;
blk->desc[i].next = 0;
blk->free[i] = 1;
}
static void free_chain(struct virtio_blk *blk, int i)
{
int flag, nxt;
for (;;)
{
flag = blk->desc[i].flags;
nxt = blk->desc[i].next;
free_desc(blk, i);
if (flag & VRING_DESC_F_NEXT)
{
i = nxt;
}
else
{
break;
}
}
}
static int alloc3_desc(struct virtio_blk *blk, int *idx)
{
for (int i = 0; i < 3; ++i)
{
idx[i] = alloc_desc(blk);
if (idx[i] < 0)
{
for (int j = 0; j < i; ++j)
{
free_desc(blk, idx[j]);
}
return -RT_ERROR;
}
}
return 0;
}
static int virtio_blk_device_init(struct virtio_blk_device *virtio_blk_dev)
{
uint32_t status = 0;
uint32_t max;
uint64_t features;
int i;
#ifdef RT_USING_SMP
rt_spin_lock_init(&virtio_blk_dev->spinlock);
#endif
if (virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_MAGIC_VALUE) != VIRTIO_MMIO_MAGIC ||
virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_VERSION) != 1 ||
virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_DEVICE_ID) != 2 ||
virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_VENDOR_ID) != VIRTIO_MMIO_VENDOR)
{
rt_kprintf("Could not find virtio disk");
return -RT_ERROR;
}
status |= VIRTIO_STAT_ACKNOWLEDGE;
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_STATUS, status);
status |= VIRTIO_STAT_DRIVER;
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_STATUS, status);
/* negotiate features */
features = virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_DEVICE_FEATURES);
features &= ~(1 << VIRTIO_BLK_F_RO);
features &= ~(1 << VIRTIO_BLK_F_SCSI);
features &= ~(1 << VIRTIO_BLK_F_CONFIG_WCE);
features &= ~(1 << VIRTIO_BLK_F_MQ);
features &= ~(1 << VIRTIO_F_ANY_LAYOUT);
features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_DRIVER_FEATURES, features);
/* tell device that feature negotiation is complete */
status |= VIRTIO_STAT_FEATURES_OK;
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_STATUS, status);
/* tell device we're completely ready */
status |= VIRTIO_STAT_DRIVER_OK;
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_STATUS, status);
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_GUEST_PAGE_SIZE, PAGE_SIZE);
/* initialize queue 0 */
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_QUEUE_SEL, 0);
max = virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_QUEUE_NUM_MAX);
if (max == 0)
{
rt_kprintf("Virtio disk has no queue 0");
RT_ASSERT(0);
}
if (max < QUEUE_SIZE)
{
rt_kprintf("Virtio disk max queue too short");
RT_ASSERT(0);
}
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_QUEUE_NUM, QUEUE_SIZE);
rt_memset(virtio_blk_dev->blk->pages, 0, sizeof(virtio_blk_dev->blk->pages));
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_QUEUE_PFN, ((uint64_t)blk0.pages) >> PAGE_SHIFT);
virtio_blk_dev->blk->desc = (struct virtq_desc *)virtio_blk_dev->blk->pages;
virtio_blk_dev->blk->avail = (struct virtq_avail *)(virtio_blk_dev->blk->pages + QUEUE_SIZE * sizeof(struct virtq_desc));
virtio_blk_dev->blk->used = (struct virtq_used *)(virtio_blk_dev->blk->pages + PAGE_SIZE);
/* all QUEUE_SIZE descriptors start out unused */
for (i = 0; i < QUEUE_SIZE; ++i)
{
virtio_blk_dev->blk->free[i] = 1;
}
return RT_EOK;
}
static void virtio_blk_rw(struct virtio_blk_device *virtio_blk_dev, struct virtio_blk_buf *buf, int flag)
{
struct virtio_blk *blk = virtio_blk_dev->blk;
uint64_t sector = buf->block_no * (VIRTIO_BLK_BUF_DATA_SIZE / 512);
int idx[3];
struct virtio_blk_req *req;
#ifdef RT_USING_SMP
rt_base_t level;
level = rt_spin_lock_irqsave(&virtio_blk_dev->spinlock);
#endif
/* allocate the three descriptors */
for (;;)
{
if (alloc3_desc(blk, idx) == 0)
{
break;
}
}
req = &(blk->ops[idx[0]]);
req->type = flag;
req->reserved = 0;
req->sector = sector;
blk->desc[idx[0]].addr = (uint64_t)req;
blk->desc[idx[0]].len = sizeof(struct virtio_blk_req);
blk->desc[idx[0]].flags = VRING_DESC_F_NEXT;
blk->desc[idx[0]].next = idx[1];
blk->desc[idx[1]].addr = (uint64_t)buf->data;
blk->desc[idx[1]].len = VIRTIO_BLK_BUF_DATA_SIZE;
blk->desc[idx[1]].flags = flag ? 0 : VRING_DESC_F_WRITE;
blk->desc[idx[1]].flags |= VRING_DESC_F_NEXT;
blk->desc[idx[1]].next = idx[2];
/* device writes 0 on success */
blk->info[idx[0]].status = 0xff;
blk->desc[idx[2]].addr = (uint64_t)&(blk->info[idx[0]].status);
blk->desc[idx[2]].len = 1;
/* device writes the status */
blk->desc[idx[2]].flags = VRING_DESC_F_WRITE;
blk->desc[idx[2]].next = 0;
/* record struct buf for virtio_blk_isr() */
buf->valid = 1;
blk->info[idx[0]].buf = buf;
/* tell the device the first index in our chain of descriptors */
blk->avail->ring[blk->avail->idx % QUEUE_SIZE] = idx[0];
rt_hw_dsb();
/* tell the device another avail ring entry is available */
blk->avail->idx += 1;
rt_hw_dsb();
/* value is queue number */
virtio_mmio_write32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_QUEUE_NOTIFY, 0);
/* wait for virtio_blk_isr() to done */
while (buf->valid == 1)
{
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_blk_dev->spinlock, level);
#endif
rt_thread_yield();
#ifdef RT_USING_SMP
level = rt_spin_lock_irqsave(&virtio_blk_dev->spinlock);
#endif
}
blk->info[idx[0]].buf = 0;
free_chain(blk, idx[0]);
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_blk_dev->spinlock, level);
#endif
}
static void virtio_blk_isr(int irqno, void *param)
{
int id;
struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)param;
struct virtio_blk *blk = virtio_blk_dev->blk;
struct virtio_blk_buf *buf_tmp;
#ifdef RT_USING_SMP
rt_base_t level;
level = rt_spin_lock_irqsave(&virtio_blk_dev->spinlock);
#endif
virtio_mmio_write32(
virtio_blk_dev->mmio_base,
VIRTIO_MMIO_INTERRUPT_ACK,
virtio_mmio_read32(virtio_blk_dev->mmio_base, VIRTIO_MMIO_INTERRUPT_STATUS) & 0x3);
rt_hw_dsb();
/*
* the device increments disk.used->idx
* when it adds an entry to the used ring
*/
while (blk->used_idx != blk->used->idx)
{
rt_hw_dsb();
id = blk->used->ring[blk->used_idx % QUEUE_SIZE].id;
if (blk->info[id].status != 0)
{
rt_kprintf("Virtio BLK Status");
RT_ASSERT(0);
}
buf_tmp = blk->info[id].buf;
/* done with buf */
buf_tmp->valid = 0;
rt_thread_yield();
blk->used_idx += 1;
}
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_blk_dev->spinlock, level);
#endif
}
static rt_err_t virtio_blk_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t virtio_blk_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t virtio_blk_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_size_t virtio_blk_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev;
struct virtio_blk_buf buf =
{
.block_no = (uint32_t)pos,
.data = (uint8_t *)buffer
};
virtio_blk_rw(virtio_blk_dev, &buf, VIRTIO_BLK_T_IN);
return size;
}
static rt_size_t virtio_blk_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev;
struct virtio_blk_buf buf =
{
.block_no = (uint32_t)pos,
.data = (uint8_t *)buffer
};
virtio_blk_rw(virtio_blk_dev, &buf, VIRTIO_BLK_T_OUT);
return size;
}
static rt_err_t virtio_blk_control(rt_device_t dev, int cmd, void *args)
{
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
{
struct rt_device_blk_geometry *geometry;
geometry = (struct rt_device_blk_geometry *)args;
if (geometry == RT_NULL)
{
return -RT_ERROR;
}
geometry->bytes_per_sector = VIRTIO_BLK_BYTES_PER_SECTOR;
geometry->block_size = VIRTIO_BLK_BLOCK_SIZE;
geometry->sector_count = VIRTIO_BLK_SECTOR_COUNT;
}
return RT_EOK;
}
const static struct rt_device_ops virtio_blk_ops =
{
virtio_blk_init,
virtio_blk_open,
virtio_blk_close,
virtio_blk_read,
virtio_blk_write,
virtio_blk_control
};
int rt_virtio_blk_init(void)
{
rt_err_t status = RT_EOK;
#ifdef RT_USING_VIRTIO_BLK0
virtio_blk_dev0.parent.type = RT_Device_Class_Block;
virtio_blk_dev0.parent.ops = &virtio_blk_ops;
virtio_blk_dev0.blk = &blk0;
virtio_blk_dev0.mmio_base = (uint32_t *)VIRTIO_MMIO_BLK0_BASE;
status = virtio_blk_device_init(&virtio_blk_dev0);
rt_device_register((rt_device_t)&virtio_blk_dev0, "virtio-blk0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
rt_hw_interrupt_install(VIRTIO_MMIO_BLK0_IRQ, virtio_blk_isr, &virtio_blk_dev0, "virtio-blk0");
rt_hw_interrupt_umask(VIRTIO_MMIO_BLK0_IRQ);
#endif /* RT_USING_VIRTIO_BLK0 */
return status;
}
INIT_DEVICE_EXPORT(rt_virtio_blk_init);
#endif /* BSP_USING_VIRTIO_BLK */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
*/
#ifndef DRV_VIRTIO_BLK_H__
#define DRV_VIRTIO_BLK_H__
#include <rthw.h>
#include <stdint.h>
#include "virtio.h"
#define VIRTIO_BLK_BUF_DATA_SIZE 512
#define VIRTIO_BLK_BYTES_PER_SECTOR 512
#define VIRTIO_BLK_BLOCK_SIZE 512
#define VIRTIO_BLK_SECTOR_COUNT 0x40000 /* 128MB */
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
#define VIRTIO_BLK_T_IN 0 /* Read the blk */
#define VIRTIO_BLK_T_OUT 1 /* Write the blk */
#define VIRTIO_F_ANY_LAYOUT 27
#define VIRTIO_RING_F_INDIRECT_DESC 28
#define VIRTIO_RING_F_EVENT_IDX 29
struct virtio_blk_buf
{
int valid;
uint32_t block_no;
uint8_t *data;
};
struct virtio_blk_req
{
uint32_t type;
uint32_t reserved;
uint64_t sector;
};
/*
* virtio_blk must be a static variable because
* pages must consist of two contiguous pages of
* page-aligned physical memory
*/
struct virtio_blk
{
char pages[2 * PAGE_SIZE];
struct virtq_desc *desc;
struct virtq_avail *avail;
struct virtq_used *used;
char free[QUEUE_SIZE];
uint16_t used_idx;
struct
{
struct virtio_blk_buf *buf;
char status;
} info[QUEUE_SIZE];
struct virtio_blk_req ops[QUEUE_SIZE];
} __attribute__ ((aligned (PAGE_SIZE)));
struct virtio_blk_device
{
struct rt_device parent;
struct virtio_blk *blk;
uint32_t *mmio_base;
#ifdef RT_USING_SMP
struct rt_spinlock spinlock;
#endif
};
int rt_hw_virtio_blk_init(void);
#endif /* DRV_VIRTIO_BLK_H__ */
/*
* 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 <rtthread.h>
#include <cpuport.h>
#include <virtio.h>
rt_inline void _virtio_dev_check(struct virtio_device *dev)
{
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(dev->mmio_config != RT_NULL);
}
void virtio_reset_device(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status = 0;
}
void virtio_status_acknowledge_driver(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER;
}
void virtio_status_driver_ok(struct virtio_device *dev)
{
_virtio_dev_check(dev);
dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
}
void virtio_interrupt_ack(struct virtio_device *dev, rt_uint32_t ack)
{
_virtio_dev_check(dev);
dev->mmio_config->interrupt_ack = ack;
}
rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size)
{
int i;
void *pages;
rt_ubase_t pages_paddr;
rt_size_t pages_total_size;
struct virtq *queue;
_virtio_dev_check(dev);
RT_ASSERT(dev->mmio_config->queue_num_max > 0);
RT_ASSERT(dev->mmio_config->queue_num_max > queue_index);
/* ring_size is power of 2 */
RT_ASSERT(ring_size > 0);
RT_ASSERT(((ring_size - 1) & ring_size) == 0);
queue = &dev->queues[queue_index];
pages_total_size = VIRTIO_PAGE_ALIGN(
VIRTQ_DESC_TOTAL_SIZE(ring_size) + VIRTQ_AVAIL_TOTAL_SIZE(ring_size) + VIRTQ_USED_TOTAL_SIZE(ring_size));
pages = rt_malloc_align(pages_total_size, VIRTIO_PAGE_SIZE);
if (pages == RT_NULL)
{
return -RT_ENOMEM;
}
queue->free = rt_malloc(sizeof(rt_bool_t) * ring_size);
if (queue->free == RT_NULL)
{
rt_free_align(pages);
return -RT_ENOMEM;
}
rt_memset(pages, 0, pages_total_size);
pages_paddr = VIRTIO_VA2PA(pages);
dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE;
dev->mmio_config->queue_sel = queue_index;
dev->mmio_config->queue_num = ring_size;
dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE;
dev->mmio_config->queue_pfn = pages_paddr >> VIRTIO_PAGE_SHIFT;
queue->num = ring_size;
queue->desc = (struct virtq_desc *)pages_paddr;
queue->avail = (struct virtq_avail *)(pages_paddr + VIRTQ_DESC_TOTAL_SIZE(ring_size));
queue->used = (struct virtq_used *)VIRTIO_PAGE_ALIGN(
(rt_ubase_t)&queue->avail->ring[ring_size] + VIRTQ_AVAIL_RES_SIZE);
queue->used_idx = 0;
/* All descriptors start out unused */
for (i = 0; i < ring_size; ++i)
{
queue->free[i] = RT_TRUE;
}
return RT_EOK;
}
void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index)
{
struct virtq *queue;
_virtio_dev_check(dev);
RT_ASSERT(dev->mmio_config->queue_num_max > 0);
RT_ASSERT(dev->mmio_config->queue_num_max > queue_index);
queue = &dev->queues[queue_index];
RT_ASSERT(queue->num > 0);
rt_free(queue->free);
rt_free_align((void *)queue->desc);
dev->mmio_config->queue_sel = queue_index;
dev->mmio_config->queue_pfn = RT_NULL;
queue->num = 0;
queue->desc = RT_NULL;
queue->avail = RT_NULL;
queue->used = RT_NULL;
}
void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index)
{
_virtio_dev_check(dev);
dev->mmio_config->queue_notify = queue_index;
}
void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
{
rt_size_t ring_size;
struct virtq *queue;
_virtio_dev_check(dev);
queue = &dev->queues[queue_index];
ring_size = queue->num;
/* Tell the device the first index in our chain of descriptors */
queue->avail->ring[queue->avail->idx % ring_size] = desc_index;
rt_hw_dsb();
/* Tell the device another avail ring entry is available */
queue->avail->idx++;
rt_hw_dsb();
}
rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index)
{
int i;
rt_size_t ring_size;
struct virtq *queue;
_virtio_dev_check(dev);
RT_ASSERT(queue_index < RT_USING_VIRTIO_QUEUE_MAX_NR);
queue = &dev->queues[queue_index];
ring_size = queue->num;
for (i = 0; i < ring_size; ++i)
{
if (queue->free[i])
{
queue->free[i] = RT_FALSE;
return (rt_uint16_t)i;
}
}
return RT_UINT16_MAX;
}
void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
{
struct virtq *queue;
_virtio_dev_check(dev);
queue = &dev->queues[queue_index];
RT_ASSERT(queue_index + 1 < RT_USING_VIRTIO_QUEUE_MAX_NR);
RT_ASSERT(!queue->free[desc_index]);
queue->desc[desc_index].addr = 0;
queue->desc[desc_index].len = 0;
queue->desc[desc_index].flags = 0;
queue->desc[desc_index].next = 0;
queue->free[desc_index] = RT_TRUE;
}
rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
rt_uint16_t *indexs)
{
int i, j;
_virtio_dev_check(dev);
RT_ASSERT(indexs != RT_NULL);
for (i = 0; i < count; ++i)
{
indexs[i] = virtio_alloc_desc(dev, queue_index);
if (indexs[i] == RT_UINT16_MAX)
{
for (j = 0; j < i; ++j)
{
virtio_free_desc(dev, queue_index, indexs[j]);
}
return -RT_ERROR;
}
}
return RT_EOK;
}
void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
{
rt_uint16_t flags, next;
struct virtq_desc *desc;
_virtio_dev_check(dev);
desc = &dev->queues[queue_index].desc[0];
for (;;)
{
flags = desc[desc_index].flags;
next = desc[desc_index].next;
virtio_free_desc(dev, queue_index, desc_index);
if (flags & VIRTQ_DESC_F_NEXT)
{
desc_index = next;
}
else
{
break;
}
}
}
void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next)
{
struct virtq_desc *desc;
_virtio_dev_check(dev);
desc = &dev->queues[queue_index].desc[desc_index];
desc->addr = addr;
desc->len = len;
desc->flags = flags;
desc->next = next;
}
......@@ -6,55 +6,115 @@
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
* 2021-11-11 GuEe-GUI modify to virtio common interface
*/
#ifndef VIRTIO_H__
#define VIRTIO_H__
#ifndef __VIRTIO_H__
#define __VIRTIO_H__
#include <stdint.h>
#include <rthw.h>
#include <rtdef.h>
#define PAGE_SIZE 4096
#define PAGE_SHIFT 12
#ifndef RT_USING_VIRTIO_VERSION
#define RT_USING_VIRTIO_VERSION 0x1
#endif
#define VIRTIO_STAT_ACKNOWLEDGE 1
#define VIRTIO_STAT_DRIVER 2
#define VIRTIO_STAT_DRIVER_OK 4
#define VIRTIO_STAT_FEATURES_OK 8
#define VIRTIO_STAT_NEEDS_RESET 64
#define VIRTIO_STAT_FAILED 128
#ifndef RT_USING_VIRTIO_QUEUE_MAX_NR
#define RT_USING_VIRTIO_QUEUE_MAX_NR 4
#endif
#define QUEUE_SIZE 8
#include <virtio_mmio.h>
#include <virtio_queue.h>
struct virtq_desc
{
uint64_t addr;
uint32_t len;
uint16_t flags;
uint16_t next;
};
#define VIRTIO_MAGIC_VALUE 0x74726976 /* "virt" */
#define VRING_DESC_F_NEXT 1 // chained with another descriptor
#define VRING_DESC_F_WRITE 2 // device writes (vs read)
#define VIRTIO_STATUS_ACKNOWLEDGE (1 << 0)
#define VIRTIO_STATUS_DRIVER (1 << 1)
#define VIRTIO_STATUS_DRIVER_OK (1 << 2)
#define VIRTIO_STATUS_FEATURES_OK (1 << 3)
#define VIRTIO_STATUS_NEEDS_RESET (1 << 6)
#define VIRTIO_STATUS_FAILED (1 << 7)
struct virtq_avail
{
uint16_t flags; // always zero
uint16_t idx; // driver will write ring[idx] next
uint16_t ring[QUEUE_SIZE]; // descriptor numbers of chain heads
uint16_t unused;
};
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
#define VIRTIO_F_ANY_LAYOUT 27
#define VIRTIO_F_RING_INDIRECT_DESC 28
#define VIRTIO_F_RING_EVENT_IDX 29
#define VIRTIO_F_VERSION_1 32
#define VIRTIO_F_RING_PACKED 34
struct virtq_used_elem
#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)vaddr)
#define VIRTIO_PAGE_SHIFT 12
#define VIRTIO_PAGE_SIZE (1 << VIRTIO_PAGE_SHIFT)
#define VIRTIO_PAGE_ALIGN(addr) (RT_ALIGN(addr, VIRTIO_PAGE_SIZE))
enum
{
uint32_t id; // index of start of completed descriptor chain
uint32_t len;
/* virtio 1.0 */
VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */
VIRTIO_DEVICE_ID_NET = 1, /* Net */
VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */
VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */
VIRTIO_DEVICE_ID_RNG = 4, /* Rng */
VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */
VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */
VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */
VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */
VIRTIO_DEVICE_ID_9P = 9, /* 9p console */
VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */
VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */
VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */
VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */
VIRTIO_DEVICE_ID_GPU = 16, /* GPU */
VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */
VIRTIO_DEVICE_ID_INPUT = 18, /* Input */
/* virtio 1.1 */
VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */
VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */
VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */
VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */
VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */
VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */
VIRTIO_DEVICE_TYPE_SIZE
};
struct virtq_used
struct virtio_device
{
uint16_t flags; // always zero
uint16_t idx; // device increments when it adds a ring[] entry
struct virtq_used_elem ring[QUEUE_SIZE];
rt_uint32_t irq;
struct virtq queues[RT_USING_VIRTIO_QUEUE_MAX_NR];
union
{
rt_ubase_t *mmio_base;
struct virtio_mmio_config *mmio_config;
};
#ifdef RT_USING_SMP
struct rt_spinlock spinlock;
#endif
void *priv;
};
#endif /* VIRTIO_H__ */
typedef rt_err_t (*virtio_device_init_handler)(rt_ubase_t *mmio_base, rt_uint32_t irq);
void virtio_reset_device(struct virtio_device *dev);
void virtio_status_acknowledge_driver(struct virtio_device *dev);
void virtio_status_driver_ok(struct virtio_device *dev);
void virtio_interrupt_ack(struct virtio_device *dev, rt_uint32_t ack);
rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size);
void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index);
void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index);
void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index);
void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
rt_uint16_t *indexs);
void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next);
#endif /* __VIRTIO_H__ */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
* 2021-11-11 GuEe-GUI using virtio common interface
*/
#include <rthw.h>
#include <rtthread.h>
#include <cpuport.h>
#include <virtio_blk.h>
#ifdef BSP_USING_VIRTIO_BLK
static void virtio_blk_rw(struct virtio_blk_device *virtio_blk_dev, rt_off_t pos, void *buffer, int flags)
{
rt_uint16_t idx[3];
struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
#ifdef RT_USING_SMP
rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
#endif
/* Allocate 3 descriptors */
while (virtio_alloc_desc_chain(virtio_dev, 0, 3, idx))
{
}
virtio_blk_dev->info[idx[0]].status = 0xff;
virtio_blk_dev->info[idx[0]].valid = RT_TRUE;
virtio_blk_dev->info[idx[0]].req.type = flags;
virtio_blk_dev->info[idx[0]].req.ioprio = 0;
virtio_blk_dev->info[idx[0]].req.sector = pos * (VIRTIO_BLK_BUF_DATA_SIZE / 512);
flags = flags == VIRTIO_BLK_T_OUT ? 0 : VIRTQ_DESC_F_WRITE;
virtio_fill_desc(virtio_dev, 0, idx[0],
VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].req), sizeof(struct virtio_blk_req), VIRTQ_DESC_F_NEXT, idx[1]);
virtio_fill_desc(virtio_dev, 0, idx[1],
VIRTIO_VA2PA(buffer), VIRTIO_BLK_BUF_DATA_SIZE, flags | VIRTQ_DESC_F_NEXT, idx[2]);
virtio_fill_desc(virtio_dev, 0, idx[2],
VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].status), 1, VIRTQ_DESC_F_WRITE, 0);
virtio_submit_chain(virtio_dev, 0, idx[0]);
virtio_queue_notify(virtio_dev, 0);
/* Wait for virtio_blk_isr() to done */
while (virtio_blk_dev->info[idx[0]].valid)
{
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
#endif
rt_thread_yield();
#ifdef RT_USING_SMP
level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
#endif
}
virtio_free_desc_chain(virtio_dev, 0, idx[0]);
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
#endif
}
static rt_size_t virtio_blk_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
virtio_blk_rw((struct virtio_blk_device *)dev, pos, buffer, VIRTIO_BLK_T_IN);
return size;
}
static rt_size_t virtio_blk_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
virtio_blk_rw((struct virtio_blk_device *)dev, pos, (void *)buffer, VIRTIO_BLK_T_OUT);
return size;
}
static rt_err_t virtio_blk_control(rt_device_t dev, int cmd, void *args)
{
rt_err_t status = RT_EOK;
struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev;
switch (cmd)
{
case RT_DEVICE_CTRL_BLK_GETGEOME:
{
struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
if (geometry == RT_NULL)
{
status = -RT_ERROR;
break;
}
geometry->bytes_per_sector = VIRTIO_BLK_BYTES_PER_SECTOR;
geometry->block_size = VIRTIO_BLK_BLOCK_SIZE;
geometry->sector_count = virtio_blk_dev->virtio_dev.mmio_config->config[0];
}
break;
default:
break;
}
return status;
}
const static struct rt_device_ops virtio_blk_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
virtio_blk_read,
virtio_blk_write,
virtio_blk_control
};
static void virtio_blk_isr(int irqno, void *param)
{
rt_uint32_t id;
struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)param;
struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
#ifdef RT_USING_SMP
rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
#endif
virtio_interrupt_ack(virtio_dev, virtio_dev->mmio_config->interrupt_status & 0x3);
rt_hw_dsb();
/* The device increments disk.used->idx when it adds an entry to the used ring */
while (virtio_dev->queues[0].used_idx != virtio_dev->queues[0].used->idx)
{
rt_hw_dsb();
id = virtio_dev->queues[0].used->ring[virtio_dev->queues[0].used_idx % VIRTIO_BLK_QUEUE_RING_SIZE].id;
RT_ASSERT(virtio_blk_dev->info[id].status == 0);
/* Done with buffer */
virtio_blk_dev->info[id].valid = RT_FALSE;
rt_thread_yield();
virtio_dev->queues[0].used_idx++;
}
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
#endif
}
rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
{
static int dev_no = 0;
char dev_name[RT_NAME_MAX];
struct virtio_device *virtio_dev;
struct virtio_blk_device *virtio_blk_dev;
virtio_blk_dev = rt_malloc(sizeof(struct virtio_blk_device));
if (virtio_blk_dev == RT_NULL)
{
return -RT_ENOMEM;
}
virtio_dev = &virtio_blk_dev->virtio_dev;
virtio_dev->irq = irq;
virtio_dev->mmio_base = mmio_base;
#ifdef RT_USING_SMP
rt_spin_lock_init(&virtio_dev->spinlock);
#endif
virtio_reset_device(virtio_dev);
virtio_status_acknowledge_driver(virtio_dev);
/* Negotiate features */
virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
(1 << VIRTIO_BLK_F_RO) |
(1 << VIRTIO_BLK_F_MQ) |
(1 << VIRTIO_BLK_F_SCSI) |
(1 << VIRTIO_BLK_F_CONFIG_WCE) |
(1 << VIRTIO_F_ANY_LAYOUT) |
(1 << VIRTIO_F_RING_EVENT_IDX) |
(1 << VIRTIO_F_RING_INDIRECT_DESC));
/* Tell device that feature negotiation is complete and we're completely ready */
virtio_status_driver_ok(virtio_dev);
/* Initialize queue 0 */
if (virtio_queue_init(virtio_dev, 0, VIRTIO_BLK_QUEUE_RING_SIZE) != RT_EOK)
{
rt_free(virtio_blk_dev);
return -RT_ENOMEM;
}
virtio_blk_dev->parent.type = RT_Device_Class_Block;
virtio_blk_dev->parent.ops = &virtio_blk_ops;
rt_snprintf(dev_name, RT_NAME_MAX, "%s%d", "virtio-blk", dev_no++);
rt_hw_interrupt_install(irq, virtio_blk_isr, virtio_blk_dev, dev_name);
rt_hw_interrupt_umask(irq);
return rt_device_register((rt_device_t)virtio_blk_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
}
#endif /* BSP_USING_VIRTIO_BLK */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
* 2021-11-11 GuEe-GUI using virtio common interface
*/
#ifndef __VIRTIO_BLK_H__
#define __VIRTIO_BLK_H__
#include <rtdef.h>
#include <virtio.h>
#define VIRTIO_BLK_BUF_DATA_SIZE 512
#define VIRTIO_BLK_BYTES_PER_SECTOR 512
#define VIRTIO_BLK_BLOCK_SIZE 512
#define VIRTIO_BLK_QUEUE_RING_SIZE 4
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
#define VIRTIO_BLK_T_IN 0 /* Read the blk */
#define VIRTIO_BLK_T_OUT 1 /* Write the blk */
#define VIRTIO_BLK_T_SCSI_CMD 2
#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
#define VIRTIO_BLK_T_FLUSH 4
#define VIRTIO_BLK_T_FLUSH_OUT 5
struct virtio_blk_req
{
rt_uint32_t type;
rt_uint32_t ioprio;
rt_uint64_t sector;
};
struct virtio_blk_device
{
struct rt_device parent;
struct virtio_device virtio_dev;
struct
{
rt_bool_t valid;
rt_uint8_t status;
struct virtio_blk_req req;
} info[VIRTIO_BLK_QUEUE_RING_SIZE];
};
rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
#endif /* __VIRTIO_BLK_H__ */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
*/
#include <rtthread.h>
#include <cpuport.h>
#include "virtio_mmio.h"
void virtio_mmio_print_configs(uint32_t *device_base)
{
rt_kprintf("MagicValue:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_MAGIC_VALUE));
rt_kprintf("Version:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_VERSION));
rt_kprintf("DeviceID:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_DEVICE_ID));
rt_kprintf("VendorID:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_VENDOR_ID));
rt_kprintf("DeviceFeatures0:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_HOST_FEATURES));
rt_kprintf("DeviceFeaturesSel0:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_HOST_FEATURES_SEL));
virtio_mmio_write32(device_base, VIRTIO_MMIO_HOST_FEATURES_SEL, 1);
rt_hw_dsb();
rt_kprintf("DeviceFeatures1:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_HOST_FEATURES));
rt_kprintf("DriverFeatures:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_GUEST_FEATURES));
rt_kprintf("DriverFeaturesSel:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_GUEST_FEATURES_SEL));
rt_kprintf("PageSize:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_GUEST_PAGE_SIZE));
virtio_mmio_write32(device_base, VIRTIO_MMIO_QUEUE_SEL, 0);
rt_hw_dsb();
rt_kprintf("QueueSel:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_SEL));
rt_kprintf("QueueNumMax:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_NUM_MAX));
rt_kprintf("QueueNum:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_NUM));
virtio_mmio_write32(device_base, VIRTIO_MMIO_QUEUE_SEL, 1);
rt_hw_dsb();
rt_kprintf("QueueSel:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_SEL));
rt_kprintf("QueueNumMax1:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_NUM_MAX));
rt_kprintf("QueueNum1:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_NUM));
rt_kprintf("QueueAlign:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_ALIGN));
rt_kprintf("QueuePFN:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_PFN));
rt_kprintf("QueueReady:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_READY));
rt_kprintf("QueueNotify:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_NOTIFY));
rt_kprintf("InterruptStatus:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_INTERRUPT_STATUS));
rt_kprintf("InterruptACK:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_INTERRUPT_ACK));
rt_kprintf("Status:\t\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_STATUS));
rt_kprintf("QueueDescLow:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_DESC_LOW));
rt_kprintf("QueueDescHigh:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_DESC_HIGH));
rt_kprintf("QueueDriverLow:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_AVAIL_LOW));
rt_kprintf("QueueDriverHigh:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_AVAIL_HIGH));
rt_kprintf("QueueDeviceLow:\t\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_USED_LOW));
rt_kprintf("QueueDeviceHigh:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_QUEUE_USED_HIGH));
rt_kprintf("ConfigGeneration:\t 0x%x\n", virtio_mmio_read32(device_base, VIRTIO_MMIO_CONFIG_GENERATION));
rt_kprintf("Config:\t\t\t 0x%x\n", virtio_mmio_read32(device_base,VIRTIO_MMIO_CONFIG));
}
......@@ -6,70 +6,52 @@
* Change Logs:
* Date Author Notes
* 2021-9-16 GuEe-GUI the first version
* 2021-11-11 GuEe-GUI modify to virtio common interface
*/
#ifndef VIRTIO_MMIO_H
#define VIRTIO_MMIO_H
#ifndef __VIRTIO_MMIO_H__
#define __VIRTIO_MMIO_H__
#include <stdint.h>
#include <stddef.h>
#include <rtdef.h>
#define VIRTIO_MMIO_MAGIC 0x74726976
#define VIRTIO_MMIO_VENDOR 0x554d4551
#define VIRTIO_MMIO_MAGIC_VALUE 0x000 /* VIRTIO_MMIO_MAGIC */
#define VIRTIO_MMIO_VERSION 0x004 /* version: 1 is legacy */
#define VIRTIO_MMIO_DEVICE_ID 0x008 /* device type: 1 is net, 2 is disk */
#define VIRTIO_MMIO_VENDOR_ID 0x00c /* VIRTIO_MMIO_VENDOR */
#define VIRTIO_MMIO_DEVICE_FEATURES 0x010
#define VIRTIO_MMIO_DRIVER_FEATURES 0x020
#define VIRTIO_MMIO_HOST_FEATURES 0x010
#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014
#define VIRTIO_MMIO_GUEST_FEATURES 0x020
#define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024
#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 /* version 1 only */
#define VIRTIO_MMIO_QUEUE_SEL 0x030
#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
#define VIRTIO_MMIO_QUEUE_NUM 0x038
#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c /* version 1 only */
#define VIRTIO_MMIO_QUEUE_PFN 0x040 /* version 1 only */
#define VIRTIO_MMIO_QUEUE_READY 0x044 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060
#define VIRTIO_MMIO_INTERRUPT_ACK 0x064
#define VIRTIO_MMIO_STATUS 0x070
#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 /* requires version 2 */
#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 /* requires version 2 */
#define VIRTIO_MMIO_CONFIG_GENERATION 0x100 /* requires version 2 */
#define VIRTIO_MMIO_CONFIG 0x100
#define VIRTIO_MMIO_INT_VRING (1 << 0)
#define VIRTIO_MMIO_INT_CONFIG (1 << 1)
#define VIRTIO_MMIO_VRING_ALIGN 4096
static inline uint32_t virtio_mmio_read32(uint32_t *base, size_t offset)
{
return *((volatile uint32_t*) (((uintptr_t) base) + offset));
}
static inline uint16_t virtio_mmio_read16(uint32_t *base, size_t offset)
{
return *((volatile uint16_t*) (((uintptr_t) base) + offset));
}
static inline uint8_t virtio_mmio_read8(uint32_t *base, size_t offset)
{
return *((volatile uint8_t*) (((uintptr_t) base) + offset));
}
static inline void virtio_mmio_write32(uint32_t *base, size_t offset, uint32_t val)
struct virtio_mmio_config
{
*((volatile uint32_t*) (((uintptr_t) base) + offset)) = val;
}
void virtio_mmio_print_configs(uint32_t *device_base);
#endif /* VIRTIO_MMIO_H */
rt_uint32_t magic; /* [0x00]<RO> Magic value */
rt_uint32_t version; /* [0x04]<RO> Device version number */
rt_uint32_t device_id; /* [0x08]<RO> Virtio Subsystem Device ID */
rt_uint32_t vendor_id; /* [0x0c]<RO> Virtio Subsystem Vendor ID */
rt_uint32_t device_features; /* [0x10]<RO> Flags representing features the device supports */
rt_uint32_t device_features_sel; /* [0x14]<WO> Device (host) features word selection. */
rt_uint32_t res0[2]; /* [0x18] */
rt_uint32_t driver_features; /* [0x20]<WO> Device features understood and activated by the driver */
rt_uint32_t driver_features_sel; /* [0x24]<WO> Activated (guest) features word selection */
rt_uint32_t guest_page_size; /* [0x28]<WO> Guest page size, this value should be a power of 2 */
rt_uint32_t res1[1]; /* [0x2c] */
rt_uint32_t queue_sel; /* [0x30]<WO> Virtual queue index */
rt_uint32_t queue_num_max; /* [0x34]<RO> Maximum virtual queue size */
rt_uint32_t queue_num; /* [0x38]<WO> Virtual queue size */
rt_uint32_t queue_align; /* [0x3c]<WO> Used Ring alignment in the virtual queue */
rt_uint32_t queue_pfn; /* [0x40]<RW> Guest physical page number of the virtual queue */
rt_uint32_t queue_ready; /* [0x44]<RW> Virtual queue ready bit */
rt_uint32_t res2[2]; /* [0x48] */
rt_uint32_t queue_notify; /* [0x50]<WO> Queue notifier */
rt_uint32_t res3[3]; /* [0x54] */
rt_uint32_t interrupt_status; /* [0x60]<RO> Interrupt status */
rt_uint32_t interrupt_ack; /* [0x64]<WO> Interrupt acknowledge */
rt_uint32_t res4[2]; /* [0x68] */
rt_uint32_t status; /* [0x70]<RW> Device status */
rt_uint32_t res5[3]; /* [0x74] */
rt_uint32_t queue_desc_low; /* [0x80]<WO> Virtual queue’s Descriptor Area 64 bit long physical address */
rt_uint32_t queue_desc_high; /* [0x84]<WO> */
rt_uint32_t res6[2]; /* [0x88] */
rt_uint32_t queue_driver_low; /* [0x90]<WO> Virtual queue’s Driver Area 64 bit long physical address */
rt_uint32_t queue_driver_high; /* [0x94]<WO> */
rt_uint32_t res7[2]; /* [0x98] */
rt_uint32_t queue_device_low; /* [0xa0]<WO> Virtual queue’s Device Area 64 bit long physical address */
rt_uint32_t queue_device_high; /* [0xa4]<WO> */
rt_uint32_t res8[21]; /* [0xa8] */
rt_uint32_t config_generation; /* [0xfc]<RO> Configuration atomicity value */
rt_uint32_t config[]; /* [0x100+]<RO> Configuration space */
} __attribute__((packed));
#endif /* __VIRTIO_MMIO_H__ */
/*
* 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 __VIRTIO_QUEUE_H__
#define __VIRTIO_QUEUE_H__
#include <rtdef.h>
#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as continuing via the next field. */
#define VIRTQ_DESC_F_WRITE 2 /* This marks a buffer as write-only (otherwise read-only). */
#define VIRTQ_DESC_F_INDIRECT 4 /* This means the buffer contains a list of buffer descriptors. */
/*
* The device uses this in used->flags to advise the driver: don't kick me
* when you add a buffer. It's unreliable, so it's simply an optimization.
*/
#define VIRTQ_USED_F_NO_NOTIFY 1
/*
* The driver uses this in avail->flags to advise the device: don't
* interrupt me when you consume a buffer. It's unreliable, so it's
* simply an optimization.
*/
#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */
struct virtq_desc
{
rt_uint64_t addr; /* Address (guest-physical). */
rt_uint32_t len; /* Length. */
rt_uint16_t flags; /* The flags as indicated above. */
rt_uint16_t next; /* We chain unused descriptors via this, too */
};
struct virtq_avail
{
rt_uint16_t flags; /* Notifications */
rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */
rt_uint16_t ring[];
/*
* Only if VIRTIO_F_RING_EVENT_IDX
* rt_uint16_t used_event;
*/
};
struct virtq_used_elem
{
rt_uint32_t id; /* Index of start of used descriptor chain. */
rt_uint32_t len; /* Total length of the descriptor chain which was written to. */
};
struct virtq_used
{
rt_uint16_t flags;
rt_uint16_t idx;
struct virtq_used_elem ring[];
/*
* Only if VIRTIO_F_RING_EVENT_IDX
* rt_uint16_t avail_event;
*/
};
struct virtq
{
rt_uint32_t num;
struct virtq_desc *desc;
struct virtq_avail *avail;
struct virtq_used *used;
/* Helper of driver */
rt_uint32_t used_idx;
rt_bool_t *free;
};
#define VIRTQ_DESC_TOTAL_SIZE(ring_size) (sizeof(struct virtq_desc) * (ring_size))
/* flags, idx, used_event + ring * ring_size */
#define VIRTQ_AVAIL_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(rt_uint16_t) * (ring_size))
/* flags, idx, avail_event + ring * ring_size */
#define VIRTQ_USED_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(struct virtq_used_elem) * (ring_size))
#define VIRTQ_AVAIL_RES_SIZE (sizeof(rt_uint16_t)) /* used_event */
#define VIRTQ_USED_RES_SIZE (sizeof(rt_uint16_t)) /* avail_event */
#endif /* __VIRTIO_QUEUE_H__ */
......@@ -3,5 +3,6 @@ if exist sd.bin goto run
qemu-img create -f raw sd.bin 64M
:run
qemu-system-aarch64 -M virt -cpu cortex-a53 -smp 4 -kernel rtthread.elf -nographic ^
-drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0
qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.elf -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
if [ ! -f "sd.bin" ]; then
dd if=/dev/zero of=sd.bin bs=1024 count=65536
fi
qemu-system-aarch64 -M virt -cpu cortex-a53 -smp 4 -kernel rtthread.elf -nographic \
-drive if=none,file=sd.bin,format=raw,id=blk0 -device virtio-blk-device,drive=blk0,bus=virtio-mmio-bus.0
qemu-system-aarch64 -M virt,gic-version=2 -cpu cortex-a53 -smp 4 -kernel rtthread.elf -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
......@@ -61,14 +61,8 @@
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 8192
#define RT_MAIN_THREAD_PRIORITY 10
/* C++ features */
/* Command shell */
#define RT_USING_FINSH
#define RT_USING_MSH
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_THREAD_NAME "tshell"
#define FINSH_THREAD_PRIORITY 20
......@@ -80,9 +74,6 @@
#define MSH_USING_BUILT_IN_COMMANDS
#define FINSH_USING_DESCRIPTION
#define FINSH_ARG_MAX 10
/* Device virtual file system */
#define RT_USING_DFS
#define DFS_USING_POSIX
#define DFS_USING_WORKDIR
......@@ -109,6 +100,9 @@
/* Device Drivers */
#define RT_USING_DEVICE_IPC
#define RT_USING_SYSTEM_WORKQUEUE
#define RT_SYSTEM_WORKQUEUE_STACKSIZE 2048
#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
#define RT_USING_SERIAL
#define RT_USING_SERIAL_V1
#define RT_SERIAL_RB_BUFSZ 64
......@@ -119,7 +113,7 @@
/* Using USB */
/* POSIX layer and C standard library */
/* C/C++ and POSIX layer */
#define RT_LIBC_DEFAULT_TIMEZONE 8
......@@ -131,21 +125,8 @@
/* Socket is in the 'Network' category */
/* Network */
/* Socket abstraction layer */
/* Network interface device */
/* light weight TCP/IP stack */
/* AT commands */
/* VBUS(Virtual Software BUS) */
/* Network */
/* Utilities */
......@@ -215,6 +196,8 @@
/* miscellaneous packages */
/* project laboratory */
/* samples: kernel and components samples */
......@@ -229,7 +212,7 @@
#define BSP_USING_RTC
#define BSP_USING_ALARM
#define BSP_USING_VIRTIO_BLK
#define RT_USING_VIRTIO_BLK0
#define BSP_USING_GIC
#define BSP_USING_GICV2
#endif
......@@ -94,17 +94,8 @@ CONFIG_RT_USING_USER_MAIN=y
CONFIG_RT_MAIN_THREAD_STACK_SIZE=4096
CONFIG_RT_MAIN_THREAD_PRIORITY=10
# CONFIG_RT_USING_LEGACY is not set
#
# C++ features
#
# CONFIG_RT_USING_CPLUSPLUS is not set
#
# Command shell
#
CONFIG_RT_USING_FINSH=y
CONFIG_RT_USING_MSH=y
CONFIG_RT_USING_FINSH=y
CONFIG_FINSH_USING_MSH=y
CONFIG_FINSH_THREAD_NAME="tshell"
CONFIG_FINSH_THREAD_PRIORITY=20
......@@ -118,10 +109,6 @@ CONFIG_FINSH_USING_DESCRIPTION=y
# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
# CONFIG_FINSH_USING_AUTH is not set
CONFIG_FINSH_ARG_MAX=10
#
# Device virtual file system
#
CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_POSIX=y
CONFIG_DFS_USING_WORKDIR=y
......@@ -156,6 +143,7 @@ CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_NFS is not set
# CONFIG_RT_USING_FAL is not set
#
# Device Drivers
......@@ -209,7 +197,7 @@ CONFIG_RT_USING_WDT=y
# CONFIG_RT_USING_USB_DEVICE is not set
#
# POSIX layer and C standard library
# C/C++ and POSIX layer
#
CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
......@@ -233,25 +221,11 @@ CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8
#
# Socket is in the 'Network' category
#
#
# Interprocess Communication (IPC)
#
# CONFIG_RT_USING_POSIX_PIPE is not set
# CONFIG_RT_USING_POSIX_MESSAGE_QUEUE is not set
# CONFIG_RT_USING_POSIX_MESSAGE_SEMAPHORE is not set
#
# Socket is in the 'Network' category
#
# CONFIG_RT_USING_CPLUSPLUS is not set
#
# Network
#
#
# Socket abstraction layer
#
CONFIG_RT_USING_SAL=y
CONFIG_SAL_INTERNET_CHECK=y
......@@ -261,10 +235,6 @@ CONFIG_SAL_INTERNET_CHECK=y
CONFIG_SAL_USING_LWIP=y
# CONFIG_SAL_USING_POSIX is not set
CONFIG_SAL_SOCKETS_NUM=16
#
# Network interface device
#
CONFIG_RT_USING_NETDEV=y
CONFIG_NETDEV_USING_IFCONFIG=y
CONFIG_NETDEV_USING_PING=y
......@@ -274,14 +244,13 @@ CONFIG_NETDEV_USING_AUTO_DEFAULT=y
CONFIG_NETDEV_IPV4=1
CONFIG_NETDEV_IPV6=0
# CONFIG_NETDEV_IPV6_SCOPES is not set
#
# light weight TCP/IP stack
#
CONFIG_RT_USING_LWIP=y
# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set
# CONFIG_RT_USING_LWIP141 is not set
CONFIG_RT_USING_LWIP203=y
# CONFIG_RT_USING_LWIP212 is not set
# CONFIG_RT_USING_LWIP_LATEST is not set
CONFIG_RT_USING_LWIP_VER_NUM=0x20003
# CONFIG_RT_USING_LWIP_IPV6 is not set
CONFIG_RT_LWIP_MEM_ALIGNMENT=4
CONFIG_RT_LWIP_IGMP=y
......@@ -331,18 +300,9 @@ CONFIG_LWIP_NETIF_LOOPBACK=0
# CONFIG_RT_LWIP_STATS is not set
# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
CONFIG_RT_LWIP_USING_PING=y
# CONFIG_LWIP_USING_DHCPD is not set
# CONFIG_RT_LWIP_DEBUG is not set
#
# AT commands
#
# CONFIG_RT_USING_AT is not set
# CONFIG_LWIP_USING_DHCPD is not set
#
# VBUS(Virtual Software BUS)
#
# CONFIG_RT_USING_VBUS is not set
#
# Utilities
......@@ -354,6 +314,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_RT_USING_UTEST is not set
# CONFIG_RT_USING_VAR_EXPORT is not set
# CONFIG_RT_USING_RT_LINK is not set
# CONFIG_RT_USING_VBUS is not set
#
# RT-Thread Utestcases
......@@ -367,6 +328,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
#
# IoT - internet of things
#
# CONFIG_PKG_USING_LWIP is not set
# CONFIG_PKG_USING_LORAWAN_DRIVER is not set
# CONFIG_PKG_USING_PAHOMQTT is not set
# CONFIG_PKG_USING_UMQTT is not set
......@@ -383,6 +345,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_FREEMODBUS is not set
# CONFIG_PKG_USING_LJSON is not set
# CONFIG_PKG_USING_EZXML is not set
# CONFIG_PKG_USING_SIMPLE_XML is not set
# CONFIG_PKG_USING_NANOPB is not set
#
......@@ -422,6 +385,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_JOYLINK is not set
# CONFIG_PKG_USING_EZ_IOT_OS is not set
# CONFIG_PKG_USING_NIMBLE is not set
# CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set
# CONFIG_PKG_USING_OTA_DOWNLOADER is not set
# CONFIG_PKG_USING_IPMSG is not set
# CONFIG_PKG_USING_LSSDP is not set
......@@ -629,8 +593,8 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_ARM_2D is not set
# CONFIG_PKG_USING_MCUBOOT is not set
# CONFIG_PKG_USING_TINYUSB is not set
# CONFIG_PKG_USING_USB_STACK is not set
# CONFIG_PKG_USING_LUATOS_SOC is not set
# CONFIG_PKG_USING_CHERRYUSB is not set
# CONFIG_PKG_USING_KMULTI_RTIMER is not set
#
# peripheral libraries and drivers
......@@ -654,6 +618,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_WM_LIBRARIES is not set
# CONFIG_PKG_USING_KENDRYTE_SDK is not set
# CONFIG_PKG_USING_INFRARED is not set
# CONFIG_PKG_USING_MULTI_INFRARED is not set
# CONFIG_PKG_USING_AGILE_BUTTON is not set
# CONFIG_PKG_USING_AGILE_LED is not set
# CONFIG_PKG_USING_AT24CXX is not set
......@@ -710,6 +675,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_SOFT_SERIAL is not set
# CONFIG_PKG_USING_MB85RS16 is not set
# CONFIG_PKG_USING_CW2015 is not set
# CONFIG_PKG_USING_RFM300 is not set
#
# AI packages
......@@ -728,6 +694,10 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# miscellaneous packages
#
#
# project laboratory
#
#
# samples: kernel and components samples
#
......@@ -760,6 +730,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_CANFESTIVAL is not set
# CONFIG_PKG_USING_ZLIB is not set
# CONFIG_PKG_USING_MINIZIP is not set
# CONFIG_PKG_USING_HEATSHRINK is not set
# CONFIG_PKG_USING_DSTR is not set
# CONFIG_PKG_USING_TINYFRAME is not set
# CONFIG_PKG_USING_KENDRYTE_DEMO is not set
......@@ -777,6 +748,7 @@ CONFIG_YMODEM_USING_FILE_TRANSFER=y
# CONFIG_PKG_USING_DESIGN_PATTERN is not set
# CONFIG_PKG_USING_CONTROLLER is not set
# CONFIG_PKG_USING_PHASE_LOCKED_LOOP is not set
# CONFIG_PKG_USING_MFBD is not set
CONFIG_BCM2711_SOC=y
#
......@@ -793,6 +765,7 @@ CONFIG_RT_USING_UART0=y
# CONFIG_RT_USING_UART4 is not set
# CONFIG_RT_USING_UART5 is not set
CONFIG_BSP_USING_GIC=y
CONFIG_BSP_USING_GICV2=y
CONFIG_BSP_USING_PIN=y
CONFIG_BSP_USING_CORETIMER=y
# CONFIG_BSP_USING_SYSTIMER is not set
......
......@@ -31,6 +31,10 @@ menu "Hardware Drivers Config"
bool
default y
config BSP_USING_GICV2
bool
default y
config BSP_USING_PIN
bool "Using PIN"
select RT_USING_PIN
......
......@@ -10,6 +10,8 @@
#include <rthw.h>
#include "drv_wdt.h"
#include "drv_gpio.h"
#include "mbox.h"
#include "raspi4.h"
#ifdef BSP_USING_WDT
......@@ -122,6 +124,48 @@ int rt_hw_wdt_init(void)
}
INIT_DEVICE_EXPORT(rt_hw_wdt_init);
void poweroff(void)
{
unsigned long r;
rt_kprintf("poweroff...\n");
/* power off devices one by one */
for (r = 0; r < 16; ++r)
{
bcm271x_mbox_poweroff_devices(r);
}
/* power off gpio pins (but not VCC pins) */
GPIO_REG_GPFSEL0(GPIO_BASE) = 0;
GPIO_REG_GPFSEL1(GPIO_BASE) = 0;
GPIO_REG_GPFSEL2(GPIO_BASE) = 0;
GPIO_REG_GPFSEL3(GPIO_BASE) = 0;
GPIO_REG_GPFSEL4(GPIO_BASE) = 0;
GPIO_REG_GPFSEL5(GPIO_BASE) = 0;
GPIO_REG_GPPUD(GPIO_BASE) = 0;
rt_thread_mdelay(150);
GPIO_REG_GPPUDCLK0(GPIO_BASE) = 0xffffffff;
GPIO_REG_GPPUDCLK1(GPIO_BASE) = 0xffffffff;
rt_thread_mdelay(150);
/* flush GPIO setup */
GPIO_REG_GPPUDCLK0(GPIO_BASE) = 0;
GPIO_REG_GPPUDCLK1(GPIO_BASE) = 0;
/* power off the SoC (GPU + CPU), partition 63 used to indicate halt */
r = PM_RSTS;
r &= ~0xfffffaaa;
r |= 0x555;
PM_RSTS |= PM_PASSWORD | r;
PM_WDOG |= PM_PASSWORD | 0x0A;
PM_RSTC |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
while (1) {};
}
MSH_CMD_EXPORT(poweroff, poweroff...);
void reboot(void)
{
unsigned int r;
......
......@@ -53,6 +53,24 @@ int mbox_call(unsigned char ch, int mmu_enable)
return 0;
}
int bcm271x_mbox_poweroff_devices(int id)
{
mbox[0] = 8 * 4; /* length of the message */
mbox[1] = MBOX_REQUEST; /* this is a request message */
mbox[2] = MBOX_TAG_SETPOWER; /* set power state */
mbox[3] = 8; /* buffer size */
mbox[4] = 8; /* len */
mbox[5] = (unsigned int)id; /* device id */
mbox[6] = 0; /* bit 0: off, bit 1: no wait */
mbox[7] = MBOX_TAG_LAST;
mbox_call(8, MBOX_CH_PROP);
return 0;
}
int bcm271x_mbox_get_touch(void)
{
mbox[0] = 8 * 4; // length of the message
......
......@@ -161,6 +161,7 @@ enum
#define PWM_CLK_ID (0x00000000a)
int mbox_call(unsigned char ch, int mmu_enable);
int bcm271x_mbox_poweroff_devices(int id);
int bcm271x_mbox_get_touch(void);
int bcm271x_notify_reboot(void);
int bcm271x_notify_xhci_reset(void);
......
......@@ -56,14 +56,8 @@
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 4096
#define RT_MAIN_THREAD_PRIORITY 10
/* C++ features */
/* Command shell */
#define RT_USING_FINSH
#define RT_USING_MSH
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_THREAD_NAME "tshell"
#define FINSH_THREAD_PRIORITY 20
......@@ -75,9 +69,6 @@
#define MSH_USING_BUILT_IN_COMMANDS
#define FINSH_USING_DESCRIPTION
#define FINSH_ARG_MAX 10
/* Device virtual file system */
#define RT_USING_DFS
#define DFS_USING_POSIX
#define DFS_USING_WORKDIR
......@@ -125,7 +116,7 @@
/* Using USB */
/* POSIX layer and C standard library */
/* C/C++ and POSIX layer */
#define RT_LIBC_DEFAULT_TIMEZONE 8
......@@ -137,9 +128,8 @@
/* Socket is in the 'Network' category */
/* Network */
/* Socket abstraction layer */
/* Network */
#define RT_USING_SAL
#define SAL_INTERNET_CHECK
......@@ -148,9 +138,6 @@
#define SAL_USING_LWIP
#define SAL_SOCKETS_NUM 16
/* Network interface device */
#define RT_USING_NETDEV
#define NETDEV_USING_IFCONFIG
#define NETDEV_USING_PING
......@@ -158,11 +145,9 @@
#define NETDEV_USING_AUTO_DEFAULT
#define NETDEV_IPV4 1
#define NETDEV_IPV6 0
/* light weight TCP/IP stack */
#define RT_USING_LWIP
#define RT_USING_LWIP203
#define RT_USING_LWIP_VER_NUM 0x20003
#define RT_LWIP_MEM_ALIGNMENT 4
#define RT_LWIP_IGMP
#define RT_LWIP_ICMP
......@@ -203,12 +188,6 @@
#define LWIP_NETIF_LOOPBACK 0
#define RT_LWIP_USING_PING
/* AT commands */
/* VBUS(Virtual Software BUS) */
/* Utilities */
#define RT_USING_RYM
......@@ -278,6 +257,8 @@
/* miscellaneous packages */
/* project laboratory */
/* samples: kernel and components samples */
......@@ -292,6 +273,7 @@
#define BSP_USING_UART
#define RT_USING_UART0
#define BSP_USING_GIC
#define BSP_USING_GICV2
#define BSP_USING_PIN
#define BSP_USING_CORETIMER
#define BSP_USING_WDT
......
此差异已折叠。
mainmenu "RT-Thread Project Configuration"
config BSP_DIR
string
option env="BSP_ROOT"
default "."
config RTT_DIR
string
option env="RTT_ROOT"
default "../../.."
config PKGS_DIR
string
option env="PKGS_ROOT"
default "packages"
source "$RTT_DIR/Kconfig"
source "$PKGS_DIR/Kconfig"
config SOC_RK3568
bool
select ARCH_ARMV8
select ARCH_CPU_64BIT
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN
default y
source "$BSP_DIR/driver/Kconfig"
# RK3568 BSP Introduction
[中文页](README_zh.md) | English
## 1. Introduction
RK3568 is a general-purpose SOC, quad-core 64-bit Cortex-A55 processor, with 22nm lithography process, has frequency up to 2.0GHz and Mali G52 GPU, support 4K decoding and 1080P encoding. Support mangy interfaces such as SATA/PCIE/USB3.0, an 0.8T NPU for lightweight AI applications. Support dual Gigabit Ethernet ports, LPDDR4 memory, etc.
This project ported RT-Thread on RK3568, you can use the RADXA ROCK 3A version of the RK3568 in low-priced, which can even replace the Raspberry Pi 4B.
## 2. Compiling
Usage ARM Developer GNU ToolChain, it support Linux and Windows:
```
https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/
```
Download the `xxx-aarch64-none-elf` of x86_64 hosted platform, set the `RTT_EXEC_PATH` is system environment after decompress the binary.
Enter directory `rt-thread/bsp/qemu-virt64-aarch64` and input:
```
scons
```
## 3. Execution
RK3568 has different Kernel install methods according to different boardsit, recommend to install into the SD card: ([Official](https://wiki.t-firefly.com/en/ROC-RK3568-PC/hardware_doc.html)|[RADXA ROCK 3A](https://wiki.radxa.com/Rock3/install/microSD)).
After install Kernel, storage the `rtthread.bin` to EFI partition (the second partition), and add this line in the front of `boot.cmd` in this partition:
```shell
fatload mmc 1:1 0x208000 /rtthread.bin;dcache flush;go 0x208000
```
After modifying the script, build a binary script `boot.scr ` in this partition:
```shell
# Install the uboot-mkimage package on Linux, or use MSYS2 to install the u-boot-tools package on Windows
mkimage -C none -A arm -T script -d boot.cmd boot.scr
```
According to different boards, the serial port can support up to UART0~9, this project uses UART2 ([Official](https://wiki.t-firefly.com/en/ROC-RK3568-PC/debug.html)|[RADXA ROCK 3A](https://wiki.radxa.com/Rock3/dev/serial-console)) by default, the baud rate is 1500000, please make sure that the serial port used supports this baud rate.
```
heap: [0x002663f0 - 0x042663f0]
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Mar 19 2022 17:17:29
2006 - 2022 Copyright by RT-Thread team
Hi, this is RT-Thread!!
msh />
```
## 4. Condition
| Driver | Condition | Remark |
| ------ | --------- | ------ |
| UART | Support | UART0~9 |
# RK3568 板级支持包说明
中文页 | [English](README.md)
## 1. 简介
RK3568 是一款定位中高端的通用型 SOC,采用 22nm 制程工艺,集成四核 2GHz,Cortex-A55 架构和 Mali G52 GPU,支持 4K 解码和 1080P 编码。支持 SATA/PCIE/USB3.0 等各类型外围接口,内置独立的 0.8T NPU,可用于轻量级 AI 应用。支持双千兆以太网口,LPDDR4 内存等。
这份 RT-Thread BSP是针对 RK3568 的一份移植。开发者可选择使用 RADXA ROCK 3A 版本的 RK3568 廉价体验,其甚至可超量替代树莓派4B。
## 2. 编译说明
建议使用ARM Developer GNU交叉编译工具链,目前支持Linux/Windows平台:
```
https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/
```
下载x86_64 Hosted平台下载对应的`xxx-aarch64-none-elf`二进制包,解压后设置`RTT_EXEC_PATH`环境变量为该编译器的bin目录下即可。
进入到`rt-thread/bsp/rockchip/rk3568`目录进行输入:
```
scons
```
可以看到正常生成`rtthread.elf``rtthread.bin`文件。
## 3. 执行
RK3568 根据不同的开发板实现有不同的 Kernel 烧写方式,推荐烧录进 SD 卡:([官方板](https://wiki.t-firefly.com/zh_CN/ROC-RK3568-PC/hardware_doc.html)|[RADXA ROCK 3A](https://wiki.radxa.com/Rock3/install/microSD))。
在烧写完 Kernel 后,将`rtthread.bin`放入 EFI 分区(第二分区),并在该分区的`boot.cmd`最前面中添加如下行:
```shell
fatload mmc 1:1 0x208000 /rtthread.bin;dcache flush;go 0x208000
```
修改脚本后,在该分区生成二进制脚本`boot.scr`:
```shell
# Linux 下安装 uboot-mkimage 软件包,Windows 下使用 MSYS2 安装 u-boot-tools 软件包
mkimage -C none -A arm -T script -d boot.cmd boot.scr
```
根据不同的开发板实现串口最多可支持到 UART0~9,本工程默认使用 UART2([官方板](https://wiki.t-firefly.com/zh_CN/ROC-RK3568-PC/debug.html)|[RADXA ROCK 3A](https://wiki.radxa.com/Rock3/dev/serial-console)),波特率 1500000,请确保使用的串口支持该波特率。
```
heap: [0x002663f0 - 0x042663f0]
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Mar 19 2022 17:17:29
2006 - 2022 Copyright by RT-Thread team
Hi, this is RT-Thread!!
msh />
```
## 4.支持情况
| 驱动 | 支持情况 | 备注 |
| ------ | ---- | :------: |
| UART | 支持 | UART0~9 |
# for module compiling
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')
import os
import sys
import rtconfig
from rtconfig import RTT_ROOT
sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
from building import *
TARGET = 'rtthread.' + rtconfig.TARGET_EXT
DefaultEnvironment(tools=[])
env = Environment(tools = ['mingw'],
AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS,
CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS,
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')
# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT, has_libcpu = False)
# make a building
DoBuilding(TARGET, objs)
from building import *
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
*/
#include <rtthread.h>
int main(int argc, char** argv)
{
rt_kprintf("Hi, this is RT-Thread!!\n");
return 0;
}
menu "Hardware Drivers Config"
menuconfig BSP_USING_UART
bool "Using UART"
select RT_USING_SERIAL
default y
if BSP_USING_UART
config RT_USING_UART0
bool "Enable UART 0"
default n
config RT_USING_UART1
bool "Enable UART 1"
default n
config RT_USING_UART2
bool "Enable UART 2"
default y
config RT_USING_UART3
bool "Enable UART 3"
default n
config RT_USING_UART4
bool "Enable UART 4"
default n
config RT_USING_UART5
bool "Enable UART 5"
default n
config RT_USING_UART6
bool "Enable UART 6"
default n
config RT_USING_UART7
bool "Enable UART 7"
default n
config RT_USING_UART8
bool "Enable UART 8"
default n
config RT_USING_UART9
bool "Enable UART 9"
default n
endif
config BSP_USING_GIC
bool
default y
config BSP_USING_GICV3
bool
default y
endmenu
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
list = os.listdir(cwd)
CPPPATH = [cwd]
objs = []
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
objs = objs + group
Return('objs')
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-3-08 GuEe-GUI the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <mmu.h>
#include <psci.h>
#include <gicv3.h>
#include <gtimer.h>
#include <cpuport.h>
#include <interrupt.h>
#include <board.h>
#include <drv_uart.h>
struct mem_desc platform_mem_desc[] =
{
{0x200000, 0x80000000, 0x200000, NORMAL_MEM},
{UART0_MMIO_BASE, UART0_MMIO_BASE + 0x10000, UART0_MMIO_BASE, DEVICE_MEM},
{UART1_MMIO_BASE, UART1_MMIO_BASE + 0x90000, UART1_MMIO_BASE, DEVICE_MEM},
{GIC_PL600_DISTRIBUTOR_PPTR, GIC_PL600_DISTRIBUTOR_PPTR + 0x10000, GIC_PL600_DISTRIBUTOR_PPTR, DEVICE_MEM},
{GIC_PL600_REDISTRIBUTOR_PPTR, GIC_PL600_REDISTRIBUTOR_PPTR + 0xc0000, GIC_PL600_REDISTRIBUTOR_PPTR, DEVICE_MEM},
};
const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc) / sizeof(platform_mem_desc[0]);
void idle_wfi(void)
{
__asm__ volatile ("wfi");
}
void rt_hw_board_init(void)
{
rt_hw_init_mmu_table(platform_mem_desc, platform_mem_desc_size);
rt_hw_mmu_init();
/* initialize hardware interrupt */
rt_hw_interrupt_init();
/* initialize uart */
rt_hw_uart_init();
/* initialize timer for os tick */
rt_hw_gtimer_init();
rt_thread_idle_sethook(idle_wfi);
arm_psci_init(PSCI_METHOD_SMC, RT_NULL, RT_NULL);
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
/* set console device */
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#ifdef RT_USING_HEAP
/* initialize memory system */
rt_kprintf("heap: [0x%08x - 0x%08x]\n", RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
rt_system_heap_init(RT_HW_HEAP_BEGIN, RT_HW_HEAP_END);
#endif
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#ifdef RT_USING_SMP
/* install IPI handle */
rt_hw_ipi_handler_install(RT_SCHEDULE_IPI, rt_scheduler_ipi_handler);
arm_gic_umask(0, IRQ_ARM_IPI_KICK);
#endif
}
void reboot(void)
{
arm_psci_system_reboot();
}
MSH_CMD_EXPORT(reboot, reboot...);
#ifdef RT_USING_SMP
rt_uint64_t rt_cpu_mpidr_early[] =
{
[0] = 0x81000000,
[1] = 0x81000100,
[2] = 0x81000200,
[3] = 0x81000300,
};
void rt_hw_secondary_cpu_up(void)
{
int i;
extern void secondary_cpu_start(void);
for (i = 1; i < RT_CPUS_NR; ++i)
{
arm_psci_cpu_on(rt_cpu_mpidr_early[i], (rt_uint64_t)secondary_cpu_start);
}
}
void secondary_cpu_c_start(void)
{
rt_hw_mmu_init();
rt_hw_spin_lock(&_cpus_lock);
arm_gic_cpu_init(0, platform_get_gic_cpu_base());
arm_gic_redist_init(0, platform_get_gic_redist_base());
rt_hw_vector_init();
rt_hw_gtimer_local_enable();
arm_gic_umask(0, IRQ_ARM_IPI_KICK);
rt_kprintf("\rcall cpu %d on success\n", rt_hw_cpu_id());
rt_system_scheduler_start();
}
void rt_hw_secondary_cpu_idle_exec(void)
{
__WFE();
}
#endif
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-5-30 Bernard the first version
*/
#ifndef __BOARD_H__
#define __BOARD_H__
#include <rk3568.h>
extern unsigned char __bss_start;
extern unsigned char __bss_end;
#define RT_HW_HEAP_BEGIN (void *)&__bss_end
#define RT_HW_HEAP_END (void *)(RT_HW_HEAP_BEGIN + 64 * 1024 * 1024)
void rt_hw_board_init(void);
#endif /* __BOARD_H__ */
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-3-08 GuEe-GUI the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
/*
* The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#define UART_RX 0 /* In: Receive buffer */
#define UART_TX 0 /* Out: Transmit buffer */
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
#define UART_SSR 0x22 /* In: Software Reset Register */
#define UART_USR 0x1f /* UART Status Register */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_PARITY 0x8 /* Parity Enable */
#define UART_LCR_STOP 0x4 /* Stop bits: 0=1 bit, 1=2 bits */
#define UART_LCR_WLEN8 0x3 /* Wordlength: 8 bits */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_MCR_RTS 0x02 /* RTS complement */
#define UART_LSR 5 /* In: Line Status Register */
#define UART_LSR_BI 0x10 /* Break interrupt indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */
#define UART_IIR_RX_TIMEOUT 0x0c /* OMAP RX Timeout interrupt */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_FCR_EN_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
#define UART_REG_SHIFT 0x2 /* Register Shift*/
#define UART_INPUT_CLK 24000000
struct hw_uart_device
{
rt_ubase_t hw_base;
rt_uint32_t irqno;
#ifdef RT_USING_SMP
struct rt_spinlock spinlock;
#endif
};
#define BSP_DEFINE_UART_DEVICE(no) \
static struct hw_uart_device _uart##no##_device = \
{ \
UART##no##_MMIO_BASE, \
UART##no##_IRQ \
}; \
static struct rt_serial_device _serial##no;
#ifdef RT_USING_UART0
BSP_DEFINE_UART_DEVICE(0);
#endif
#ifdef RT_USING_UART1
BSP_DEFINE_UART_DEVICE(1);
#endif
#ifdef RT_USING_UART2
BSP_DEFINE_UART_DEVICE(2);
#endif
#ifdef RT_USING_UART3
BSP_DEFINE_UART_DEVICE(3);
#endif
#ifdef RT_USING_UART4
BSP_DEFINE_UART_DEVICE(4);
#endif
#ifdef RT_USING_UART5
BSP_DEFINE_UART_DEVICE(5);
#endif
#ifdef RT_USING_UART6
BSP_DEFINE_UART_DEVICE(6);
#endif
#ifdef RT_USING_UART7
BSP_DEFINE_UART_DEVICE(7);
#endif
#ifdef RT_USING_UART8
BSP_DEFINE_UART_DEVICE(8);
#endif
#ifdef RT_USING_UART9
BSP_DEFINE_UART_DEVICE(9);
#endif
rt_inline rt_uint32_t dw8250_read32(rt_ubase_t addr, rt_ubase_t offset)
{
return *((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT)));
}
rt_inline void dw8250_write32(rt_ubase_t addr, rt_ubase_t offset, rt_uint32_t value)
{
*((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT))) = value;
if (offset == UART_LCR)
{
int tries = 1000;
/* Make sure LCR write wasn't ignored */
while (tries--)
{
unsigned int lcr = dw8250_read32(addr, UART_LCR);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
{
return;
}
dw8250_write32(addr, UART_FCR, UART_FCR_EN_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
dw8250_read32(addr, UART_RX);
*((volatile rt_uint32_t *)(addr + (offset << UART_REG_SHIFT))) = value;
}
}
}
static rt_err_t dw8250_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
rt_base_t base, rate;
struct hw_uart_device *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device *)serial->parent.user_data;
base = uart->hw_base;
#ifdef RT_USING_SMP
rt_spin_lock_init(&uart->spinlock);
#endif
/* Resset UART */
dw8250_write32(base, UART_SSR, 1);
dw8250_write32(base, UART_SSR, 0);
dw8250_write32(base, UART_IER, !UART_IER_RDI);
dw8250_write32(base, UART_FCR, UART_FCR_EN_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
/* Disable flow ctrl */
dw8250_write32(base, UART_MCR, 0);
/* Clear RTS */
dw8250_write32(base, UART_MCR, dw8250_read32(base, UART_MCR) | UART_MCR_RTS);
rate = UART_INPUT_CLK / 16 / serial->config.baud_rate;
/* Enable access DLL & DLH */
dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) | UART_LCR_DLAB);
dw8250_write32(base, UART_DLL, (rate & 0xff));
dw8250_write32(base, UART_DLM, (rate & 0xff00) >> 8);
/* Clear DLAB bit */
dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_DLAB));
dw8250_write32(base, UART_LCR, (dw8250_read32(base, UART_LCR) & (~UART_LCR_WLEN8)) | UART_LCR_WLEN8);
dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_STOP));
dw8250_write32(base, UART_LCR, dw8250_read32(base, UART_LCR) & (~UART_LCR_PARITY));
dw8250_write32(base, UART_IER, UART_IER_RDI);
return RT_EOK;
}
static rt_err_t dw8250_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 */
dw8250_write32(uart->hw_base, UART_IER, !UART_IER_RDI);
rt_hw_interrupt_mask(uart->irqno);
break;
case RT_DEVICE_CTRL_SET_INT:
/* Enable rx irq */
dw8250_write32(uart->hw_base, UART_IER, UART_IER_RDI);
rt_hw_interrupt_umask(uart->irqno);
break;
}
return RT_EOK;
}
static int dw8250_uart_putc(struct rt_serial_device *serial, char c)
{
rt_base_t base;
struct hw_uart_device *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device *)serial->parent.user_data;
base = uart->hw_base;
while ((dw8250_read32(base, UART_USR) & 0x2) == 0)
{
}
dw8250_write32(base, UART_TX, c);
return 1;
}
static int dw8250_uart_getc(struct rt_serial_device *serial)
{
int ch = -1;
rt_base_t base;
struct hw_uart_device *uart;
RT_ASSERT(serial != RT_NULL);
uart = (struct hw_uart_device *)serial->parent.user_data;
base = uart->hw_base;
if ((dw8250_read32(base, UART_LSR) & 0x1))
{
ch = dw8250_read32(base, UART_RX) & 0xff;
}
return ch;
}
static const struct rt_uart_ops _uart_ops =
{
dw8250_uart_configure,
dw8250_uart_control,
dw8250_uart_putc,
dw8250_uart_getc,
};
static void rt_hw_uart_isr(int irqno, void *param)
{
unsigned int iir, status;
struct rt_serial_device *serial = (struct rt_serial_device *)param;
struct hw_uart_device *uart = (struct hw_uart_device *)serial->parent.user_data;
iir = dw8250_read32(uart->hw_base, UART_IIR);
/* If don't do this in non-DMA mode then the "RX TIMEOUT" interrupt will fire forever. */
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT)
{
#ifdef RT_USING_SMP
rt_base_t level = rt_spin_lock_irqsave(&uart->spinlock);
#endif
status = dw8250_read32(uart->hw_base, UART_LSR);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
{
dw8250_read32(uart->hw_base, UART_RX);
}
#ifdef RT_USING_SMP
rt_spin_unlock_irqrestore(&uart->spinlock, level);
#endif
}
if (!(iir & UART_IIR_NO_INT))
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
}
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY)
{
/* Clear the USR */
dw8250_read32(uart->hw_base, UART_USR);
return;
}
}
int rt_hw_uart_init(void)
{
struct hw_uart_device *uart;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
config.baud_rate = 1500000;
#define BSP_INSTALL_UART_DEVICE(no) \
uart = &_uart##no##_device; \
_serial##no.ops = &_uart_ops; \
_serial##no.config = config; \
rt_hw_serial_register(&_serial##no, "uart" #no, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); \
rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, &_serial##no, "uart" #no);
#ifdef RT_USING_UART0
BSP_INSTALL_UART_DEVICE(0);
#endif
#ifdef RT_USING_UART1
BSP_INSTALL_UART_DEVICE(1);
#endif
#ifdef RT_USING_UART2
BSP_INSTALL_UART_DEVICE(2);
#endif
#ifdef RT_USING_UART3
BSP_INSTALL_UART_DEVICE(3);
#endif
#ifdef RT_USING_UART4
BSP_INSTALL_UART_DEVICE(4);
#endif
#ifdef RT_USING_UART5
BSP_INSTALL_UART_DEVICE(5);
#endif
#ifdef RT_USING_UART6
BSP_INSTALL_UART_DEVICE(6);
#endif
#ifdef RT_USING_UART7
BSP_INSTALL_UART_DEVICE(7);
#endif
#ifdef RT_USING_UART8
BSP_INSTALL_UART_DEVICE(8);
#endif
#ifdef RT_USING_UART9
BSP_INSTALL_UART_DEVICE(9);
#endif
return 0;
}
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-3-08 GuEe-GUI the first version
*/
#ifndef __DRV_UART_H__
#define __DRV_UART_H__
int rt_hw_uart_init(void);
#endif /* __DRV_UART_H__ */
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-3-08 GuEe-GUI the first version
*/
#ifndef __RK3568_H__
#define __RK3568_H__
/* UART */
#define UART_MMIO_BASE 0xfe650000
#define UART0_MMIO_BASE 0xfdd50000
#define UART1_MMIO_BASE (UART_MMIO_BASE + 0)
#define UART2_MMIO_BASE (UART_MMIO_BASE + 0x10000)
#define UART3_MMIO_BASE (UART_MMIO_BASE + 0x20000)
#define UART4_MMIO_BASE (UART_MMIO_BASE + 0x30000)
#define UART5_MMIO_BASE (UART_MMIO_BASE + 0x40000)
#define UART6_MMIO_BASE (UART_MMIO_BASE + 0x50000)
#define UART7_MMIO_BASE (UART_MMIO_BASE + 0x60000)
#define UART8_MMIO_BASE (UART_MMIO_BASE + 0x70000)
#define UART9_MMIO_BASE (UART_MMIO_BASE + 0x80000)
#define UART_MMIO_SIZE 0x100
#define UART_IRQ_BASE (32 + 116)
#define UART0_IRQ (UART_IRQ_BASE + 0)
#define UART1_IRQ (UART_IRQ_BASE + 1)
#define UART2_IRQ (UART_IRQ_BASE + 2)
#define UART3_IRQ (UART_IRQ_BASE + 3)
#define UART4_IRQ (UART_IRQ_BASE + 4)
#define UART5_IRQ (UART_IRQ_BASE + 5)
#define UART6_IRQ (UART_IRQ_BASE + 6)
#define UART7_IRQ (UART_IRQ_BASE + 7)
#define UART8_IRQ (UART_IRQ_BASE + 8)
#define UART9_IRQ (UART_IRQ_BASE + 9)
/* GPIO */
#define GPIO0_MMIO_BASE 0xfdd60000
#define GPIO1_MMIO_BASE 0xfe740000
#define GPIO2_MMIO_BASE 0xfe750000
#define GPIO3_MMIO_BASE 0xfe760000
#define GPIO4_MMIO_BASE 0xfe770000
#define GPIO_MMIO_SIZE 0x100
#define GPIO_IRQ_BASE (32 + 33)
#define GPIO0_IRQ (GPIO_IRQ_BASE + 0)
#define GPIO1_IRQ (GPIO_IRQ_BASE + 1)
#define GPIO2_IRQ (GPIO_IRQ_BASE + 2)
#define GPIO3_IRQ (GPIO_IRQ_BASE + 3)
#define GPIO4_IRQ (GPIO_IRQ_BASE + 4)
/* MMC */
#define MMC0_MMIO_BASE 0xfe310000 /* sdhci */
#define MMC1_MMIO_BASE 0xfe2b0000 /* sdmmc0 */
#define MMC2_MMIO_BASE 0xfe2c0000 /* sdmmc1 */
#define MMC3_MMIO_BASE 0xfe000000 /* sdmmc2 */
#define MMC0_MMIO_SIZE 0x10000
#define MMC_MMIO_SIZE 0x4000
#define MMC0_IRQ (32 + 19)
#define MMC1_IRQ (32 + 98)
#define MMC2_IRQ (32 + 99)
#define MMC3_IRQ (32 + 100)
/* Ethernet */
#define GMAC0_MMIO_BASE 0xfe2a0000
#define GMAC1_MMIO_BASE 0xfe010000
#define GMAC_MMIO_SIZE 0x10000
#define GMAC0_MAC_IRQ (32 + 27)
#define GMAC0_WAKE_IRQ (32 + 24)
#define GMAC1_MAC_IRQ (32 + 32)
#define GMAC1_WAKE_IRQ (32 + 29)
/* GIC */
#define MAX_HANDLERS 256
#define GIC_IRQ_START 0
#define ARM_GIC_NR_IRQS 256
#define ARM_GIC_MAX_NR 1
#define IRQ_ARM_IPI_KICK 0
#define IRQ_ARM_IPI_CALL 1
#define GIC_PL600_DISTRIBUTOR_PPTR 0xfd400000
#define GIC_PL600_REDISTRIBUTOR_PPTR 0xfd460000
#define GIC_PL600_CONTROLLER_PPTR RT_NULL
#define GIC_PL600_ITS_PPTR 0xfd440000
rt_inline rt_uint32_t platform_get_gic_dist_base(void)
{
return GIC_PL600_DISTRIBUTOR_PPTR;
}
rt_inline rt_uint32_t platform_get_gic_redist_base(void)
{
return GIC_PL600_REDISTRIBUTOR_PPTR;
}
rt_inline rt_uint32_t platform_get_gic_cpu_base(void)
{
return GIC_PL600_CONTROLLER_PPTR;
}
rt_inline rt_uint32_t platform_get_gic_its_base(void)
{
return GIC_PL600_ITS_PPTR;
}
#endif /* __RK3568_H__ */
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-5-30 bernard first version
*/
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
SECTIONS
{
. = 0x208000;
. = ALIGN(4096);
.text :
{
KEEP(*(.text.entrypoint)) /* The entry point */
*(.vectors)
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t*)
*(COMMON)
/* section information for finsh shell */
. = ALIGN(16);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(16);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(16);
/* section information for initial. */
. = ALIGN(16);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(16);
. = ALIGN(16);
_etext = .;
}
.eh_frame_hdr :
{
*(.eh_frame_hdr)
*(.eh_frame_entry)
}
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
. = ALIGN(16);
.data :
{
*(.data)
*(.data.*)
*(.data1)
*(.data1.*)
. = ALIGN(16);
_gp = ABSOLUTE(.); /* Base of small data */
*(.sdata)
*(.sdata.*)
}
. = ALIGN(16);
.ctors :
{
PROVIDE(__ctors_start__ = .);
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
PROVIDE(__ctors_end__ = .);
}
.dtors :
{
PROVIDE(__dtors_start__ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(__dtors_end__ = .);
}
. = ALIGN(16);
.bss :
{
PROVIDE(__bss_start = .);
*(.bss)
*(.bss.*)
*(.dynbss)
. = ALIGN(16);
PROVIDE(__bss_end = .);
}
_end = .;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}
__bss_size = SIZEOF(.bss);
#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__
/* Automatically generated file; DO NOT EDIT. */
/* RT-Thread Project Configuration */
/* RT-Thread Kernel */
#define RT_NAME_MAX 8
#define RT_ALIGN_SIZE 4
#define RT_THREAD_PRIORITY_32
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND 100
#define RT_USING_OVERFLOW_CHECK
#define RT_USING_HOOK
#define RT_HOOK_USING_FUNC_PTR
#define RT_USING_IDLE_HOOK
#define RT_IDLE_HOOK_LIST_SIZE 4
#define IDLE_THREAD_STACK_SIZE 4096
#define RT_USING_TIMER_SOFT
#define RT_TIMER_THREAD_PRIO 4
#define RT_TIMER_THREAD_STACK_SIZE 4096
/* kservice optimization */
#define RT_DEBUG
#define RT_DEBUG_COLOR
/* Inter-Thread communication */
#define RT_USING_SEMAPHORE
#define RT_USING_MUTEX
#define RT_USING_EVENT
#define RT_USING_MAILBOX
#define RT_USING_MESSAGEQUEUE
/* Memory Management */
#define RT_USING_MEMPOOL
#define RT_USING_SMALL_MEM
#define RT_USING_MEMHEAP
#define RT_MEMHEAP_FAST_MODE
#define RT_USING_SMALL_MEM_AS_HEAP
#define RT_USING_MEMTRACE
#define RT_USING_HEAP
/* Kernel Device Object */
#define RT_USING_DEVICE
#define RT_USING_DEVICE_OPS
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 128
#define RT_CONSOLE_DEVICE_NAME "uart2"
#define RT_VER_NUM 0x40100
#define ARCH_CPU_64BIT
#define ARCH_ARMV8
/* RT-Thread Components */
#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 8192
#define RT_MAIN_THREAD_PRIORITY 10
#define RT_USING_MSH
#define RT_USING_FINSH
#define FINSH_USING_MSH
#define FINSH_THREAD_NAME "tshell"
#define FINSH_THREAD_PRIORITY 20
#define FINSH_THREAD_STACK_SIZE 4096
#define FINSH_USING_HISTORY
#define FINSH_HISTORY_LINES 5
#define FINSH_USING_SYMTAB
#define FINSH_CMD_SIZE 80
#define MSH_USING_BUILT_IN_COMMANDS
#define FINSH_USING_DESCRIPTION
#define FINSH_ARG_MAX 10
/* Device Drivers */
#define RT_USING_DEVICE_IPC
#define RT_USING_SERIAL
#define RT_USING_SERIAL_V1
#define RT_SERIAL_RB_BUFSZ 64
#define RT_USING_PIN
/* Using USB */
/* C/C++ and POSIX layer */
#define RT_LIBC_DEFAULT_TIMEZONE 8
/* POSIX (Portable Operating System Interface) layer */
/* Interprocess Communication (IPC) */
/* Socket is in the 'Network' category */
/* Network */
/* Utilities */
/* RT-Thread Utestcases */
/* RT-Thread online packages */
/* IoT - internet of things */
/* Wi-Fi */
/* Marvell WiFi */
/* Wiced WiFi */
/* IoT Cloud */
/* security packages */
/* language packages */
/* multimedia packages */
/* LVGL: powerful and easy-to-use embedded GUI library */
/* u8g2: a monochrome graphic library */
/* PainterEngine: A cross-platform graphics application framework written in C language */
/* tools packages */
/* system packages */
/* enhanced kernel services */
/* POSIX extension functions */
/* acceleration: Assembly language or algorithmic acceleration packages */
/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
/* Micrium: Micrium software products porting for RT-Thread */
/* peripheral libraries and drivers */
/* AI packages */
/* miscellaneous packages */
/* project laboratory */
/* samples: kernel and components samples */
/* entertainment: terminal games and other interesting software packages */
#define SOC_RK3568
/* Hardware Drivers Config */
#define BSP_USING_UART
#define RT_USING_UART2
#define BSP_USING_GIC
#define BSP_USING_GICV3
#endif
import os
# toolchains options
ARCH ='aarch64'
CPU ='cortex-a'
CROSS_TOOL ='gcc'
if os.getenv('RTT_ROOT'):
RTT_ROOT = os.getenv('RTT_ROOT')
else:
RTT_ROOT = os.path.join(os.getcwd(), '..', '..', '..')
if os.getenv('RTT_CC'):
CROSS_TOOL = os.getenv('RTT_CC')
PLATFORM = 'gcc'
EXEC_PATH = r'/opt/gcc-arm-8.3-2019.03-x86_64-aarch64-elf/bin/'
if os.getenv('RTT_EXEC_PATH'):
EXEC_PATH = os.getenv('RTT_EXEC_PATH')
BUILD = 'debug'
if PLATFORM == 'gcc':
# toolchains
PREFIX = 'aarch64-none-elf-'
CC = PREFIX + 'gcc'
CXX = PREFIX + 'g++'
AS = PREFIX + 'gcc'
AR = PREFIX + 'ar'
LINK = PREFIX + 'gcc'
TARGET_EXT = 'elf'
SIZE = PREFIX + 'size'
OBJDUMP = PREFIX + 'objdump'
OBJCPY = PREFIX + 'objcopy'
DEVICE = ' -g -march=armv8-a -mtune=cortex-a55'
CFLAGS = DEVICE + ' -Wall'
AFLAGS = ' -c' + ' -x assembler-with-cpp -D__ASSEMBLY__'
LFLAGS = DEVICE + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds'
CPATH = ''
LPATH = ''
if BUILD == 'debug':
CFLAGS += ' -O0 -gdwarf-2'
AFLAGS += ' -gdwarf-2'
else:
CFLAGS += ' -O2'
CXXFLAGS = CFLAGS
DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n'
POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'
......@@ -26,6 +26,9 @@ extern "C" {
/*
* Some macros define
*/
#ifndef HWREG64
#define HWREG64(x) (*((volatile rt_uint64_t *)(x)))
#endif
#ifndef HWREG32
#define HWREG32(x) (*((volatile rt_uint32_t *)(x)))
#endif
......
......@@ -6,10 +6,6 @@ Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp') + Glob('*.S')
if not GetDepend('BSP_USING_GIC'):
SrcRemove(src, 'gic.c')
CPPPATH = [cwd]
group = DefineGroup('common', src, depend = [''], CPPPATH = CPPPATH)
......
......@@ -9,20 +9,25 @@
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
* 2022-03-08 GuEe-GUI add BSP bind SPI CPU self support
*/
#include <rthw.h>
#include <rtthread.h>
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2)
#include <gic.h>
#include <cpuport.h>
#include <board.h>
struct arm_gic
{
rt_uint64_t offset; /* the first interrupt index in the vector table */
rt_uint64_t dist_hw_base; /* the base address of the gic distributor */
rt_uint64_t cpu_hw_base; /* the base addrees of the gic cpu interface */
rt_uint64_t cpu_hw_base; /* the base address of the gic cpu interface */
};
/* 'ARM_GIC_MAX_NR' is the number of cores */
......@@ -30,33 +35,33 @@ static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
#define GIC_CPU_CTRL(hw_base) HWREG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) HWREG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) HWREG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) HWREG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) HWREG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) HWREG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) HWREG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) HWREG32((hw_base) + 0xFCU)
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
#define GIC_DIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) HWREG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) HWREG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) HWREG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) HWREG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) HWREG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) HWREG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) HWREG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) HWREG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) HWREG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) HWREG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) HWREG32((hw_base) + 0xfe8U)
static unsigned int _gic_max_irq;
......@@ -179,7 +184,7 @@ void arm_gic_clear_pending_irq(rt_uint64_t index, int irq)
}
}
void arm_gic_set_configuration(rt_uint64_t index, int irq, uint32_t config)
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config)
{
rt_uint64_t icfgr;
rt_uint64_t shift;
......@@ -323,6 +328,8 @@ void arm_gic_send_sgi(rt_uint64_t index, int irq, rt_uint64_t target_list, rt_ui
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) =
((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
__DSB();
}
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index)
......@@ -341,8 +348,8 @@ rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index)
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group)
{
uint32_t igroupr;
uint32_t shift;
rt_uint32_t igroupr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(group <= 1U);
......@@ -373,6 +380,10 @@ int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start)
unsigned int gic_type, i;
rt_uint64_t cpumask = 1U << 0U;
#ifdef ARM_SPI_BIND_CPU_ID
cpumask = 1U << ARM_SPI_BIND_CPU_ID;
#endif
RT_ASSERT(index < ARM_GIC_MAX_NR);
_gic_table[index].dist_hw_base = dist_base;
......@@ -502,3 +513,4 @@ long gic_dump(void)
}
MSH_CMD_EXPORT(gic_dump, show gic status);
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */
......@@ -11,9 +11,9 @@
#ifndef __GIC_H__
#define __GIC_H__
#include <rthw.h>
#include <stdint.h>
#include <board.h>
#include <rtdef.h>
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2)
int arm_gic_get_active_irq(rt_uint64_t index);
void arm_gic_ack(rt_uint64_t index, int irq);
......@@ -25,7 +25,7 @@ rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq);
void arm_gic_set_pending_irq(rt_uint64_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq);
void arm_gic_set_configuration(rt_uint64_t index, int irq, uint32_t config);
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config);
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq);
void arm_gic_clear_active(rt_uint64_t index, int irq);
......@@ -59,5 +59,7 @@ int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base);
void arm_gic_dump_type(rt_uint64_t index);
void arm_gic_dump(rt_uint64_t index);
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */
#endif
此差异已折叠。
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
*/
#ifndef __GICV3_H__
#define __GICV3_H__
#include <rtdef.h>
#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV3)
#define GICV3_ROUTED_TO_ALL 1UL
#define GICV3_ROUTED_TO_SPEC 0UL
int arm_gic_get_active_irq(rt_uint64_t index);
void arm_gic_ack(rt_uint64_t index, int irq);
void arm_gic_mask(rt_uint64_t index, int irq);
void arm_gic_umask(rt_uint64_t index, int irq);
rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq);
void arm_gic_set_pending_irq(rt_uint64_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint64_t index, int irq);
void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config);
rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq);
void arm_gic_clear_active(rt_uint64_t index, int irq);
void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask);
rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq);
void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority);
rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq);
void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority);
rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index);
void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point);
rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index);
rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq);
#ifdef RT_USING_SMP
void arm_gic_send_affinity_sgi(rt_uint64_t index, int irq, rt_uint64_t cpu_masks[], rt_uint64_t routing_mode);
#endif
rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index);
rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index);
void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group);
rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq);
int arm_gic_redist_address_set(rt_uint64_t index, rt_uint64_t redist_addr, int cpu_id);
int arm_gic_cpu_interface_address_set(rt_uint64_t index, rt_uint64_t interface_addr, int cpu_id);
int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start);
int arm_gic_redist_init(rt_uint64_t index, rt_uint64_t redist_base);
int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base);
void arm_gic_dump_type(rt_uint64_t index);
void arm_gic_dump(rt_uint64_t index);
#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) */
#endif
......@@ -13,6 +13,7 @@
#include <rtthread.h>
#include "interrupt.h"
#include "gic.h"
#include "gicv3.h"
#include "armv8.h"
#include "mmu.h"
#include "cpuport.h"
......@@ -52,6 +53,9 @@ void rt_hw_interrupt_init(void)
/* initialize ARM GIC */
arm_gic_dist_init(0, platform_get_gic_dist_base(), GIC_IRQ_START);
arm_gic_cpu_init(0, platform_get_gic_cpu_base());
#ifdef BSP_USING_GICV3
arm_gic_redist_init(0, platform_get_gic_redist_base());
#endif
#endif
}
......@@ -346,7 +350,11 @@ rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
{
#ifdef BSP_USING_GIC
#ifdef BSP_USING_GICV2
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
#else
arm_gic_send_affinity_sgi(0, ipi_vector, (rt_uint64_t *)&cpu_mask, GICV3_ROUTED_TO_SPEC);
#endif
#else
int i;
......@@ -359,8 +367,9 @@ void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
IPI_MAILBOX_SET(i) = 1 << ipi_vector;
}
}
#endif
__DSB();
#endif
}
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
......
......@@ -29,11 +29,19 @@ static psci_call_handle psci_call = psci_smc_call;
static uint64_t shutdown_args[3] = {0, 0, 0};
static uint64_t reboot_args[3] = {0, 0, 0};
void arm_psci_init(uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args)
void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args)
{
if (rt_hw_get_current_el() < 2)
switch (method)
{
psci_call = psci_hvc_call;
case PSCI_METHOD_SMC:
psci_call = psci_smc_call;
break;
case PSCI_METHOD_HVC:
if (rt_hw_get_current_el() < 2)
{
psci_call = psci_hvc_call;
}
break;
}
if (platform_shutdown_args != RT_NULL)
......
......@@ -18,6 +18,9 @@
*/
#define PSCI_VER_0_2 0x00000002
#define PSCI_METHOD_SMC 3
#define PSCI_METHOD_HVC 2
/* PSCI 0.2 interface */
#define PSCI_0_2_FN_BASE 0x84000000
#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n))
......@@ -114,7 +117,7 @@
#define PSCI_RET_DISABLED (-8)
#define PSCI_RET_INVALID_ADDRESS (-9)
void arm_psci_init(uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args);
void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args);
uint32_t arm_psci_get_version();
uint32_t arm_psci_get_affinity_info(uint64_t target_affinity, uint64_t lowest_affinity_level);
......
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
......@@ -11,19 +11,28 @@
*/
#include "rtconfig.h"
.section ".text.entrypoint","ax"
#define SECONDARY_STACK_SIZE 4096
.section ".text.entrypoint","ax"
.globl _start
.globl secondary_cpu_start
_start:
#ifdef RT_USING_SMP
mrs x1, mpidr_el1
and x1, x1, #0xff
cbnz x1, cpu_idle /* If cpu id > 0, stop slave cores */
adr x4, .boot_cpu_mpidr
str x1, [x4]
dsb sy
#endif
bl __asm_flush_dcache_all /* The kernel and data must flush to DDR */
secondary_cpu_start:
#ifdef RT_USING_SMP
adr x4, .boot_cpu_mpidr
ldr x4, [x4]
dsb sy
/* Read cpu mpidr_el1 */
mrs x1, mpidr_el1
......@@ -34,6 +43,7 @@ secondary_cpu_start:
cpu_id_confirm:
add x2, x2, #1 /* Next cpu id inc */
ldr x3, [x0], #8
dsb sy
cmp x3, #0
beq cpu_idle /* Mean that `rt_cpu_mpidr_early' table is end */
cmp x3, x1
......@@ -42,7 +52,8 @@ cpu_id_confirm:
/* Get cpu id success */
sub x0, x2, #1
msr tpidr_el1, x0 /* Save cpu id global */
cbz x0, cpu_setup /* Only go to cpu_setup when cpu id = 0 */
cmp x3, x4 /* If it is boot cpu */
beq boot_cpu_setup
/* Set current cpu's stack top */
sub x0, x0, #1
......@@ -53,14 +64,9 @@ cpu_id_confirm:
b cpu_check_el
#else
msr tpidr_el1, xzr
b cpu_setup
#endif /* RT_USING_SMP */
cpu_idle:
wfe
b cpu_idle
cpu_setup:
boot_cpu_setup:
ldr x1, =_start
cpu_check_el:
......@@ -75,7 +81,7 @@ cpu_check_el:
mov x2, #(1 << 0) /* EL0 and EL1 are in Non-Secure state */
orr x2, x2, #(1 << 4) /* RES1 */
orr x2, x2, #(1 << 5) /* RES1 */
orr x2, x2, #(1 << 7) /* SMC instructions are undefined at EL1 and above */
bic x2, x2, #(1 << 7) /* SMC instructions are enabled at EL1 and above */
orr x2, x2, #(1 << 8) /* HVC instructions are enabled at EL1 and above */
orr x2, x2, #(1 << 10) /* The next lower level is AArch64 */
msr scr_el3, x2
......@@ -91,7 +97,7 @@ cpu_check_el:
eret
cpu_not_in_el3: /* Running at EL2 or EL1 */
cmp x0, #4 /* EL1 = 0100 */
cmp x0, #4 /* EL1 = 0100 */
beq cpu_in_el1
cpu_in_el2:
......@@ -159,9 +165,16 @@ clean_bss_check:
jump_to_entry:
b rtthread_startup
b cpu_idle /* For failsafe, halt this core too */
cpu_idle:
wfe
b cpu_idle
#ifdef RT_USING_SMP
.align 3
.boot_cpu_mpidr:
.quad 0x0
.align 12
.secondary_cpu_stack:
.space (SECONDARY_STACK_SIZE * (RT_CPUS_NR - 1))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册