diff --git a/bsp/cvitek/README.md b/bsp/cvitek/README.md index 80a23f1ede..8a7dffc1a9 100755 --- a/bsp/cvitek/README.md +++ b/bsp/cvitek/README.md @@ -1,25 +1,33 @@ -- [参考文档](#参考文档) -- [概述](#概述) -- [BSP 支持情况](#bsp-支持情况) - - [驱动支持列表](#驱动支持列表) -- [编译](#编译) - - [Toolchain 下载](#toolchain-下载) - - [依赖安装](#依赖安装) - - [构建](#构建) -- [运行](#运行) -- [FAQ](#faq) -- [联系人信息](#联系人信息) +- [1. 参考文档](#1-参考文档) +- [2. 概述](#2-概述) +- [3. BSP 支持情况](#3-bsp-支持情况) + - [3.1. 驱动支持列表](#31-驱动支持列表) +- [4. 编译](#4-编译) + - [4.1. Toolchain 下载](#41-toolchain-下载) + - [4.2. 依赖安装](#42-依赖安装) + - [4.3. 构建](#43-构建) + - [4.3.1. 开发板选择](#431-开发板选择) + - [4.3.2. 开启 RT-Smart](#432-开启-rt-smart) + - [4.3.3. 编译](#433-编译) +- [5. 运行](#5-运行) +- [6. 大核 RT-Smart 启动并自动挂载根文件系统](#6-大核-rt-smart-启动并自动挂载根文件系统) + - [6.1. 内核构建配置](#61-内核构建配置) + - [6.2. 构建文件系统](#62-构建文件系统) + - [6.3. 将文件系统写入 sd-card](#63-将文件系统写入-sd-card) + - [6.4. 上电启动](#64-上电启动) +- [7. FAQ](#7-faq) +- [8. 联系人信息](#8-联系人信息) -# 参考文档 +# 1. 参考文档 - 【参考 1】CV1800B/CV1801B Datasheet(中文版): - 【参考 2】SG2002/SG2000 技术参考手册(中文版):。官方定期发布 pdf 形式。可以下载下载最新版本的中文版本技术参考手册:`sg2002_trm_cn.pdf` 或者 `sg2000_trm_cn.pdf`。 -# 概述 +# 2. 概述 支持开发板以及集成 SoC 芯片信息如下 @@ -38,7 +46,7 @@ Duo 家族开发板采用 CV18xx 系列芯片。芯片的工作模式总结如 - 大核(RISC-V C906@1GHz)+ 小核(RISC-V C906@700MHz)。 - 大核(ARM Cortex-A53@1GHz)+ 小核(RISC-V C906@700MHz)。 -# BSP 支持情况 +# 3. BSP 支持情况 由于大小核的存在,以及不同 SoC 下不同工作模式的存在,bsp/cvitek 提供了三种不同 BSP/OS,需要单独编译。 @@ -52,7 +60,7 @@ Duo 家族开发板采用 CV18xx 系列芯片。芯片的工作模式总结如 > 注:不同开发板 uart 输出管脚不同,默认配置可能导致串口无法正常显示,请根据开发板 uart 通过 `scons --menuconfig` 配置对应 uart 的输出管脚。 -## 驱动支持列表 +## 3.1. 驱动支持列表 | 驱动 | 支持情况 | 备注 | | :---- | :------- | :---------------- | @@ -67,45 +75,54 @@ Duo 家族开发板采用 CV18xx 系列芯片。芯片的工作模式总结如 | sdio | 支持 | | | eth | 支持 | | -# 编译 +# 4. 编译 -## Toolchain 下载 +## 4.1. Toolchain 下载 > 注:当前 bsp 只支持 Linux 编译,推荐 ubuntu 22.04 -1. RT-Thread 标准版工具链:`riscv64-unknown-elf-gcc` 下载地址 [https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1705395512373/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1-20240115.tar.gz](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1705395512373/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1-20240115.tar.gz) +1. 用于编译 RT-Thread 标准版的工具链是 `riscv64-unknown-elf-gcc` 下载地址 [https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1705395512373/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1-20240115.tar.gz](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1705395512373/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1-20240115.tar.gz) -2. RT-Smart 版工具链: `riscv64-unknown-linux-musl-gcc` 下载地址 [https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2](https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2) +2. 用于编译 RT-Thread Smart 版的工具链是 `riscv64-unknown-linux-musl-gcc` 下载地址 [https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2](https://github.com/RT-Thread/toolchains-ci/releases/download/v1.7/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2) -正确解压后,在`rtconfig.py`中将 `riscv64-unknown-elf-gcc` 或 `riscv64-unknown-linux-musl-gcc` 工具链的本地路径加入 `EXEC_PATH` 或通过 `RTT_EXEC_PATH` 环境变量指定路径。 +正确解压后,导出如下环境变量,建议将这些 export 命令写入 `~/.bashrc`。**并注意在使用不同工具链时确保导出正确的一组环境变量**。 + +构建 RT-Thread 标准版时按照以下配置: ```shell -# RT-Thread 标准版按照以下配置: -$ export RTT_CC_PREFIX=riscv64-unknown-elf- -$ export RTT_EXEC_PATH=/opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1/bin - -# RT-Samrt 版按照以下配置: -$ export RTT_CC_PREFIX=riscv64-unknown-linux-musl- -$ export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +export RTT_CC="gcc" +export RTT_CC_PREFIX=riscv64-unknown-elf- +export RTT_EXEC_PATH=/opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.8.1/bin ``` -## 依赖安装 +构建 RT-Thread Smart 版时按照以下配置: + +```shell +export RTT_CC="gcc" +export RTT_CC_PREFIX=riscv64-unknown-linux-musl- +export RTT_EXEC_PATH=/opt/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin +``` + +## 4.2. 依赖安装 ```shell $ sudo apt install -y scons libncurses5-dev device-tree-compiler ``` -## 构建 +## 4.3. 构建 异构芯片需单独编译每个核的 OS,在大/小核对应的目录下,依次执行: -1. 开发板选择 -Linux平台下,可以先执行: +### 4.3.1. 开发板选择 + + Linux平台下,可以先执行: + ```shell $ scons --menuconfig ``` -选择当前需要编译的目标开发板类型 +选择当前需要编译的目标开发板类型,默认是 "milkv-duo256m"。 + ```shell Board Type (milkv-duo) ---> ( ) milkv-duo @@ -115,39 +132,131 @@ Board Type (milkv-duo) ---> ( ) milkv-duos ``` -2. 可按照以下方式开启 RT-Smart +### 4.3.2. 开启 RT-Smart + +目前大核默认启用 RT-Smart,小核不支持 RT-Smart。 + +如果要对大核启用 RT-Smart,可以按如下方式设置。 ```shell RT-Thread Kernel ---> [*] Enable RT-Thread Smart (microkernel on kernel/userland) ``` -并配置内核虚拟起始地址 `0xFFFFFFC000200000` +**注意检查内核虚拟起始地址的配置,确保为 `0xFFFFFFC000200000`。** + ```shell RT-Thread Kernel ---> (0xFFFFFFC000200000) The virtural address of kernel start RT-Thread Components ---> ``` -3. 编译 +### 4.3.3. 编译 + ```shell $ scons ``` -编译成功后,会在 `bsp/cvitek/output` 对应开发板型号目录下自动生成 `fip.bin` 和 `boot.sd` 文件,其中大核运行文件在 `boot.sd` 中,小核的运行文件在 `fip.bin` 中。 +编译成功后,会在 `bsp/cvitek/output` 对应开发板型号目录下自动生成 `fip.bin` 和 `boot.sd` 文件。 -- fip.bin:fsbl、opensbi、uboot、小核运行文件打包后的 bin 文件 -- boot.sd:大核打包后的 bin 文件 +- `fip.bin`:这是一个打包后生成的 bin 文件,包含了 `fsbl`、`opensbi`、`uboot` 以及小核的内核镜像文件 `rtthread.bin`。 +- `boot.sd`:这也是一个打包后生成的 bin 文件,包含了大核的内核镜像文件 `rtthread.bin`。 -# 运行 +# 5. 运行 -1. 将 SD 卡分为 2 个分区,第 1 个分区用于存放 bin 文件,第 2 个分区用于作为数据存储分区,分区格式为 `FAT32`。 +1. 将 SD 卡分为 2 个分区,第 1 个分区的分区格式为 `FAT32`,用于存放 `fip.bin` 和 `boot.sd` 文件,第 2 个分区可选,如果有可用于作为数据存储分区或者存放文件系统。 -2. 将根目录下的 `fip.bin` 和 `boot.sd` 复制到 SD 卡第一个分区中。两个固件文件可以独立修改更新,譬如后续只需要更新大核,只需要重新编译 "cv18xx_risc-v" 并复制 `boot.sd` 文件即可。 +2. 将根目录下的 `fip.bin` 和 `boot.sd` 复制到 SD 卡第一个分区中。两个固件文件可以独立修改更新,譬如后续只需要更新大核,只需要重新编译 "cv18xx_risc-v" 并替换 SD 卡第一个分区中的 `boot.sd` 文件即可。 3. 更新完固件文件后, 重新上电可以看到串口的输出信息。 -# FAQ +# 6. 大核 RT-Smart 启动并自动挂载根文件系统 + +大核启用 RT-Smart 后可以在启动阶段挂载根文件系统。目前 Duo 支持 ext4,fat 文件格式,下面以 fat 格式为例,具体操作说明如下: + +## 6.1. 内核构建配置 + +首先确保开启 RT-Smart,参考 [4.3.2. 可按照以下方式开启 RT-Smart](#432-可按照以下方式开启-rt-smart)。 + +在开启 RT-Smart 基础上确保如下配置修改。 + +- 使能 `BSP_USING_SDH`: Enable Secure Digital Host Controller, 因为使用 sd-card 存放文件系统。 +- 使能 `BSP_USING_RTC`: Enable RTC, 避免挂载文件系统后执行命令报错:`[W/time] Cannot find a RTC device!` +- 使能 `BSP_ROOTFS_TYPE_DISKFS`: Disk FileSystems, e.g. ext4, fat ..., 该配置默认已打开。 + +保存后重新编译内核。 + +## 6.2. 构建文件系统 + +这里用 RT-Thread 官方的 userapps 工具制作文件系统。 + +userapps 仓库地址: 。具体操作参考 [《介绍与快速入门》](https://github.com/RT-Thread/userapps/blob/main/README.md)。 + +制作根文件系统步骤如下,供参考: + +```shell +cd $WS +git clone https://github.com/RT-Thread/userapps.git +cd $WS/userapps +source ./env.sh +cd apps +xmake f -a riscv64gc +xmake -j$(nproc) +xmake smart-rootfs +xmake smart-image -f fat +``` + +在 `$WS/userapps/apps/build` 路径下生成根文件系统镜像文件 `fat.img`。 + +## 6.3. 将文件系统写入 sd-card + +将 SD 卡分为 2 个分区,第 1 个分区用于存放 `fip.bin` 和 `boot.sd` 文件,第 2 个分区用于存放文件系统,分区格式为 `FAT32`。 + +将 SD 卡插入 PC 主机系统,假设为 Ubuntu,识别为 `/dev/sdb`,则第二个分区为 `/dev/sdb2`。将第二个分区挂载,假设挂载到 `~/ws/u-disk`。 + +将上一步生成的 `fat.img` 文件也挂载到一个临时目录,假设是 `/tmp`。 + +最后将 /tmp 下的文件全部拷贝到 `~/ws/u-disk` 中,即完成对 SD 卡中文件系统分区的烧写。 + +最后不要忘记卸载 SD 卡的分区。 + +简单步骤示例如下,供参考: + +```shell +sudo mount -o loop fat.img /tmp +sudo mount /dev/sdb2 ~/ws/u-disk +sudo cp -a /tmp/* ~/ws/u-disk +sudo umount ~/ws/u-disk +sudo umount /tmp +``` + +## 6.4. 上电启动 + +启动完成后, 会看到 `[I/app.filesystem] device 'sd1' is mounted to '/' as FAT` 的输出,说明文件系统挂载成功。此时 `msh` 被替换为 `/bin/ash`。 + +```shell + \ | / +- RT - Thread Smart Operating System + / | \ 5.2.0 build Nov 26 2024 09:55:38 + 2006 - 2024 Copyright by RT-Thread team +lwIP-2.1.2 initialized! +[I/sal.skt] Socket Abstraction Layer initialize success. +[I/drivers.serial] Using /dev/ttyS0 as default console +[I/SDIO] SD card capacity 30216192 KB. +[I/SDIO] sd: switch to High Speed / SDR25 mode + +found part[0], begin: 1048576, size: 128.0MB +found part[1], begin: 135266304, size: 28.707GB +[I/app.filesystem] device 'sd1' is mounted to '/' as FAT +Hello RT-Smart! +msh />[E/sal.skt] not find network interface device by protocol family(1). +[E/sal.skt] SAL socket protocol family input failed, return error -3. +/ # ls +bin etc mnt root sbin tc usr +dev lib proc run services tmp var +``` + +# 7. FAQ 1. 如遇到不能正常编译,请先使用 `scons --menuconfig` 重新生成配置。 @@ -162,7 +271,7 @@ $ sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb 3. 如发现切换开发板编译正常,但无法正常打包,请切换至自动下载的 `cvi_bootloader` 目录,并手工运行 `git pull` 更新,或删除该目录后重新自动下载。 -# 联系人信息 +# 8. 联系人信息 维护人:[flyingcys](https://github.com/flyingcys) diff --git a/bsp/cvitek/cv18xx_risc-v/.config b/bsp/cvitek/cv18xx_risc-v/.config index 290b22b466..5726c5a1aa 100644 --- a/bsp/cvitek/cv18xx_risc-v/.config +++ b/bsp/cvitek/cv18xx_risc-v/.config @@ -2,10 +2,114 @@ # # RT-Thread Kernel # + +# +# klibc options +# + +# +# ------------rt_memset options------------ +# +# CONFIG_RT_KLIBC_USING_USER_MEMSET is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMSET is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMSET is not set + +# +# ------------rt_memcpy options------------ +# +# CONFIG_RT_KLIBC_USING_USER_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCPY is not set +# CONFIG_RT_KLIBC_USING_TINY_MEMCPY is not set + +# +# ------------rt_memmove options------------ +# +# CONFIG_RT_KLIBC_USING_USER_MEMMOVE is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMMOVE is not set + +# +# ------------rt_memcmp options------------ +# +# CONFIG_RT_KLIBC_USING_USER_MEMCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_MEMCMP is not set + +# +# ------------rt_strstr options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRSTR is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRSTR is not set + +# +# ------------rt_strcasecmp options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRCASECMP is not set + +# +# ------------rt_strncpy options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRNCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCPY is not set + +# +# ------------rt_strcpy options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRCPY is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCPY is not set + +# +# ------------rt_strncmp options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRNCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRNCMP is not set + +# +# ------------rt_strcmp options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRCMP is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRCMP is not set + +# +# ------------rt_strlen options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRLEN is not set +# CONFIG_RT_KLIBC_USING_LIBC_STRLEN is not set + +# +# ------------rt_strlen options------------ +# + +# +# ------------rt_strnlen options------------ +# +# CONFIG_RT_KLIBC_USING_USER_STRNLEN is not set + +# +# ------------rt_vsscanf options------------ +# +# CONFIG_RT_KLIBC_USING_LIBC_VSSCANF is not set + +# +# ------------rt_vsnprintf options------------ +# +# CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set +CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y +CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y +CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y +CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y +CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y +CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y +# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set +CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32 +CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32 +CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6 +CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9 +CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4 +# end of klibc options + CONFIG_RT_NAME_MAX=8 # CONFIG_RT_USING_ARCH_DATA_TYPE is not set -CONFIG_RT_USING_SMART=y # CONFIG_RT_USING_NANO is not set +CONFIG_RT_USING_SMART=y # CONFIG_RT_USING_AMP is not set # CONFIG_RT_USING_SMP is not set CONFIG_RT_CPUS_NR=1 @@ -15,6 +119,7 @@ CONFIG_RT_THREAD_PRIORITY_32=y # CONFIG_RT_THREAD_PRIORITY_256 is not set CONFIG_RT_THREAD_PRIORITY_MAX=32 CONFIG_RT_TICK_PER_SECOND=1000 +CONFIG_RT_USING_OVERFLOW_CHECK=y CONFIG_RT_USING_HOOK=y CONFIG_RT_HOOK_USING_FUNC_PTR=y # CONFIG_RT_USING_HOOKLIST is not set @@ -28,18 +133,10 @@ CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384 CONFIG_RT_USING_CPU_USAGE_TRACER=y # -# kservice optimization +# kservice options # # CONFIG_RT_USING_TINY_FFS is not set -# end of kservice optimization - -# -# klibc optimization -# -# CONFIG_RT_KLIBC_USING_STDLIB is not set -# CONFIG_RT_KLIBC_USING_TINY_SIZE is not set -CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG=y -# end of klibc optimization +# end of kservice options CONFIG_RT_USING_DEBUG=y CONFIG_RT_DEBUGING_ASSERT=y @@ -47,7 +144,6 @@ CONFIG_RT_DEBUGING_COLOR=y CONFIG_RT_DEBUGING_CONTEXT=y # CONFIG_RT_DEBUGING_AUTO_INIT is not set # CONFIG_RT_DEBUGING_PAGE_LEAK is not set -CONFIG_RT_USING_OVERFLOW_CHECK=y # # Inter-Thread communication @@ -206,6 +302,7 @@ CONFIG_RT_USING_CPUTIME_RISCV=y CONFIG_CPUTIME_TIMER_FREQ=25000000 # CONFIG_RT_USING_I2C is not set # CONFIG_RT_USING_PHY is not set +# CONFIG_RT_USING_PHY_V2 is not set # CONFIG_RT_USING_ADC is not set # CONFIG_RT_USING_DAC is not set CONFIG_RT_USING_NULL=y @@ -235,6 +332,15 @@ CONFIG_RT_USING_WDT=y # CONFIG_RT_USING_LCD is not set # CONFIG_RT_USING_HWCRYPTO is not set # CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_BLK=y + +# +# Partition Types +# +CONFIG_RT_BLK_PARTITION_DFS=y +CONFIG_RT_BLK_PARTITION_EFI=y +# end of Partition Types + # CONFIG_RT_USING_VIRTIO is not set CONFIG_RT_USING_PIN=y CONFIG_RT_USING_KTIME=y @@ -601,7 +707,6 @@ CONFIG_LWP_PTY_MAX_PARIS_LIMIT=64 # CONFIG_PKG_USING_JSMN is not set # CONFIG_PKG_USING_AGILE_JSMN is not set # CONFIG_PKG_USING_PARSON is not set -# CONFIG_PKG_USING_RYAN_JSON is not set # end of JSON: JavaScript Object Notation, a lightweight data-interchange format # @@ -812,8 +917,6 @@ CONFIG_LWP_PTY_MAX_PARIS_LIMIT=64 # # STM32 HAL & SDK Drivers # -# CONFIG_PKG_USING_STM32F4_HAL_DRIVER is not set -# CONFIG_PKG_USING_STM32F4_CMSIS_DRIVER is not set # CONFIG_PKG_USING_STM32L4_HAL_DRIVER is not set # CONFIG_PKG_USING_STM32L4_CMSIS_DRIVER is not set # CONFIG_PKG_USING_STM32WB55_SDK is not set @@ -1008,7 +1111,6 @@ CONFIG_LWP_PTY_MAX_PARIS_LIMIT=64 # CONFIG_PKG_USING_SYSTEM_RUN_LED is not set # CONFIG_PKG_USING_BT_MX01 is not set # CONFIG_PKG_USING_RGPOWER is not set -# CONFIG_PKG_USING_BT_MX02 is not set # CONFIG_PKG_USING_SPI_TOOLS is not set # end of peripheral libraries and drivers @@ -1124,7 +1226,6 @@ CONFIG_PKG_ZLIB_VER="latest" # CONFIG_PKG_USING_ARDUINO_MSGQ_C_CPP_DEMO is not set # CONFIG_PKG_USING_ARDUINO_SKETCH_LOADER_DEMO is not set # CONFIG_PKG_USING_ARDUINO_ULTRASOUND_RADAR is not set -# CONFIG_PKG_USING_ARDUINO_RTDUINO_SENSORFUSION_SHIELD is not set # CONFIG_PKG_USING_ARDUINO_NINEINONE_SENSOR_SHIELD is not set # CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set # CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set @@ -1385,5 +1486,5 @@ CONFIG_SOC_TYPE_SG2002=y CONFIG_BOARD_TYPE_MILKV_DUO256M=y # CONFIG_BOARD_TYPE_MILKV_DUO256M_SPINOR is not set # CONFIG_BOARD_TYPE_MILKV_DUOS is not set -CONFIG_BSP_ROOTFS_TYPE_ROMFS=y +CONFIG_BSP_ROOTFS_TYPE_DISKFS=y # CONFIG_BSP_ROOTFS_TYPE_CROMFS is not set diff --git a/bsp/cvitek/cv18xx_risc-v/Kconfig b/bsp/cvitek/cv18xx_risc-v/Kconfig index ba6b0889d2..bb4a2c9b78 100755 --- a/bsp/cvitek/cv18xx_risc-v/Kconfig +++ b/bsp/cvitek/cv18xx_risc-v/Kconfig @@ -84,10 +84,10 @@ endchoice choice BSP_ROOTFS_TYPE prompt "rootfs type" - default BSP_ROOTFS_TYPE_ROMFS + default BSP_ROOTFS_TYPE_DISKFS - config BSP_ROOTFS_TYPE_ROMFS - bool "ROMFS" + config BSP_ROOTFS_TYPE_DISKFS + bool "Disk FileSystems, e.g. ext4, fat ..." select RT_USING_DFS_ROMFS config BSP_ROOTFS_TYPE_CROMFS diff --git a/bsp/cvitek/cv18xx_risc-v/rtconfig.h b/bsp/cvitek/cv18xx_risc-v/rtconfig.h index ef152eb30c..eb2571320c 100755 --- a/bsp/cvitek/cv18xx_risc-v/rtconfig.h +++ b/bsp/cvitek/cv18xx_risc-v/rtconfig.h @@ -3,6 +3,63 @@ /* RT-Thread Kernel */ +/* klibc options */ + +/* ------------rt_memset options------------ */ + + +/* ------------rt_memcpy options------------ */ + + +/* ------------rt_memmove options------------ */ + + +/* ------------rt_memcmp options------------ */ + + +/* ------------rt_strstr options------------ */ + + +/* ------------rt_strcasecmp options------------ */ + + +/* ------------rt_strncpy options------------ */ + + +/* ------------rt_strcpy options------------ */ + + +/* ------------rt_strncmp options------------ */ + + +/* ------------rt_strcmp options------------ */ + + +/* ------------rt_strlen options------------ */ + + +/* ------------rt_strlen options------------ */ + +/* ------------rt_strnlen options------------ */ + + +/* ------------rt_vsscanf options------------ */ + + +/* ------------rt_vsnprintf options------------ */ + +#define RT_KLIBC_USING_VSNPRINTF_LONGLONG +#define RT_KLIBC_USING_VSNPRINTF_STANDARD +#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS +#define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS +#define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER +#define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER +#define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32 +#define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32 +#define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6 +#define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 +#define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4 +/* end of klibc options */ #define RT_NAME_MAX 8 #define RT_USING_SMART #define RT_CPUS_NR 1 @@ -10,6 +67,7 @@ #define RT_THREAD_PRIORITY_32 #define RT_THREAD_PRIORITY_MAX 32 #define RT_TICK_PER_SECOND 1000 +#define RT_USING_OVERFLOW_CHECK #define RT_USING_HOOK #define RT_HOOK_USING_FUNC_PTR #define RT_USING_IDLE_HOOK @@ -20,19 +78,13 @@ #define RT_TIMER_THREAD_STACK_SIZE 16384 #define RT_USING_CPU_USAGE_TRACER -/* kservice optimization */ +/* kservice options */ -/* end of kservice optimization */ - -/* klibc optimization */ - -#define RT_KLIBC_USING_VSNPRINTF_LONGLONG -/* end of klibc optimization */ +/* end of kservice options */ #define RT_USING_DEBUG #define RT_DEBUGING_ASSERT #define RT_DEBUGING_COLOR #define RT_DEBUGING_CONTEXT -#define RT_USING_OVERFLOW_CHECK /* Inter-Thread communication */ @@ -157,6 +209,13 @@ #define RT_MMCSD_THREAD_PREORITY 22 #define RT_MMCSD_MAX_PARTITION 16 #define RT_USING_WDT +#define RT_USING_BLK + +/* Partition Types */ + +#define RT_BLK_PARTITION_DFS +#define RT_BLK_PARTITION_EFI +/* end of Partition Types */ #define RT_USING_PIN #define RT_USING_KTIME #define RT_USING_HWTIMER @@ -495,6 +554,6 @@ #define __STACKSIZE__ 8192 #define SOC_TYPE_SG2002 #define BOARD_TYPE_MILKV_DUO256M -#define BSP_ROOTFS_TYPE_ROMFS +#define BSP_ROOTFS_TYPE_DISKFS #endif diff --git a/bsp/cvitek/drivers/SConscript b/bsp/cvitek/drivers/SConscript index e6333eadde..27aa394920 100755 --- a/bsp/cvitek/drivers/SConscript +++ b/bsp/cvitek/drivers/SConscript @@ -40,8 +40,8 @@ if GetDepend('BSP_USING_PWM'): if GetDepend('BSP_ROOTFS_TYPE_CROMFS'): src += ['port/mnt_cromfs.c'] -elif GetDepend('BSP_ROOTFS_TYPE_ROMFS'): - src += ['port/mnt_romfs.c'] +elif GetDepend('BSP_ROOTFS_TYPE_DISKFS'): + src += ['port/mnt_diskfs.c'] if GetDepend('BSP_USING_SDH'): src += ['drv_sdhci.c'] diff --git a/bsp/cvitek/drivers/drv_rtc.c b/bsp/cvitek/drivers/drv_rtc.c index 93f2b07082..65927ab4bb 100644 --- a/bsp/cvitek/drivers/drv_rtc.c +++ b/bsp/cvitek/drivers/drv_rtc.c @@ -317,7 +317,6 @@ static void rt_hw_rtc_isr(int irqno, void *param) rt_interrupt_leave(); } -#endif static rt_err_t _rtc_get_alarm(struct rt_rtc_wkalarm *alarm) { @@ -367,6 +366,7 @@ static rt_err_t _rtc_set_alarm(struct rt_rtc_wkalarm *alarm) return RT_EOK; } +#endif static const struct rt_rtc_ops _rtc_ops = { diff --git a/bsp/cvitek/drivers/port/mnt_diskfs.c b/bsp/cvitek/drivers/port/mnt_diskfs.c new file mode 100644 index 0000000000..ca80816f5a --- /dev/null +++ b/bsp/cvitek/drivers/port/mnt_diskfs.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#ifdef RT_USING_DFS +#include + +#define DBG_TAG "app.filesystem" +#define DBG_LVL DBG_LOG +#include + +static int _wait_device_ready(const char* devname) +{ + int k; + + for(k = 0; k < 10; k++) + { + if (rt_device_find(devname) != RT_NULL) + { + return 1; + } + rt_thread_mdelay(50); + } + + return 0; +} + +static void sd_mount(const char *devname) +{ + if (!_wait_device_ready(devname)) { + LOG_W("Failed to find device: %s", devname); + return; + } + + if (dfs_mount(devname, "/", "ext", 0, 0) == RT_EOK) + { + LOG_I("device '%s' is mounted to '/' as EXT", devname); + } + else if (dfs_mount(devname, "/", "elm", 0, 0) == RT_EOK) + { + LOG_I("device '%s' is mounted to '/' as FAT", devname); + } + else + { + LOG_W("Failed to mount device '%s' to '/': %d\n", devname, rt_get_errno()); + } +} + +int mount_init(void) +{ +#ifdef BSP_USING_SDH + sd_mount("sd1"); +#endif + + return RT_EOK; +} +INIT_ENV_EXPORT(mount_init); + +#endif /* RT_USING_DFS */ diff --git a/bsp/cvitek/drivers/port/mnt_romfs.c b/bsp/cvitek/drivers/port/mnt_romfs.c deleted file mode 100644 index 799b7c5ccf..0000000000 --- a/bsp/cvitek/drivers/port/mnt_romfs.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022/12/25 flyingcys first version - */ -#include - -#ifdef RT_USING_DFS -#include -#include "dfs_romfs.h" - -#define DBG_TAG "app.filesystem" -#define DBG_LVL DBG_LOG -#include - -static const struct romfs_dirent _romfs_root[] = -{ -#ifdef BSP_USING_ON_CHIP_FLASH - {ROMFS_DIRENT_DIR, "flash", RT_NULL, 0}, -#endif - {ROMFS_DIRENT_DIR, "sdcard", RT_NULL, 0} -}; - -const struct romfs_dirent romfs_root = -{ - ROMFS_DIRENT_DIR, "/", (rt_uint8_t *)_romfs_root, sizeof(_romfs_root) / sizeof(_romfs_root[0]) -}; - -static void sd_mount(void *parameter) -{ - while (1) - { - rt_thread_mdelay(500); - - if (rt_device_find("sd0") != RT_NULL) - { - if (dfs_mount("sd0", "/sdcard", "elm", 0, 0) == RT_EOK) - { - LOG_I("sd card mount to '/sdcard'"); - break; - } - else - { - LOG_W("sd card mount to '/sdcard' failed! %d\n", rt_get_errno()); - } - } - } -} - -int mount_init(void) -{ - if(dfs_mount(RT_NULL, "/", "rom", 0, &romfs_root) != 0) - { - LOG_E("rom mount to '/' failed!"); - } - -#ifdef BSP_USING_ON_CHIP_FLASH_FS - struct rt_device *flash_dev = RT_NULL; - - /* 使用 filesystem 分区创建块设备,块设备名称为 filesystem */ - flash_dev = fal_blk_device_create("filesystem"); - if(flash_dev == RT_NULL) - { - LOG_E("Failed to create device.\n"); - return -RT_ERROR; - } - - if (dfs_mount("filesystem", "/flash", "lfs", 0, 0) != 0) - { - LOG_I("file system initialization failed!\n"); - if(dfs_mkfs("lfs", "filesystem") == 0) - { - if (dfs_mount("filesystem", "/flash", "lfs", 0, 0) == 0) - { - LOG_I("mount to '/flash' success!"); - } - } - } - else - { - LOG_I("mount to '/flash' success!"); - } -#endif - -#ifdef BSP_USING_SDH - rt_thread_t tid; - - tid = rt_thread_create("sd_mount", sd_mount, RT_NULL, - 4096, RT_THREAD_PRIORITY_MAX - 2, 20); - if (tid != RT_NULL) - { - rt_thread_startup(tid); - } - else - { - LOG_E("create sd_mount thread err!"); - } -#endif - - return RT_EOK; -} -INIT_APP_EXPORT(mount_init); - -#endif /* RT_USING_DFS */ diff --git a/bsp/nuvoton/libraries/m460/rtt_port/drv_common.c b/bsp/nuvoton/libraries/m460/rtt_port/drv_common.c index cb12e1fcb5..adbe38618e 100644 --- a/bsp/nuvoton/libraries/m460/rtt_port/drv_common.c +++ b/bsp/nuvoton/libraries/m460/rtt_port/drv_common.c @@ -167,12 +167,12 @@ void devmem(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "0x%x", &value) != 1) + if (rt_sscanf(argv[2], "0x%x", &value) != 1) goto exit_devmem; mode = 1; /*Write*/ } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (!u32Addr || u32Addr & (4 - 1)) goto exit_devmem; @@ -203,12 +203,12 @@ void devmem2(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "%u", &value) != 1) + if (rt_sscanf(argv[2], "%u", &value) != 1) goto exit_devmem; word_count = value; } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (!u32Addr || u32Addr & (4 - 1)) goto exit_devmem; diff --git a/bsp/nuvoton/libraries/ma35/rtt_port/drv_disp.c b/bsp/nuvoton/libraries/ma35/rtt_port/drv_disp.c index 842c567882..ddb3cb1d6d 100644 --- a/bsp/nuvoton/libraries/ma35/rtt_port/drv_disp.c +++ b/bsp/nuvoton/libraries/ma35/rtt_port/drv_disp.c @@ -399,7 +399,7 @@ static rt_err_t lcd_set_overlay_colkey(int argc, char **argv) for (index = 0; index < (len - 1); index ++) { - if (sscanf(argv[index + 1], "%x", &arg[index]) != 1) + if (rt_sscanf(argv[index + 1], "%x", &arg[index]) != 1) return -1; } rt_kprintf("colkeylow:0x%08x colkeyhigh:0x%08x\n", arg[0], arg[1]); @@ -459,7 +459,7 @@ static rt_err_t lcd_set_alphablend_opmode(int argc, char **argv) for (index = 0; index < (len - 1); index ++) { - if (sscanf(argv[index + 1], "%x", &arg[index]) != 1) + if (rt_sscanf(argv[index + 1], "%x", &arg[index]) != 1) return -1; } diff --git a/bsp/nuvoton/libraries/ma35/rtt_port/drv_sys.c b/bsp/nuvoton/libraries/ma35/rtt_port/drv_sys.c index d88df6677e..302730c81f 100644 --- a/bsp/nuvoton/libraries/ma35/rtt_port/drv_sys.c +++ b/bsp/nuvoton/libraries/ma35/rtt_port/drv_sys.c @@ -307,12 +307,12 @@ void devmem(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "0x%x", &value) != 1) + if (rt_sscanf(argv[2], "0x%x", &value) != 1) goto exit_devmem; mode = 1; //Write } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (u32Addr & (4 - 1)) goto exit_devmem; @@ -343,12 +343,12 @@ void devmem2(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "%d", &value) != 1) + if (rt_sscanf(argv[2], "%d", &value) != 1) goto exit_devmem; word_count = value; } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (u32Addr & (4 - 1)) goto exit_devmem; diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c index 620e439dda..402c05a5dd 100644 --- a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c @@ -90,12 +90,12 @@ void devmem(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "0x%x", &value) != 1) + if (rt_sscanf(argv[2], "0x%x", &value) != 1) goto exit_devmem; mode = 1; //Write } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (!u32Addr || u32Addr & (4 - 1)) goto exit_devmem; diff --git a/bsp/nuvoton/libraries/nu_packages/Demo/wormhole_demo.c b/bsp/nuvoton/libraries/nu_packages/Demo/wormhole_demo.c index bf2b8d7ad7..f079de13e4 100644 --- a/bsp/nuvoton/libraries/nu_packages/Demo/wormhole_demo.c +++ b/bsp/nuvoton/libraries/nu_packages/Demo/wormhole_demo.c @@ -298,12 +298,12 @@ void whc_devmem(int argc, char *argv[]) if (argc == 3) { - if (sscanf(argv[2], "0x%x", &value) != 1) + if (rt_sscanf(argv[2], "0x%x", &value) != 1) goto exit_devmem; mode = 1; //Write } - if (sscanf(argv[1], "0x%x", &u32Addr) != 1) + if (rt_sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (u32Addr & (4 - 1)) goto exit_devmem; diff --git a/bsp/nxp/mcx/mcxa/Libraries/drivers/drv_hwtimer.c b/bsp/nxp/mcx/mcxa/Libraries/drivers/drv_hwtimer.c new file mode 100644 index 0000000000..78b1e1e49a --- /dev/null +++ b/bsp/nxp/mcx/mcxa/Libraries/drivers/drv_hwtimer.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-26 hywing the first version. + * +*/ +#include + +#ifdef BSP_USING_HWTIMER + +#define LOG_TAG "drv.hwtimer" +#include +#include +#include "fsl_ctimer.h" + +enum +{ +#ifdef BSP_USING_CTIMER0 + TIM0_INDEX, +#endif +#ifdef BSP_USING_CTIMER1 + TIM1_INDEX, +#endif +#ifdef BSP_USING_CTIMER2 + TIM2_INDEX, +#endif +}; + +#ifdef BSP_USING_CTIMER0 +#define TIM0_CONFIG \ + { \ + .tim_handle = CTIMER0, \ + .tim_irqn = CTIMER0_IRQn, \ + .name = "timer0", \ + } +#endif /* TIM0_CONFIG */ + +#ifdef BSP_USING_CTIMER1 +#define TIM1_CONFIG \ + { \ + .tim_handle = CTIMER1, \ + .tim_irqn = CTIMER1_IRQn, \ + .name = "timer1", \ + } +#endif /* TIM1_CONFIG */ + +#ifdef BSP_USING_CTIMER2 +#define TIM2_CONFIG \ + { \ + .tim_handle = CTIMER2, \ + .tim_irqn = CTIMER2_IRQn, \ + .name = "timer2", \ + } +#endif /* TIM2_CONFIG */ + +struct mcxa_hwtimer +{ + rt_hwtimer_t time_device; + CTIMER_Type* tim_handle; + enum IRQn tim_irqn; + char* name; +}; + +static struct mcxa_hwtimer mcxa_hwtimer_obj[] = +{ +#ifdef BSP_USING_CTIMER0 + TIM0_CONFIG, +#endif + +#ifdef BSP_USING_CTIMER1 + TIM1_CONFIG, +#endif + +#ifdef BSP_USING_CTIMER2 + TIM2_CONFIG, +#endif +}; + +static void NVIC_Configuration(void) +{ +#ifdef BSP_USING_CTIMER0 + EnableIRQ(CTIMER0_IRQn); +#endif + +#ifdef BSP_USING_CTIMER1 + EnableIRQ(CTIMER1_IRQn); +#endif + +#ifdef BSP_USING_CTIMER2 + EnableIRQ(CTIMER2_IRQn); +#endif +} + +static rt_err_t mcxa_ctimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + CTIMER_Type *hwtimer_dev; + hwtimer_dev = (CTIMER_Type *)timer->parent.user_data; + + RT_ASSERT(timer != RT_NULL); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + { + uint32_t clk; + uint32_t pre; + if(hwtimer_dev == CTIMER0) clk = CLOCK_GetCTimerClkFreq(0U); + if(hwtimer_dev == CTIMER1) clk = CLOCK_GetCTimerClkFreq(1U); + if(hwtimer_dev == CTIMER2) clk = CLOCK_GetCTimerClkFreq(2U); + + pre = clk / *((uint32_t *)args) - 1; + + hwtimer_dev->PR = pre; + } + break; + default: + err = -RT_ENOSYS; + break; + } + return err; +} + +static rt_uint32_t mcxa_ctimer_count_get(rt_hwtimer_t *timer) +{ + rt_uint32_t CurrentTimer_Count; + CTIMER_Type *hwtimer_dev; + hwtimer_dev = (CTIMER_Type *)timer->parent.user_data; + + RT_ASSERT(timer != RT_NULL); + + CurrentTimer_Count = hwtimer_dev->TC; + + return CurrentTimer_Count; +} + +static void mcxa_ctimer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + CTIMER_Type *hwtimer_dev; + ctimer_config_t cfg; + hwtimer_dev = (CTIMER_Type *)timer->parent.user_data; + + RT_ASSERT(timer != RT_NULL); + + /* Use Main clock for some of the Ctimers */ + if(hwtimer_dev == CTIMER0) CLOCK_AttachClk(kFRO_HF_to_CTIMER0); + if(hwtimer_dev == CTIMER1) CLOCK_AttachClk(kFRO_HF_to_CTIMER1); + if(hwtimer_dev == CTIMER2) CLOCK_AttachClk(kFRO_HF_to_CTIMER2); + + CTIMER_Init(hwtimer_dev, &cfg); + + if (state == 1) + { + NVIC_Configuration(); + CTIMER_GetDefaultConfig(&cfg); + CTIMER_Init(hwtimer_dev, &cfg); + } +} + +static rt_err_t mcxa_ctimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + CTIMER_Type *hwtimer_dev; + hwtimer_dev = (CTIMER_Type *)timer->parent.user_data; + /* Match Configuration for Channel 0 */ + ctimer_match_config_t matchCfg; + + RT_ASSERT(timer != RT_NULL); + + /* Configuration*/ + matchCfg.enableCounterReset = true; + matchCfg.enableCounterStop = (mode == HWTIMER_MODE_ONESHOT) ? true : false;; + matchCfg.matchValue = cnt; + matchCfg.outControl = kCTIMER_Output_NoAction; + matchCfg.outPinInitState = false; + matchCfg.enableInterrupt = true; + + CTIMER_SetupMatch(hwtimer_dev, kCTIMER_Match_1, &matchCfg); + + NVIC_Configuration(); + + CTIMER_StartTimer(hwtimer_dev); + + return RT_EOK; +} + +static void mcxa_ctimer_stop(rt_hwtimer_t *timer) +{ + CTIMER_Type *hwtimer_dev; + hwtimer_dev = (CTIMER_Type *)timer->parent.user_data; + + RT_ASSERT(timer != RT_NULL); + + CTIMER_StopTimer(hwtimer_dev); +} + +static const struct rt_hwtimer_ops mcxa_hwtimer_ops = +{ + .init = mcxa_ctimer_init, + .start = mcxa_ctimer_start, + .stop = mcxa_ctimer_stop, + .count_get = mcxa_ctimer_count_get, + .control = mcxa_ctimer_control, +}; + +static const struct rt_hwtimer_info mcxa_hwtimer_info = +{ + 96000000, /* the maximum count frequency can be set */ + 6103, /* the minimum count frequency can be set */ + 0xFFFFFFFF, + HWTIMER_CNTMODE_UP, +}; + +int rt_hw_hwtimer_init(void) +{ + int i = 0; + int result = RT_EOK; + + for (i = 0; i < sizeof(mcxa_hwtimer_obj) / sizeof(mcxa_hwtimer_obj[0]); i++) + { + mcxa_hwtimer_obj[i].time_device.info = &mcxa_hwtimer_info; + mcxa_hwtimer_obj[i].time_device.ops = &mcxa_hwtimer_ops; + if (rt_device_hwtimer_register(&mcxa_hwtimer_obj[i].time_device, + mcxa_hwtimer_obj[i].name, mcxa_hwtimer_obj[i].tim_handle) == RT_EOK) + { + LOG_D("%s register success", mcxa_hwtimer_obj[i].name); + } + else + { + LOG_E("%s register failed", mcxa_hwtimer_obj[i].name); + result = -RT_ERROR; + } + } + + return result; +} + +INIT_DEVICE_EXPORT(rt_hw_hwtimer_init); + +#ifdef BSP_USING_CTIMER0 +void CTIMER0_IRQHandler(void) +{ + rt_interrupt_enter(); + uint32_t int_stat; + /* Get Interrupt status flags */ + int_stat = CTIMER_GetStatusFlags(CTIMER0); + /* Clear the status flags that were set */ + CTIMER_ClearStatusFlags(CTIMER0, int_stat); + rt_device_hwtimer_isr(&mcxa_hwtimer_obj[TIM0_INDEX].time_device); + rt_interrupt_leave(); +} +#endif /* BSP_USING_HWTIMER0 */ + +#ifdef BSP_USING_CTIMER1 +void CTIMER1_IRQHandler(void) +{ + rt_interrupt_enter(); + uint32_t int_stat; + /* Get Interrupt status flags */ + int_stat = CTIMER_GetStatusFlags(CTIMER1); + /* Clear the status flags that were set */ + CTIMER_ClearStatusFlags(CTIMER1, int_stat); + rt_device_hwtimer_isr(&mcxa_hwtimer_obj[TIM1_INDEX].time_device); + rt_interrupt_leave(); +} +#endif /* BSP_USING_HWTIMER1 */ + +#ifdef BSP_USING_CTIMER2 +void CTIMER2_IRQHandler(void) +{ + rt_interrupt_enter(); + uint32_t int_stat; + /* Get Interrupt status flags */ + int_stat = CTIMER_GetStatusFlags(CTIMER2); + /* Clear the status flags that were set */ + CTIMER_ClearStatusFlags(CTIMER2, int_stat); + rt_device_hwtimer_isr(&mcxa_hwtimer_obj[TIM2_INDEX].time_device); + rt_interrupt_leave(); +} +#endif /* BSP_USING_HWTIMER2 */ + + +#endif /* BSP_USING_HWTIMER */ diff --git a/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/Kconfig b/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/Kconfig index 3685b3fb87..28395131bd 100644 --- a/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/Kconfig +++ b/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/Kconfig @@ -103,7 +103,7 @@ menu "On-chip Peripheral Drivers" menuconfig BSP_USING_HWTIMER config BSP_USING_HWTIMER - bool "Enable Timer" + bool "Enable Hardware Timer" select RT_USING_HWTIMER default y @@ -116,12 +116,8 @@ menu "On-chip Peripheral Drivers" bool "Enable CIMER1" default n - config BSP_USING_CTIMER3 - bool "Enable CIMER3" - default n - - config BSP_USING_CTIMER4 - bool "Enable CIMER4" + config BSP_USING_CTIMER2 + bool "Enable CIMER2" default n endif diff --git a/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/MCUX_Config/board/pin_mux.c b/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/MCUX_Config/board/pin_mux.c index e0c56633e4..f157f43763 100644 --- a/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/MCUX_Config/board/pin_mux.c +++ b/bsp/nxp/mcx/mcxa/frdm-mcxa153/board/MCUX_Config/board/pin_mux.c @@ -44,8 +44,12 @@ void BOARD_InitPins(void) CLOCK_EnableClock(kCLOCK_GateGPIO2); CLOCK_EnableClock(kCLOCK_GateGPIO3); + CLOCK_SetClockDiv(kCLOCK_DivCTIMER0, 1u); + CLOCK_AttachClk(kFRO_HF_to_CTIMER0); CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, 1u); CLOCK_AttachClk(kFRO_HF_to_CTIMER1); + CLOCK_SetClockDiv(kCLOCK_DivCTIMER2, 1u); + CLOCK_AttachClk(kFRO_HF_to_CTIMER2); RESET_ReleasePeripheralReset(kLPUART0_RST_SHIFT_RSTn); RESET_ReleasePeripheralReset(kLPUART1_RST_SHIFT_RSTn); diff --git a/bsp/phytium/aarch64/.config b/bsp/phytium/aarch64/.config index 63ce1f2edc..8b9a1f9325 100644 --- a/bsp/phytium/aarch64/.config +++ b/bsp/phytium/aarch64/.config @@ -253,6 +253,15 @@ CONFIG_RT_USING_QSPI=y # CONFIG_RT_USING_LCD is not set # CONFIG_RT_USING_HWCRYPTO is not set # CONFIG_RT_USING_WIFI is not set +CONFIG_RT_USING_BLK=y + +# +# Partition Types +# +CONFIG_RT_BLK_PARTITION_DFS=y +CONFIG_RT_BLK_PARTITION_EFI=y +# end of Partition Types + # CONFIG_RT_USING_VIRTIO is not set CONFIG_RT_USING_PIN=y CONFIG_RT_USING_KTIME=y diff --git a/bsp/phytium/aarch64/Kconfig b/bsp/phytium/aarch64/Kconfig index a3b99c57f2..0bb44f3565 100644 --- a/bsp/phytium/aarch64/Kconfig +++ b/bsp/phytium/aarch64/Kconfig @@ -26,6 +26,7 @@ config PHYTIUM_ARCH_AARCH64 select RT_USING_CACHE select TARGET_ARMV8_AARCH64 select ARCH_ARM_BOOTWITH_FLUSH_CACHE + select ARCH_USING_IRQ_CTX_LIST select RT_USING_HW_ATOMIC default y diff --git a/bsp/phytium/aarch64/rtconfig.h b/bsp/phytium/aarch64/rtconfig.h index ffa79f701e..90679b4345 100644 --- a/bsp/phytium/aarch64/rtconfig.h +++ b/bsp/phytium/aarch64/rtconfig.h @@ -160,6 +160,13 @@ #define RT_MMCSD_MAX_PARTITION 16 #define RT_USING_SPI #define RT_USING_QSPI +#define RT_USING_BLK + +/* Partition Types */ + +#define RT_BLK_PARTITION_DFS +#define RT_BLK_PARTITION_EFI +/* end of Partition Types */ #define RT_USING_PIN #define RT_USING_KTIME #define RT_USING_CHERRYUSB diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 108811247f..9dcc8dd368 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -22,12 +22,14 @@ rsource "graphic/Kconfig" rsource "hwcrypto/Kconfig" rsource "wlan/Kconfig" rsource "input/Kconfig" +rsource "led/Kconfig" rsource "mailbox/Kconfig" rsource "phye/Kconfig" rsource "ata/Kconfig" rsource "block/Kconfig" rsource "nvme/Kconfig" rsource "scsi/Kconfig" +rsource "regulator/Kconfig" rsource "reset/Kconfig" rsource "virtio/Kconfig" rsource "dma/Kconfig" diff --git a/components/drivers/include/drivers/dev_spi.h b/components/drivers/include/drivers/dev_spi.h index 45e8e8544f..ad23453d5b 100644 --- a/components/drivers/include/drivers/dev_spi.h +++ b/components/drivers/include/drivers/dev_spi.h @@ -16,6 +16,8 @@ #include #include #include +#include + /** * @addtogroup Drivers RTTHREAD Driver * @defgroup SPI SPI @@ -151,7 +153,12 @@ struct rt_spi_configuration { rt_uint8_t mode; rt_uint8_t data_width; +#ifdef RT_USING_DM + rt_uint8_t data_width_tx; + rt_uint8_t data_width_rx; +#else rt_uint16_t reserved; +#endif rt_uint32_t max_hz; }; @@ -167,6 +174,12 @@ struct rt_spi_bus rt_uint8_t mode; const struct rt_spi_ops *ops; +#ifdef RT_USING_DM + rt_base_t *pins; + rt_bool_t slave; + int num_chipselect; +#endif /* RT_USING_DM */ + struct rt_mutex lock; struct rt_spi_device *owner; }; @@ -180,6 +193,20 @@ struct rt_spi_ops rt_ssize_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message); }; +#ifdef RT_USING_DM +/** + * @brief SPI delay info + */ +struct rt_spi_delay +{ +#define RT_SPI_DELAY_UNIT_USECS 0 +#define RT_SPI_DELAY_UNIT_NSECS 1 +#define RT_SPI_DELAY_UNIT_SCK 2 + rt_uint16_t value; + rt_uint8_t unit; +}; +#endif /* RT_USING_DM */ + /** * @brief SPI Virtual BUS, one device must connected to a virtual BUS */ @@ -188,6 +215,17 @@ struct rt_spi_device struct rt_device parent; struct rt_spi_bus *bus; +#ifdef RT_USING_DM + const char *name; + const struct rt_spi_device_id *id; + const struct rt_ofw_node_id *ofw_id; + + rt_uint8_t chip_select; + struct rt_spi_delay cs_setup; + struct rt_spi_delay cs_hold; + struct rt_spi_delay cs_inactive; +#endif + struct rt_spi_configuration config; rt_base_t cs_pin; void *user_data; @@ -252,6 +290,31 @@ struct rt_qspi_device #define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev)) +#ifdef RT_USING_DM +struct rt_spi_device_id +{ + char name[20]; + void *data; +}; + +struct rt_spi_driver +{ + struct rt_driver parent; + + const struct rt_spi_device_id *ids; + const struct rt_ofw_node_id *ofw_ids; + + rt_err_t (*probe)(struct rt_spi_device *device); + rt_err_t (*remove)(struct rt_spi_device *device); + rt_err_t (*shutdown)(struct rt_spi_device *device); +}; + +rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver); +rt_err_t rt_spi_device_register(struct rt_spi_device *device); + +#define RT_SPI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, spi, BUILIN) +#endif /* RT_USING_DM */ + /** * @brief register a SPI bus * diff --git a/components/drivers/include/drivers/led.h b/components/drivers/include/drivers/led.h new file mode 100644 index 0000000000..aeb80a6d64 --- /dev/null +++ b/components/drivers/include/drivers/led.h @@ -0,0 +1,57 @@ +/* + * 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 __LED_H__ +#define __LED_H__ + +#include +#include + +struct rt_led_ops; + +enum rt_led_state +{ + RT_LED_S_OFF, + RT_LED_S_ON, + RT_LED_S_TOGGLE, + RT_LED_S_BLINK, + + RT_LED_STATE_NR, +}; + +struct rt_led_device +{ + struct rt_device parent; + + const struct rt_led_ops *ops; + + struct rt_spinlock spinlock; + + void *sysdata; + void *priv; +}; + +struct rt_led_ops +{ + rt_err_t (*set_state)(struct rt_led_device *led, enum rt_led_state state); + rt_err_t (*get_state)(struct rt_led_device *led, enum rt_led_state *out_state); + rt_err_t (*set_period)(struct rt_led_device *led, rt_uint32_t period_ms); + rt_err_t (*set_brightness)(struct rt_led_device *led, rt_uint32_t brightness); +}; + +rt_err_t rt_hw_led_register(struct rt_led_device *led); +rt_err_t rt_hw_led_unregister(struct rt_led_device *led); + +rt_err_t rt_led_set_state(struct rt_led_device *led, enum rt_led_state state); +rt_err_t rt_led_get_state(struct rt_led_device *led, enum rt_led_state *out_state); +rt_err_t rt_led_set_period(struct rt_led_device *led, rt_uint32_t period_ms); +rt_err_t rt_led_set_brightness(struct rt_led_device *led, rt_uint32_t brightness); + +#endif /* __LED_H__ */ diff --git a/components/drivers/include/drivers/pci_endpoint.h b/components/drivers/include/drivers/pci_endpoint.h index 3e6fd7c918..c43c182d95 100644 --- a/components/drivers/include/drivers/pci_endpoint.h +++ b/components/drivers/include/drivers/pci_endpoint.h @@ -73,6 +73,7 @@ struct rt_pci_ep_msix_tbl }; struct rt_pci_ep_ops; +struct rt_pci_ep_mem; struct rt_pci_ep { @@ -84,6 +85,9 @@ struct rt_pci_ep const struct rt_device *rc_dev; const struct rt_pci_ep_ops *ops; + rt_size_t mems_nr; + struct rt_pci_ep_mem *mems; + rt_uint8_t max_functions; RT_BITMAP_DECLARE(functions_map, 8); rt_list_t epf_nodes; @@ -92,6 +96,16 @@ struct rt_pci_ep void *priv; }; +struct rt_pci_ep_mem +{ + rt_ubase_t cpu_addr; + rt_size_t size; + rt_size_t page_size; + + rt_bitmap_t *map; + rt_size_t bits; +}; + struct rt_pci_epf { rt_list_t list; @@ -170,6 +184,16 @@ rt_err_t rt_pci_ep_stop(struct rt_pci_ep *ep); rt_err_t rt_pci_ep_register(struct rt_pci_ep *ep); rt_err_t rt_pci_ep_unregister(struct rt_pci_ep *ep); +rt_err_t rt_pci_ep_mem_array_init(struct rt_pci_ep *ep, + struct rt_pci_ep_mem *mems, rt_size_t mems_nr); +rt_err_t rt_pci_ep_mem_init(struct rt_pci_ep *ep, + rt_ubase_t cpu_addr, rt_size_t size, rt_size_t page_size); + +void *rt_pci_ep_mem_alloc(struct rt_pci_ep *ep, + rt_ubase_t *out_cpu_addr, rt_size_t size); +void rt_pci_ep_mem_free(struct rt_pci_ep *ep, + void *vaddr, rt_ubase_t cpu_addr, rt_size_t size); + rt_err_t rt_pci_ep_add_epf(struct rt_pci_ep *ep, struct rt_pci_epf *epf); rt_err_t rt_pci_ep_remove_epf(struct rt_pci_ep *ep, struct rt_pci_epf *epf); diff --git a/components/drivers/include/drivers/regulator.h b/components/drivers/include/drivers/regulator.h new file mode 100644 index 0000000000..d74fc64277 --- /dev/null +++ b/components/drivers/include/drivers/regulator.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __REGULATOR_H__ +#define __REGULATOR_H__ + +#include +#include +#include + +#include + +#define RT_REGULATOR_UVOLT_INVALID (((int)(RT_UINT32_MAX >> 1))) + +struct rt_regulator_param +{ + const char *name; + + int min_uvolt; /* In uV */ + int max_uvolt; /* In uV */ + int min_uamp; /* In uA */ + int max_uamp; /* In uA */ + int ramp_delay; /* In uV/usec */ + int enable_delay; /* In usec */ + int off_on_delay; /* In usec */ + + rt_uint32_t enable_active_high:1; + rt_uint32_t boot_on:1; /* Is enabled on boot */ + rt_uint32_t always_on:1; /* Must be enabled */ + rt_uint32_t soft_start:1; /* Ramp voltage slowly */ + rt_uint32_t pull_down:1; /* Pull down resistor when regulator off */ + rt_uint32_t over_current_protection:1; /* Auto disable on over current */ +}; + +struct rt_regulator_ops; + +struct rt_regulator_node +{ + rt_list_t list; + rt_list_t children_nodes; + + struct rt_device *dev; + struct rt_regulator_node *parent; + + const char *supply_name; + const struct rt_regulator_ops *ops; + + struct rt_ref ref; + rt_atomic_t enabled_count; + + const struct rt_regulator_param *param; + + rt_list_t notifier_nodes; + + void *priv; +}; + +/* + * NOTE: Power regulator control is dangerous work. We don't want non-internal + * consumer could access the power regulator tree without regulator's API. So + * we defined the `rt_regulator` member in core instead of here. + */ +struct rt_regulator; + +#define RT_REGULATOR_MODE_INVALID 0 +#define RT_REGULATOR_MODE_FAST RT_BIT(0) +#define RT_REGULATOR_MODE_NORMAL RT_BIT(1) +#define RT_REGULATOR_MODE_IDLE RT_BIT(2) +#define RT_REGULATOR_MODE_STANDBY RT_BIT(3) + +struct rt_regulator_ops +{ + rt_err_t (*enable)(struct rt_regulator_node *reg); + rt_err_t (*disable)(struct rt_regulator_node *reg); + rt_bool_t (*is_enabled)(struct rt_regulator_node *reg); + rt_err_t (*set_voltage)(struct rt_regulator_node *reg, int min_uvolt, int max_uvolt); + int (*get_voltage)(struct rt_regulator_node *reg); + rt_err_t (*set_mode)(struct rt_regulator_node *reg, rt_uint32_t mode); + rt_int32_t (*get_mode)(struct rt_regulator_node *reg); + rt_err_t (*set_ramp_delay)(struct rt_regulator_node *reg, int ramp); + rt_uint32_t (*enable_time)(struct rt_regulator_node *reg); +}; + +struct rt_regulator_notifier; + +#define RT_REGULATOR_MSG_ENABLE RT_BIT(0) +#define RT_REGULATOR_MSG_DISABLE RT_BIT(1) +#define RT_REGULATOR_MSG_VOLTAGE_CHANGE RT_BIT(2) +#define RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR RT_BIT(3) + +union rt_regulator_notifier_args +{ + struct + { + int old_uvolt; + int min_uvolt; + int max_uvolt; + }; +}; + +typedef rt_err_t (*rt_regulator_notifier_callback)(struct rt_regulator_notifier *notifier, + rt_ubase_t msg, void *data); + +struct rt_regulator_notifier +{ + rt_list_t list; + + struct rt_regulator *regulator; + rt_regulator_notifier_callback callback; + void *priv; +}; + +rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np); +rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np); + +rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier); +rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier); + +struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id); +void rt_regulator_put(struct rt_regulator *reg); + +rt_err_t rt_regulator_enable(struct rt_regulator *reg); +rt_err_t rt_regulator_disable(struct rt_regulator *reg); +rt_bool_t rt_regulator_is_enabled(struct rt_regulator *reg); + +rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt); +rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt); +int rt_regulator_get_voltage(struct rt_regulator *reg); + +rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode); +rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg); + +rt_inline rt_err_t rt_regulator_set_voltage_triplet(struct rt_regulator *reg, + int min_uvolt, int target_uvolt, int max_uvolt) +{ + if (!rt_regulator_set_voltage(reg, target_uvolt, max_uvolt)) + { + return RT_EOK; + } + + return rt_regulator_set_voltage(reg, min_uvolt, max_uvolt); +} + +#endif /* __REGULATOR_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 4f3ab8f83f..dc84f28b12 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -51,6 +51,10 @@ extern "C" { #endif /* RT_ATA_AHCI */ #endif /* RT_USING_ATA */ +#ifdef RT_USING_LED +#include "drivers/led.h" +#endif + #ifdef RT_USING_MBOX #include "drivers/mailbox.h" #endif /* RT_USING_MBOX */ @@ -89,6 +93,10 @@ extern "C" { #include "drivers/pic.h" #endif /* RT_USING_PIC */ +#ifdef RT_USING_REGULATOR +#include "drivers/regulator.h" +#endif /* RT_USING_REGULATOR */ + #ifdef RT_USING_RESET #include "drivers/reset.h" #endif /* RT_USING_RESET */ diff --git a/components/drivers/led/Kconfig b/components/drivers/led/Kconfig new file mode 100644 index 0000000000..462aa0bac0 --- /dev/null +++ b/components/drivers/led/Kconfig @@ -0,0 +1,15 @@ +menuconfig RT_USING_LED + bool "Using Light Emitting Diode (LED) device drivers" + depends on RT_USING_DM + default n + +config RT_LED_GPIO + bool "GPIO connected LEDs Support" + depends on RT_USING_LED + depends on RT_USING_PINCTRL + depends on RT_USING_OFW + default n + +if RT_USING_LED + osource "$(SOC_DM_LED_DIR)/Kconfig" +endif diff --git a/components/drivers/led/SConscript b/components/drivers/led/SConscript new file mode 100644 index 0000000000..276ca0bd8b --- /dev/null +++ b/components/drivers/led/SConscript @@ -0,0 +1,18 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_DM', 'RT_USING_LED']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['led.c'] + +if GetDepend(['RT_LED_GPIO']): + src += ['led-gpio.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/led/led-gpio.c b/components/drivers/led/led-gpio.c new file mode 100644 index 0000000000..0b6bd6875e --- /dev/null +++ b/components/drivers/led/led-gpio.c @@ -0,0 +1,228 @@ +/* + * 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 +#include + +#define DBG_TAG "led.gpio" +#define DBG_LVL DBG_INFO +#include + +struct gpio_led +{ + struct rt_led_device parent; + + rt_base_t pin; + rt_uint8_t active_val; +}; + +#define raw_to_gpio_led(raw) rt_container_of(raw, struct gpio_led, parent); + +static rt_err_t gpio_led_set_state(struct rt_led_device *led, enum rt_led_state state) +{ + rt_err_t err = RT_EOK; + struct gpio_led *gled = raw_to_gpio_led(led); + + rt_pin_mode(gled->pin, PIN_MODE_OUTPUT); + + switch (state) + { + case RT_LED_S_OFF: + rt_pin_write(gled->pin, !gled->active_val); + break; + + case RT_LED_S_ON: + rt_pin_write(gled->pin, gled->active_val); + break; + + case RT_LED_S_TOGGLE: + err = led->ops->get_state(led, &state); + + if (!err) + { + err = led->ops->set_state(led, state == RT_LED_S_OFF ? RT_LED_S_ON : RT_LED_S_OFF); + } + break; + + default: + return -RT_ENOSYS; + } + + return err; +} + +static rt_err_t gpio_led_get_state(struct rt_led_device *led, enum rt_led_state *out_state) +{ + struct gpio_led *gled = raw_to_gpio_led(led); + + switch (rt_pin_read(gled->pin)) + { + case PIN_LOW: + *out_state = RT_LED_S_OFF; + break; + + case PIN_HIGH: + *out_state = RT_LED_S_ON; + break; + + default: + return -RT_ERROR; + } + + return RT_EOK; +} + +const static struct rt_led_ops gpio_led_ops = +{ + .set_state = gpio_led_set_state, + .get_state = gpio_led_get_state, +}; + +static rt_err_t ofw_append_gpio_led(struct rt_ofw_node *np) +{ + rt_err_t err; + enum rt_led_state led_state = RT_LED_S_OFF; + const char *propname, *state, *trigger; + struct gpio_led *gled = rt_malloc(sizeof(*gled)); + + if (!gled) + { + return -RT_ENOMEM; + } + + gled->pin = rt_ofw_get_named_pin(np, RT_NULL, 0, RT_NULL, &gled->active_val); + + if (gled->pin < 0) + { + err = gled->pin; + + goto _fail; + } + + gled->parent.ops = &gpio_led_ops; + + if ((err = rt_hw_led_register(&gled->parent))) + { + goto _fail; + } + + if (!rt_ofw_prop_read_string(np, "default-state", &state)) + { + if (!rt_strcmp(state, "on")) + { + led_state = RT_LED_S_ON; + } + } + + if ((propname = rt_ofw_get_prop_fuzzy_name(np, "default-trigger$"))) + { + if (!rt_ofw_prop_read_string(np, propname, &trigger)) + { + if (!rt_strcmp(trigger, "heartbeat") || + !rt_strcmp(trigger, "timer")) + { + led_state = RT_LED_S_BLINK; + } + } + } + + rt_led_set_state(&gled->parent, led_state); + + rt_ofw_data(np) = &gled->parent; + + return RT_EOK; + +_fail: + rt_free(gled); + + return err; +} + +static rt_err_t gpio_led_probe(struct rt_platform_device *pdev) +{ + rt_bool_t pinctrl_apply = RT_FALSE; + struct rt_ofw_node *led_np, *np = pdev->parent.ofw_node; + + if (rt_ofw_prop_read_bool(np, "pinctrl-0")) + { + pinctrl_apply = RT_TRUE; + rt_pin_ctrl_confs_apply_by_name(&pdev->parent, RT_NULL); + } + + rt_ofw_foreach_available_child_node(np, led_np) + { + rt_err_t err = ofw_append_gpio_led(led_np); + + if (err == -RT_ENOMEM) + { + rt_ofw_node_put(led_np); + + return err; + } + else if (err) + { + LOG_E("%s: create LED fail", rt_ofw_node_full_name(led_np)); + continue; + } + + if (!pinctrl_apply) + { + struct rt_device dev_tmp; + + dev_tmp.ofw_node = led_np; + rt_pin_ctrl_confs_apply_by_name(&dev_tmp, RT_NULL); + } + } + + return RT_EOK; +} + +static rt_err_t gpio_led_remove(struct rt_platform_device *pdev) +{ + struct gpio_led *gled; + struct rt_led_device *led_dev; + struct rt_ofw_node *led_np, *np = pdev->parent.ofw_node; + + rt_ofw_foreach_available_child_node(np, led_np) + { + led_dev = rt_ofw_data(led_np); + + if (!led_dev) + { + continue; + } + + gled = rt_container_of(led_dev, struct gpio_led, parent); + + rt_ofw_data(led_np) = RT_NULL; + + rt_hw_led_unregister(&gled->parent); + + rt_free(gled); + } + + return RT_EOK; +} + +static const struct rt_ofw_node_id gpio_led_ofw_ids[] = +{ + { .compatible = "gpio-leds" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver gpio_led_driver = +{ + .name = "led-gpio", + .ids = gpio_led_ofw_ids, + + .probe = gpio_led_probe, + .remove = gpio_led_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(gpio_led_driver); diff --git a/components/drivers/led/led.c b/components/drivers/led/led.c new file mode 100644 index 0000000000..8bfd44bfe2 --- /dev/null +++ b/components/drivers/led/led.c @@ -0,0 +1,349 @@ +/* + * 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 + +#define DBG_TAG "rtdm.led" +#define DBG_LVL DBG_INFO +#include + +#include +#include + +struct blink_timer +{ + rt_bool_t toggle; + rt_bool_t enabled; + struct rt_timer timer; +}; + +static struct rt_dm_ida led_ida = RT_DM_IDA_INIT(LED); + +static const char * const _led_states[] = +{ + [RT_LED_S_OFF] = "off", + [RT_LED_S_ON] = "on", + [RT_LED_S_TOGGLE] = "toggle", + [RT_LED_S_BLINK] = "blink", +}; + +static rt_ssize_t _led_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_ssize_t res; + rt_size_t state_len; + enum rt_led_state state; + struct rt_led_device *led = rt_container_of(dev, struct rt_led_device, parent); + + if ((res = rt_led_get_state(led, &state))) + { + return res; + } + + state_len = rt_strlen(_led_states[state]); + + if (pos < state_len) + { + size = rt_min_t(rt_size_t, size, size - pos); + ((char *)buffer)[size - 1] = '\0'; + rt_strncpy(buffer, &_led_states[state][pos], size); + + return size; + } + else + { + return 0; + } +} + +static rt_ssize_t _led_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_uint32_t brightness = 0; + const char *value = buffer; + struct rt_led_device *led = rt_container_of(dev, struct rt_led_device, parent); + + for (int i = 0; i < RT_ARRAY_SIZE(_led_states); ++i) + { + if (!rt_strncpy((char *)_led_states[i], buffer, size)) + { + return rt_led_set_state(led, i) ? : size; + } + } + + while (*value) + { + if (*value < '0' || *value > '9') + { + return -RT_EINVAL; + } + + brightness *= 10; + brightness += *value - '0'; + + ++value; + } + + rt_led_set_brightness(led, brightness); + + return size; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops _led_ops = +{ + .read = _led_read, + .write = _led_write, +}; +#endif + +static void _led_blink_timerout(void *param) +{ + struct rt_led_device *led = param; + struct blink_timer *btimer = led->sysdata; + + if (btimer->toggle) + { + led->ops->set_state(led, RT_LED_S_OFF); + } + else + { + led->ops->set_state(led, RT_LED_S_ON); + } + + btimer->toggle = !btimer->toggle; +} + +rt_err_t rt_hw_led_register(struct rt_led_device *led) +{ + rt_err_t err; + int device_id; + const char *dev_name; + struct blink_timer *btimer = RT_NULL; + + if (!led || !led->ops) + { + return -RT_EINVAL; + } + + if ((device_id = rt_dm_ida_alloc(&led_ida)) < 0) + { + return -RT_EFULL; + } + + rt_dm_dev_set_name(&led->parent, "led%u", device_id); + dev_name = rt_dm_dev_get_name(&led->parent); + + led->sysdata = RT_NULL; + rt_spin_lock_init(&led->spinlock); + + if (!led->ops->set_period && led->ops->set_state) + { + btimer = rt_malloc(sizeof(*btimer)); + + if (!btimer) + { + LOG_E("%s create blink timer failed", dev_name); + + err = -RT_ENOMEM; + goto _fail; + } + + led->sysdata = btimer; + + btimer->toggle = RT_FALSE; + btimer->enabled = RT_FALSE; + rt_timer_init(&btimer->timer, dev_name, _led_blink_timerout, led, + rt_tick_from_millisecond(500), RT_TIMER_FLAG_PERIODIC); + } + + led->parent.type = RT_Device_Class_Char; +#ifdef RT_USING_DEVICE_OPS + led->parent.ops = &_led_ops; +#else + led->parent.read = _led_read; + led->parent.write = _led_write; +#endif + led->parent.master_id = led_ida.master_id; + led->parent.device_id = device_id; + + if ((err = rt_device_register(&led->parent, dev_name, RT_DEVICE_FLAG_RDWR))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_dm_ida_free(&led_ida, device_id); + + if (btimer) + { + rt_timer_detach(&btimer->timer); + rt_free(btimer); + + led->sysdata = RT_NULL; + } + + return err; +} + +rt_err_t rt_hw_led_unregister(struct rt_led_device *led) +{ + if (!led) + { + return -RT_EINVAL; + } + + rt_led_set_state(led, RT_LED_S_OFF); + + if (led->sysdata) + { + struct blink_timer *btimer = led->sysdata; + + rt_timer_detach(&btimer->timer); + + rt_free(btimer); + } + + rt_dm_ida_free(&led_ida, led->parent.device_id); + + rt_device_unregister(&led->parent); + + return RT_EOK; +} + +rt_err_t rt_led_set_state(struct rt_led_device *led, enum rt_led_state state) +{ + rt_err_t err; + struct blink_timer *btimer; + + if (!led) + { + return -RT_EINVAL; + } + + if (!led->ops->set_state) + { + return -RT_ENOSYS; + } + + rt_spin_lock(&led->spinlock); + + btimer = led->sysdata; + + if (btimer && btimer->enabled) + { + rt_timer_stop(&btimer->timer); + } + + err = led->ops->set_state(led, state); + + if (state == RT_LED_S_BLINK) + { + if (err == -RT_ENOSYS && btimer && !btimer->enabled) + { + btimer->enabled = RT_TRUE; + rt_timer_start(&btimer->timer); + } + } + else if (btimer && btimer->enabled) + { + if (err) + { + rt_timer_start(&btimer->timer); + } + else + { + btimer->enabled = RT_FALSE; + } + } + + rt_spin_unlock(&led->spinlock); + + return err; +} + +rt_err_t rt_led_get_state(struct rt_led_device *led, enum rt_led_state *out_state) +{ + rt_err_t err; + + if (!led || !out_state) + { + return -RT_EINVAL; + } + + if (!led->ops->get_state) + { + return -RT_ENOSYS; + } + + rt_spin_lock(&led->spinlock); + + err = led->ops->get_state(led, out_state); + + rt_spin_unlock(&led->spinlock); + + return err; +} + +rt_err_t rt_led_set_period(struct rt_led_device *led, rt_uint32_t period_ms) +{ + rt_err_t err; + + if (!led) + { + return -RT_EINVAL; + } + + if (!led->ops->set_period && !led->sysdata) + { + return -RT_ENOSYS; + } + + rt_spin_lock(&led->spinlock); + + if (led->ops->set_period) + { + err = led->ops->set_period(led, period_ms); + } + else + { + struct blink_timer *btimer = led->sysdata; + rt_tick_t tick = rt_tick_from_millisecond(period_ms); + + err = rt_timer_control(&btimer->timer, RT_TIMER_CTRL_SET_TIME, &tick); + } + + rt_spin_unlock(&led->spinlock); + + return err; +} + +rt_err_t rt_led_set_brightness(struct rt_led_device *led, rt_uint32_t brightness) +{ + rt_err_t err; + + if (!led) + { + return -RT_EINVAL; + } + + if (!led->ops->set_brightness) + { + return -RT_ENOSYS; + } + + rt_spin_lock(&led->spinlock); + + err = led->ops->set_brightness(led, brightness); + + rt_spin_unlock(&led->spinlock); + + return err; +} diff --git a/components/drivers/pci/endpoint/SConscript b/components/drivers/pci/endpoint/SConscript index ca3121619b..9b76a96123 100644 --- a/components/drivers/pci/endpoint/SConscript +++ b/components/drivers/pci/endpoint/SConscript @@ -8,7 +8,7 @@ if not GetDepend(['RT_PCI_ENDPOINT']): cwd = GetCurrentDir() CPPPATH = [cwd + '/../../include'] -src = ['endpoint.c'] +src = ['endpoint.c', 'mem.c'] group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) diff --git a/components/drivers/pci/endpoint/mem.c b/components/drivers/pci/endpoint/mem.c new file mode 100644 index 0000000000..297db161c7 --- /dev/null +++ b/components/drivers/pci/endpoint/mem.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-08-25 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "pci.ep.mem" +#define DBG_LVL DBG_INFO +#include + +rt_err_t rt_pci_ep_mem_array_init(struct rt_pci_ep *ep, + struct rt_pci_ep_mem *mems, rt_size_t mems_nr) +{ + rt_size_t idx; + rt_err_t err = RT_EOK; + + if (!ep || !mems) + { + return -RT_EINVAL; + } + + rt_mutex_take(&ep->lock, RT_WAITING_FOREVER); + + ep->mems_nr = mems_nr; + ep->mems = rt_calloc(mems_nr, sizeof(*ep->mems)); + + if (!ep->mems) + { + return -RT_ENOMEM; + } + + for (idx = 0; idx < mems_nr; ++idx) + { + struct rt_pci_ep_mem *mem = &ep->mems[idx]; + + mem->cpu_addr = mems->cpu_addr; + mem->size = mems->size; + mem->page_size = mems->page_size; + mem->bits = mems->size / mems->page_size; + mem->map = rt_calloc(RT_BITMAP_LEN(mem->bits), sizeof(*mem->map)); + + if (!mem->map) + { + err = -RT_ENOMEM; + goto _out_lock; + } + } + +_out_lock: + if (err) + { + while (idx --> 0) + { + rt_free(ep->mems[idx].map); + } + rt_free(ep->mems); + + ep->mems_nr = 0; + ep->mems = RT_NULL; + } + + rt_mutex_release(&ep->lock); + + return err; +} + +rt_err_t rt_pci_ep_mem_init(struct rt_pci_ep *ep, + rt_ubase_t cpu_addr, rt_size_t size, rt_size_t page_size) +{ + struct rt_pci_ep_mem mem; + + if (!ep) + { + return -RT_EINVAL; + } + + mem.cpu_addr = cpu_addr; + mem.size = size; + mem.page_size = page_size; + + return rt_pci_ep_mem_array_init(ep, &mem, 1); +} + +static rt_ubase_t bitmap_region_alloc(struct rt_pci_ep_mem *mem, rt_size_t size) +{ + rt_size_t bit, next_bit, end_bit, max_bits; + + size /= mem->page_size; + max_bits = mem->bits - size; + + rt_bitmap_for_each_clear_bit(mem->map, bit, max_bits) + { + end_bit = bit + size; + + for (next_bit = bit + 1; next_bit < end_bit; ++next_bit) + { + if (rt_bitmap_test_bit(mem->map, next_bit)) + { + bit = next_bit; + goto _next; + } + } + + if (next_bit == end_bit) + { + while (next_bit --> bit) + { + rt_bitmap_set_bit(mem->map, next_bit); + } + + return mem->cpu_addr + bit * mem->page_size; + } + _next: + } + + return ~0ULL; +} + +static void bitmap_region_free(struct rt_pci_ep_mem *mem, + rt_ubase_t cpu_addr, rt_size_t size) +{ + rt_size_t bit = (cpu_addr - mem->cpu_addr) / mem->page_size, end_bit; + + size /= mem->page_size; + end_bit = bit + size; + + for (; bit < end_bit; ++bit) + { + rt_bitmap_clear_bit(mem->map, bit); + } +} + +void *rt_pci_ep_mem_alloc(struct rt_pci_ep *ep, + rt_ubase_t *out_cpu_addr, rt_size_t size) +{ + void *vaddr = RT_NULL; + + if (!ep || !out_cpu_addr) + { + return vaddr; + } + + rt_mutex_take(&ep->lock, RT_WAITING_FOREVER); + + for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx) + { + rt_ubase_t cpu_addr; + struct rt_pci_ep_mem *mem = &ep->mems[idx]; + + cpu_addr = bitmap_region_alloc(mem, size); + + if (cpu_addr != ~0ULL) + { + vaddr = rt_ioremap((void *)cpu_addr, size); + + if (!vaddr) + { + bitmap_region_free(mem, cpu_addr, size); + + /* Try next memory */ + continue; + } + + *out_cpu_addr = cpu_addr; + break; + } + } + + rt_mutex_release(&ep->lock); + + return vaddr; +} + +void rt_pci_ep_mem_free(struct rt_pci_ep *ep, + void *vaddr, rt_ubase_t cpu_addr, rt_size_t size) +{ + if (!ep || !vaddr || !size) + { + return; + } + + rt_mutex_take(&ep->lock, RT_WAITING_FOREVER); + + for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx) + { + struct rt_pci_ep_mem *mem = &ep->mems[idx]; + + if (mem->cpu_addr > cpu_addr && + mem->cpu_addr + mem->size >= cpu_addr + size) + { + rt_iounmap(mem); + bitmap_region_free(mem, cpu_addr, size); + + break; + } + } + + rt_mutex_release(&ep->lock); +} diff --git a/components/drivers/pci/host/Kconfig b/components/drivers/pci/host/Kconfig index 73b45782e7..221c997ebc 100644 --- a/components/drivers/pci/host/Kconfig +++ b/components/drivers/pci/host/Kconfig @@ -8,3 +8,5 @@ config RT_PCI_HOST_GENERIC depends on RT_PCI_ECAM select RT_PCI_HOST_COMMON default y + +rsource "dw/Kconfig" diff --git a/components/drivers/pci/host/dw/Kconfig b/components/drivers/pci/host/dw/Kconfig new file mode 100644 index 0000000000..e76011b387 --- /dev/null +++ b/components/drivers/pci/host/dw/Kconfig @@ -0,0 +1,13 @@ +config RT_PCI_DW + bool "DesignWare-based PCIe" + depends on RT_MFD_SYSCON + depends on RT_USING_DMA + default n + +config RT_PCI_DW_HOST + bool + depends on RT_PCI_DW + +config RT_PCI_DW_EP + bool + depends on RT_PCI_DW diff --git a/components/drivers/pci/host/dw/SConscript b/components/drivers/pci/host/dw/SConscript new file mode 100644 index 0000000000..ca6c031e00 --- /dev/null +++ b/components/drivers/pci/host/dw/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_PCI_DW']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../../../include'] + +src = ['pcie-dw.c', 'pcie-dw_platfrom.c'] + +if GetDepend(['RT_PCI_DW_HOST']): + src += ['pcie-dw_host.c'] + +if GetDepend(['RT_PCI_DW_EP']): + src += ['pcie-dw_ep.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/pci/host/dw/pcie-dw.c b/components/drivers/pci/host/dw/pcie-dw.c new file mode 100644 index 0000000000..2cca6f15eb --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw.c @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.dw" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +static rt_uint8_t __dw_pcie_find_next_cap(struct dw_pcie *pci, + rt_uint8_t cap_ptr, rt_uint8_t cap) +{ + rt_uint16_t reg; + rt_uint8_t cap_id, next_cap_ptr; + + if (!cap_ptr) + { + return 0; + } + + reg = dw_pcie_readw_dbi(pci, cap_ptr); + cap_id = (reg & 0x00ff); + + if (cap_id > PCIY_MAX) + { + return 0; + } + + if (cap_id == cap) + { + return cap_ptr; + } + + next_cap_ptr = (reg & 0xff00) >> 8; + return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap); +} + +rt_uint8_t dw_pcie_find_capability(struct dw_pcie *pci, rt_uint8_t cap) +{ + rt_uint16_t reg; + rt_uint8_t next_cap_ptr; + + reg = dw_pcie_readw_dbi(pci, PCIR_CAP_PTR); + next_cap_ptr = (reg & 0x00ff); + + return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap); +} + +static rt_uint16_t dw_pcie_find_next_ext_capability(struct dw_pcie *pci, + rt_uint16_t start, rt_uint8_t cap) +{ + rt_uint32_t header; + int ttl, pos = PCI_REGMAX + 1; + + /* minimum 8 bytes per capability */ + ttl = ((PCIE_REGMAX + 1) - (PCI_REGMAX + 1)) / 8; + + if (start) + { + pos = start; + } + + header = dw_pcie_readl_dbi(pci, pos); + /* + * If we have no capabilities, this is indicated by cap ID, + * cap version and next pointer all being 0. + */ + if (header == 0) + { + return 0; + } + + while (ttl-- > 0) + { + if (PCI_EXTCAP_ID(header) == cap && pos != start) + { + return pos; + } + + pos = PCI_EXTCAP_NEXTPTR(header); + + if (pos < PCI_REGMAX + 1) + { + break; + } + + header = dw_pcie_readl_dbi(pci, pos); + } + + return 0; +} + +rt_uint16_t dw_pcie_find_ext_capability(struct dw_pcie *pci, rt_uint8_t cap) +{ + return dw_pcie_find_next_ext_capability(pci, 0, cap); +} + +rt_err_t dw_pcie_read(void *addr, rt_size_t size, rt_uint32_t *out_val) +{ + /* Check aligned */ + if ((rt_ubase_t)addr & ((rt_ubase_t)size - 1)) + { + *out_val = 0; + return -RT_EINVAL; + } + + if (size == 4) + { + *out_val = HWREG32(addr); + } + else if (size == 2) + { + *out_val = HWREG16(addr); + } + else if (size == 1) + { + *out_val = HWREG8(addr); + } + else + { + *out_val = 0; + return -RT_EINVAL; + } + + return RT_EOK; +} + +rt_err_t dw_pcie_write(void *addr, rt_size_t size, rt_uint32_t val) +{ + /* Check aligned */ + if ((rt_ubase_t)addr & ((rt_ubase_t)size - 1)) + { + return -RT_EINVAL; + } + + if (size == 4) + { + HWREG32(addr) = val; + } + else if (size == 2) + { + HWREG16(addr) = val; + } + else if (size == 1) + { + HWREG8(addr) = val; + } + else + { + return -RT_EINVAL; + } + + return RT_EOK; +} + +rt_uint32_t dw_pcie_read_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size) +{ + rt_err_t err; + rt_uint32_t val = 0; + + if (pci->ops->read_dbi) + { + return pci->ops->read_dbi(pci, pci->dbi_base, reg, size); + } + + if ((err = dw_pcie_read(pci->dbi_base + reg, size, &val))) + { + LOG_E("Read DBI address error = %s", rt_strerror(err)); + } + + return val; +} + +void dw_pcie_write_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size, rt_uint32_t val) +{ + rt_err_t err; + + if (pci->ops->write_dbi) + { + pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val); + return; + } + + if ((err = dw_pcie_write(pci->dbi_base + reg, size, val))) + { + LOG_E("Write DBI address error = %s", rt_strerror(err)); + } +} + +void dw_pcie_write_dbi2(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size, rt_uint32_t val) +{ + rt_err_t err; + + if (pci->ops && pci->ops->write_dbi2) + { + pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val); + return; + } + + if ((err = dw_pcie_write(pci->dbi_base2 + reg, size, val))) + { + LOG_E("Write DBI2 address error = %s", rt_strerror(err)); + } +} + +rt_uint32_t dw_pcie_readl_atu(struct dw_pcie *pci, rt_uint32_t reg) +{ + rt_err_t err; + rt_uint32_t val = 0; + + if (pci->ops->read_dbi) + { + return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); + } + + if ((err = dw_pcie_read(pci->atu_base + reg, 4, &val))) + { + LOG_E("Read ATU address error = %s", rt_strerror(err)); + } + + return val; +} + +void dw_pcie_writel_atu(struct dw_pcie *pci, rt_uint32_t reg, rt_uint32_t val) +{ + rt_err_t err; + + if (pci->ops->write_dbi) + { + pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); + return; + } + + if ((err = dw_pcie_write(pci->atu_base + reg, 4, val))) + { + LOG_E("Write ATU address error = %s", rt_strerror(err)); + } +} + +static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, rt_uint8_t func_no, + int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + rt_uint64_t limit_addr = cpu_addr + size - 1; + + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, + rt_lower_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, + rt_upper_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT, + rt_lower_32_bits(limit_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT, + rt_upper_32_bits(limit_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, + rt_lower_32_bits(pci_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, + rt_upper_32_bits(pci_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, + type | PCIE_ATU_FUNC_NUM(func_no)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (int retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; ++retries) + { + if (dw_pcie_readl_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2) & PCIE_ATU_ENABLE) + { + return; + } + + rt_thread_mdelay(LINK_WAIT_IATU); + } + + LOG_E("Outbound iATU is not being enabled"); +} + +static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, rt_uint8_t func_no, + int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + if (pci->ops->cpu_addr_fixup) + { + cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); + } + + if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN) + { + dw_pcie_prog_outbound_atu_unroll(pci, func_no, + index, type, cpu_addr, pci_addr, size); + + return; + } + + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | index); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, rt_lower_32_bits(cpu_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, rt_upper_32_bits(cpu_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, rt_lower_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, rt_lower_32_bits(pci_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, rt_upper_32_bits(pci_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | PCIE_ATU_FUNC_NUM(func_no)); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (int retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; ++retries) + { + if (dw_pcie_readl_dbi(pci, PCIE_ATU_CR2) & PCIE_ATU_ENABLE) + { + return; + } + + rt_thread_mdelay(LINK_WAIT_IATU); + } + + LOG_E("Outbound iATU is not being enabled"); +} + +void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, + int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + __dw_pcie_prog_outbound_atu(pci, 0, index, type, cpu_addr, pci_addr, size); +} + +void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, rt_uint8_t func_no, + int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + __dw_pcie_prog_outbound_atu(pci, func_no, index, type, cpu_addr, pci_addr, size); +} + +static rt_err_t dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, + rt_uint8_t func_no, int index, int bar, rt_uint64_t cpu_addr, + enum dw_pcie_aspace_type aspace_type) +{ + int type; + + dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, + rt_lower_32_bits(cpu_addr)); + dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, + rt_upper_32_bits(cpu_addr)); + + switch (aspace_type) + { + case DW_PCIE_ASPACE_MEM: + type = PCIE_ATU_TYPE_MEM; + break; + + case DW_PCIE_ASPACE_IO: + type = PCIE_ATU_TYPE_IO; + break; + + default: + return -RT_EINVAL; + } + + dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, + type | PCIE_ATU_FUNC_NUM(func_no)); + dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_FUNC_NUM_MATCH_EN | PCIE_ATU_ENABLE | + PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (int retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; ++retries) + { + if (dw_pcie_readl_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2) & PCIE_ATU_ENABLE) + { + return RT_EOK; + } + + rt_thread_mdelay(LINK_WAIT_IATU); + } + + LOG_E("Inbound iATU is not being enabled"); + + return -RT_EBUSY; +} + +rt_err_t dw_pcie_prog_inbound_atu(struct dw_pcie *pci, + rt_uint8_t func_no, int index, int bar, rt_uint64_t cpu_addr, + enum dw_pcie_aspace_type aspace_type) +{ + int type; + + if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN) + { + return dw_pcie_prog_inbound_atu_unroll(pci, func_no, + index, bar, cpu_addr, aspace_type); + } + + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | index); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, rt_lower_32_bits(cpu_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, rt_upper_32_bits(cpu_addr)); + + switch (aspace_type) + { + case DW_PCIE_ASPACE_MEM: + type = PCIE_ATU_TYPE_MEM; + break; + + case DW_PCIE_ASPACE_IO: + type = PCIE_ATU_TYPE_IO; + break; + + default: + return -RT_EINVAL; + } + + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | PCIE_ATU_FUNC_NUM(func_no)); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | + PCIE_ATU_FUNC_NUM_MATCH_EN | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (int retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; ++retries) + { + if (dw_pcie_readl_dbi(pci, PCIE_ATU_CR2) & PCIE_ATU_ENABLE) + { + return RT_EOK; + } + + rt_thread_mdelay(LINK_WAIT_IATU); + } + + LOG_E("Inbound iATU is not being enabled"); + + return -RT_EBUSY; +} + +void dw_pcie_disable_atu(struct dw_pcie *pci, int index, enum dw_pcie_region_type type) +{ + rt_uint32_t region; + + switch (type) + { + case DW_PCIE_REGION_INBOUND: + region = PCIE_ATU_REGION_INBOUND; + break; + + case DW_PCIE_REGION_OUTBOUND: + region = PCIE_ATU_REGION_OUTBOUND; + break; + + default: + return; + } + + if (pci->iatu_unroll_enabled) + { + if (region == PCIE_ATU_REGION_INBOUND) + { + dw_pcie_writel_ib_unroll(pci, index, + PCIE_ATU_UNR_REGION_CTRL2, ~(rt_uint32_t)PCIE_ATU_ENABLE); + } + else + { + dw_pcie_writel_ob_unroll(pci, index, + PCIE_ATU_UNR_REGION_CTRL2, ~(rt_uint32_t)PCIE_ATU_ENABLE); + } + } + else + { + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(rt_uint32_t)PCIE_ATU_ENABLE); + } +} + +rt_err_t dw_pcie_wait_for_link(struct dw_pcie *pci) +{ + /* Check if the link is up or not */ + for (int retries = 0; retries < LINK_WAIT_MAX_RETRIES; ++retries) + { + if (dw_pcie_link_up(pci)) + { + LOG_I("%s: Link up", rt_dm_dev_get_name(pci->dev)); + + return RT_EOK; + } + + rt_hw_us_delay((LINK_WAIT_USLEEP_MIN + LINK_WAIT_USLEEP_MAX) >> 1); + } + + LOG_I("PHY link never came up"); + + return -RT_ETIMEOUT; +} + +rt_bool_t dw_pcie_link_up(struct dw_pcie *pci) +{ + rt_uint32_t val; + + if (pci->ops->link_up) + { + return pci->ops->link_up(pci); + } + + val = HWREG32(pci->dbi_base + PCIE_PORT_DEBUG1); + + return (val & PCIE_PORT_DEBUG1_LINK_UP) && (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)); +} + +void dw_pcie_upconfig_setup(struct dw_pcie *pci) +{ + rt_uint32_t val; + + val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL); + val |= PORT_MLTI_UPCFG_SUPPORT; + dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val); +} + +static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, rt_uint32_t link_gen) +{ + rt_uint32_t cap, ctrl2, link_speed; + rt_uint8_t offset = dw_pcie_find_capability(pci, PCIY_EXPRESS); + + cap = dw_pcie_readl_dbi(pci, offset + PCIER_LINK_CAP); + ctrl2 = dw_pcie_readl_dbi(pci, offset + PCIER_LINK_CTL2); + ctrl2 &= ~PCIEM_LNKCTL2_TLS; + + switch (link_gen) + { + case 1: link_speed = PCIEM_LNKCTL2_TLS_2_5GT; break; + case 2: link_speed = PCIEM_LNKCTL2_TLS_5_0GT; break; + case 3: link_speed = PCIEM_LNKCTL2_TLS_8_0GT; break; + case 4: link_speed = PCIEM_LNKCTL2_TLS_16_0GT; break; + default: + /* Use hardware capability */ + link_speed = RT_FIELD_GET(PCIEM_LINK_CAP_MAX_SPEED, cap); + ctrl2 &= ~PCIEM_LNKCTL2_HASD; + break; + } + + dw_pcie_writel_dbi(pci, offset + PCIER_LINK_CTL2, ctrl2 | link_speed); + + cap &= ~((rt_uint32_t)PCIEM_LINK_CAP_MAX_SPEED); + dw_pcie_writel_dbi(pci, offset + PCIER_LINK_CAP, cap | link_speed); +} + +void dw_pcie_setup(struct dw_pcie *pci) +{ + rt_uint32_t val; + struct rt_device *dev = pci->dev; + + if (pci->version >= 0x480a || (!pci->version && dw_pcie_iatu_unroll_enabled(pci))) + { + pci->iatu_unroll_enabled |= DWC_IATU_UNROLL_EN; + + if (!pci->atu_base) + { + pci->atu_base = rt_dm_dev_iomap_by_name(dev, "atu"); + } + + if (!pci->atu_base) + { + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + } + + LOG_D("iATU unroll is %sabled", pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN ? "en" : "dis"); + + if (pci->link_gen > 0) + { + dw_pcie_link_set_max_speed(pci, pci->link_gen); + } + + /* Configure Gen1 N_FTS */ + if (pci->fts_number[0]) + { + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK); + val |= PORT_AFR_N_FTS(pci->fts_number[0]); + val |= PORT_AFR_CC_N_FTS(pci->fts_number[0]); + dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); + } + + /* Configure Gen2+ N_FTS */ + if (pci->fts_number[1]) + { + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_N_FTS_MASK; + val |= pci->fts_number[1]; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); + } + + val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); + val &= ~PORT_LINK_FAST_LINK_MODE; + val |= PORT_LINK_DLL_LINK_EN; + dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); + + if (rt_dm_dev_prop_read_bool(dev, "snps,enable-cdm-check")) + { + val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS); + val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS | PCIE_PL_CHK_REG_CHK_REG_START; + dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val); + } + + rt_dm_dev_prop_read_u32(dev, "num-lanes", &pci->num_lanes); + + if (!pci->num_lanes) + { + LOG_D("Using h/w default number of lanes"); + return; + } + + /* Set the number of lanes */ + val &= ~PORT_LINK_FAST_LINK_MODE; + val &= ~PORT_LINK_MODE_MASK; + switch (pci->num_lanes) + { + case 1: val |= PORT_LINK_MODE_1_LANES; break; + case 2: val |= PORT_LINK_MODE_2_LANES; break; + case 4: val |= PORT_LINK_MODE_4_LANES; break; + case 8: val |= PORT_LINK_MODE_8_LANES; break; + default: + LOG_E("Invail num-lanes = %d", pci->num_lanes); + return; + } + dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); + + /* Set link width speed control register */ + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_LINK_WIDTH_MASK; + switch (pci->num_lanes) + { + case 1: val |= PORT_LOGIC_LINK_WIDTH_1_LANES; break; + case 2: val |= PORT_LOGIC_LINK_WIDTH_2_LANES; break; + case 4: val |= PORT_LOGIC_LINK_WIDTH_4_LANES; break; + case 8: val |= PORT_LOGIC_LINK_WIDTH_8_LANES; break; + } + val |= pci->user_speed; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); +} diff --git a/components/drivers/pci/host/dw/pcie-dw.h b/components/drivers/pci/host/dw/pcie-dw.h new file mode 100644 index 0000000000..c0760bf884 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw.h @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __PCIE_DESIGNWARE_H__ +#define __PCIE_DESIGNWARE_H__ + +#include +#include + +/* Parameters for the waiting for link up routine */ +#define LINK_WAIT_MAX_RETRIES 10 +#define LINK_WAIT_USLEEP_MIN 90000 +#define LINK_WAIT_USLEEP_MAX 100000 + +/* Parameters for the waiting for iATU enabled routine */ +#define LINK_WAIT_MAX_IATU_RETRIES 5 +#define LINK_WAIT_IATU 9 + +/* Synopsys-specific PCIe configuration registers */ +#define PCIE_PORT_AFR 0x70c +#define PORT_AFR_N_FTS_MASK RT_GENMASK(15, 8) +#define PORT_AFR_N_FTS(n) RT_FIELD_PREP(PORT_AFR_N_FTS_MASK, n) +#define PORT_AFR_CC_N_FTS_MASK RT_GENMASK(23, 16) +#define PORT_AFR_CC_N_FTS(n) RT_FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n) +#define PORT_AFR_ENTER_ASPM RT_BIT(30) +#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24 +#define PORT_AFR_L0S_ENTRANCE_LAT_MASK RT_GENMASK(26, 24) +#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27 +#define PORT_AFR_L1_ENTRANCE_LAT_MASK RT_GENMASK(29, 27) + +#define PCIE_PORT_LINK_CONTROL 0x710 +#define PORT_LINK_LPBK_ENABLE RT_BIT(2) +#define PORT_LINK_DLL_LINK_EN RT_BIT(5) +#define PORT_LINK_FAST_LINK_MODE RT_BIT(7) +#define PORT_LINK_MODE_MASK RT_GENMASK(21, 16) +#define PORT_LINK_MODE(n) RT_FIELD_PREP(PORT_LINK_MODE_MASK, n) +#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1) +#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3) +#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7) +#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf) + +#define PCIE_PORT_DEBUG0 0x728 +#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f +#define PORT_LOGIC_LTSSM_STATE_L0 0x11 +#define PCIE_PORT_DEBUG1 0x72c +#define PCIE_PORT_DEBUG1_LINK_UP RT_BIT(4) +#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING RT_BIT(29) + +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c +#define PORT_LOGIC_N_FTS_MASK RT_GENMASK(7, 0) +#define PORT_LOGIC_SPEED_CHANGE RT_BIT(17) +#define PORT_LOGIC_LINK_WIDTH_MASK RT_GENMASK(12, 8) +#define PORT_LOGIC_LINK_WIDTH(n) RT_FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n) +#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1) +#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2) +#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4) +#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8) + +#define PCIE_MSI_ADDR_LO 0x820 +#define PCIE_MSI_ADDR_HI 0x824 +#define PCIE_MSI_INTR0_ENABLE 0x828 +#define PCIE_MSI_INTR0_MASK 0x82c +#define PCIE_MSI_INTR0_STATUS 0x830 + +#define PCIE_PORT_MULTI_LANE_CTRL 0x8c0 +#define PORT_MLTI_UPCFG_SUPPORT RT_BIT(7) + +#define PCIE_ATU_VIEWPORT 0x900 +#define PCIE_ATU_REGION_INBOUND RT_BIT(31) +#define PCIE_ATU_REGION_OUTBOUND 0 +#define PCIE_ATU_CR1 0x904 +#define PCIE_ATU_TYPE_MEM 0x0 +#define PCIE_ATU_TYPE_IO 0x2 +#define PCIE_ATU_TYPE_CFG0 0x4 +#define PCIE_ATU_TYPE_CFG1 0x5 +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) +#define PCIE_ATU_CR2 0x908 +#define PCIE_ATU_ENABLE RT_BIT(31) +#define PCIE_ATU_BAR_MODE_ENABLE RT_BIT(30) +#define PCIE_ATU_FUNC_NUM_MATCH_EN RT_BIT(19) +#define PCIE_ATU_LOWER_BASE 0x90c +#define PCIE_ATU_UPPER_BASE 0x910 +#define PCIE_ATU_LIMIT 0x914 +#define PCIE_ATU_LOWER_TARGET 0x918 +#define PCIE_ATU_BUS(x) RT_FIELD_PREP(RT_GENMASK(31, 24), x) +#define PCIE_ATU_DEV(x) RT_FIELD_PREP(RT_GENMASK(23, 19), x) +#define PCIE_ATU_FUNC(x) RT_FIELD_PREP(RT_GENMASK(18, 16), x) +#define PCIE_ATU_UPPER_TARGET 0x91c + +#define PCIE_MISC_CONTROL_1_OFF 0x8bc +#define PCIE_DBI_RO_WR_EN RT_BIT(0) + +#define PCIE_MSIX_DOORBELL 0x948 +#define PCIE_MSIX_DOORBELL_PF_SHIFT 24 + +#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xb20 +#define PCIE_PL_CHK_REG_CHK_REG_START RT_BIT(0) +#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS RT_BIT(1) +#define PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR RT_BIT(16) +#define PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR RT_BIT(17) +#define PCIE_PL_CHK_REG_CHK_REG_COMPLETE RT_BIT(18) + +#define PCIE_PL_CHK_REG_ERR_ADDR 0xb28 + +/* + * iATU Unroll-specific register definitions + * From 4.80 core version the address translation will be made by unroll + */ +#define PCIE_ATU_UNR_REGION_CTRL1 0x00 +#define PCIE_ATU_UNR_REGION_CTRL2 0x04 +#define PCIE_ATU_UNR_LOWER_BASE 0x08 +#define PCIE_ATU_UNR_UPPER_BASE 0x0C +#define PCIE_ATU_UNR_LOWER_LIMIT 0x10 +#define PCIE_ATU_UNR_LOWER_TARGET 0x14 +#define PCIE_ATU_UNR_UPPER_TARGET 0x18 +#define PCIE_ATU_UNR_UPPER_LIMIT 0x20 + +/* + * The default address offset between dbi_base and atu_base. Root controller + * drivers are not required to initialize atu_base if the offset matches this + * default; the driver core automatically derives atu_base from dbi_base using + * this offset, if atu_base not set. + */ +#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20) + +/* Register address builder */ +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9) +#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) (((region) << 9) | RT_BIT(8)) + +#define MAX_MSI_IRQS 256 +#define MAX_MSI_IRQS_PER_CTRL 32 +#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) +#define MSI_REG_CTRL_BLOCK_SIZE 12 +#define MSI_DEF_NUM_VECTORS 32 + +/* Maximum number of inbound/outbound iATUs */ +#define MAX_IATU_IN 256 +#define MAX_IATU_OUT 256 + +#define DWC_IATU_UNROLL_EN RT_BIT(0) +#define DWC_IATU_IOCFG_SHARED RT_BIT(1) + +struct dw_pcie_host_ops; +struct dw_pcie_ep_ops; +struct dw_pcie_ops; + +enum dw_pcie_region_type +{ + DW_PCIE_REGION_UNKNOWN, + DW_PCIE_REGION_INBOUND, + DW_PCIE_REGION_OUTBOUND, +}; + +enum dw_pcie_device_mode +{ + DW_PCIE_UNKNOWN_TYPE, + DW_PCIE_EP_TYPE, + DW_PCIE_LEG_EP_TYPE, + DW_PCIE_RC_TYPE, +}; + +enum dw_pcie_aspace_type +{ + DW_PCIE_ASPACE_UNKNOWN, + DW_PCIE_ASPACE_MEM, + DW_PCIE_ASPACE_IO, +}; + +struct dw_pcie_port +{ + void *cfg0_base; + rt_uint64_t cfg0_addr; + rt_uint64_t cfg0_size; + + rt_ubase_t io_addr; + rt_ubase_t io_bus_addr; + rt_size_t io_size; + + const struct dw_pcie_host_ops *ops; + + int sys_irq; + int msi_irq; + struct rt_pic *irq_pic; + struct rt_pic *msi_pic; + + void *msi_data; + rt_ubase_t msi_data_phy; + + rt_uint32_t irq_count; + rt_uint32_t irq_mask[MAX_MSI_CTRLS]; + + struct rt_pci_host_bridge *bridge; + const struct rt_pci_ops *bridge_child_ops; + + struct rt_spinlock lock; + RT_BITMAP_DECLARE(msi_map, MAX_MSI_IRQS); +}; + +struct dw_pcie_host_ops +{ + rt_err_t (*host_init)(struct dw_pcie_port *port); + rt_err_t (*msi_host_init)(struct dw_pcie_port *port); + void (*set_irq_count)(struct dw_pcie_port *port); +}; + +struct dw_pcie_ep_func +{ + rt_list_t list; + + rt_uint8_t func_no; + rt_uint8_t msi_cap; /* MSI capability offset */ + rt_uint8_t msix_cap; /* MSI-X capability offset */ +}; + +struct dw_pcie_ep +{ + struct rt_pci_ep *epc; + struct rt_pci_ep_bar *epc_bar[PCI_STD_NUM_BARS]; + + rt_list_t func_nodes; + + const struct dw_pcie_ep_ops *ops; + + rt_uint64_t aspace; + rt_uint64_t aspace_size; + rt_size_t page_size; + + rt_uint8_t bar_to_atu[PCI_STD_NUM_BARS]; + rt_ubase_t *outbound_addr; + + rt_bitmap_t *ib_window_map; + rt_bitmap_t *ob_window_map; + rt_uint32_t num_ib_windows; + rt_uint32_t num_ob_windows; + + void *msi_mem; + rt_ubase_t msi_mem_phy; +}; + +struct dw_pcie_ep_ops +{ + rt_err_t (*ep_init)(struct dw_pcie_ep *ep); + rt_err_t (*raise_irq)(struct dw_pcie_ep *ep, rt_uint8_t func_no, enum rt_pci_ep_irq type, unsigned irq); + rt_off_t (*func_select)(struct dw_pcie_ep *ep, rt_uint8_t func_no); +}; + +struct dw_pcie +{ + struct rt_device *dev; + + void *dbi_base; + void *dbi_base2; + void *atu_base; + + rt_uint32_t version; + rt_uint32_t num_viewport; + rt_uint32_t num_lanes; + rt_uint32_t link_gen; + rt_uint32_t user_speed; + rt_uint8_t iatu_unroll_enabled; /* Internal Address Translation Unit */ + rt_uint8_t fts_number[2]; /* Fast Training Sequences */ + + struct dw_pcie_port port; + struct dw_pcie_ep endpoint; + const struct dw_pcie_ops *ops; + + void *priv; +}; + +struct dw_pcie_ops +{ + rt_uint64_t (*cpu_addr_fixup)(struct dw_pcie *pcie, rt_uint64_t cpu_addr); + rt_uint32_t (*read_dbi)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size); + void (*write_dbi)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); + void (*write_dbi2)(struct dw_pcie *pcie, void *base, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); + rt_bool_t (*link_up)(struct dw_pcie *pcie); + rt_err_t (*start_link)(struct dw_pcie *pcie); + void (*stop_link)(struct dw_pcie *pcie); +}; + +#define to_dw_pcie_from_port(ptr) rt_container_of((ptr), struct dw_pcie, port) +#define to_dw_pcie_from_endpoint(ptr) rt_container_of((ptr), struct dw_pcie, endpoint) + +#ifdef RT_PCI_DW_HOST +#undef RT_PCI_DW_HOST +#define RT_PCI_DW_HOST 1 +#define HOST_API +#define HOST_RET(...) ; +#else +#define HOST_API rt_inline +#define HOST_RET(...) { return __VA_ARGS__; } +#endif + +#ifdef RT_PCI_DW_EP +#undef RT_PCI_DW_EP +#define RT_PCI_DW_EP 1 +#define EP_API +#define EP_RET(...) ; +#else +#define EP_API rt_inline +#define EP_RET(...) { return __VA_ARGS__; } +#endif + +rt_uint8_t dw_pcie_find_capability(struct dw_pcie *pci, rt_uint8_t cap); +rt_uint16_t dw_pcie_find_ext_capability(struct dw_pcie *pci, rt_uint8_t cap); + +rt_err_t dw_pcie_read(void *addr, rt_size_t size, rt_uint32_t *out_val); +rt_err_t dw_pcie_write(void *addr, rt_size_t size, rt_uint32_t val); + +rt_uint32_t dw_pcie_read_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size); +void dw_pcie_write_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); +void dw_pcie_write_dbi2(struct dw_pcie *pci, rt_uint32_t reg, rt_size_t size, rt_uint32_t val); +rt_uint32_t dw_pcie_readl_atu(struct dw_pcie *pci, rt_uint32_t reg); +void dw_pcie_writel_atu(struct dw_pcie *pci, rt_uint32_t reg, rt_uint32_t val); +rt_bool_t dw_pcie_link_up(struct dw_pcie *pci); +void dw_pcie_upconfig_setup(struct dw_pcie *pci); +rt_err_t dw_pcie_wait_for_link(struct dw_pcie *pci); +void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size); +void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, rt_uint8_t func_no, int index, int type, rt_uint64_t cpu_addr, rt_uint64_t pci_addr, rt_size_t size); +rt_err_t dw_pcie_prog_inbound_atu(struct dw_pcie *pci, rt_uint8_t func_no, int index, int bar, rt_uint64_t cpu_addr, enum dw_pcie_aspace_type aspace_type); +void dw_pcie_disable_atu(struct dw_pcie *pci, int index, enum dw_pcie_region_type type); +void dw_pcie_setup(struct dw_pcie *pci); + +rt_inline void dw_pcie_writel_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_uint32_t val) +{ + dw_pcie_write_dbi(pci, reg, 0x4, val); +} + +rt_inline rt_uint32_t dw_pcie_readl_dbi(struct dw_pcie *pci, rt_uint32_t reg) +{ + return dw_pcie_read_dbi(pci, reg, 0x4); +} + +rt_inline void dw_pcie_writew_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_uint16_t val) +{ + dw_pcie_write_dbi(pci, reg, 0x2, val); +} + +rt_inline rt_uint16_t dw_pcie_readw_dbi(struct dw_pcie *pci, rt_uint32_t reg) +{ + return dw_pcie_read_dbi(pci, reg, 0x2); +} + +rt_inline void dw_pcie_writeb_dbi(struct dw_pcie *pci, rt_uint32_t reg, rt_uint8_t val) +{ + dw_pcie_write_dbi(pci, reg, 0x1, val); +} + +rt_inline rt_uint8_t dw_pcie_readb_dbi(struct dw_pcie *pci, rt_uint32_t reg) +{ + return dw_pcie_read_dbi(pci, reg, 0x1); +} + +rt_inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, rt_uint32_t reg, rt_uint32_t val) +{ + dw_pcie_write_dbi2(pci, reg, 0x4, val); +} + +rt_inline void dw_pcie_dbi_ro_writable_enable(struct dw_pcie *pci, rt_bool_t enable) +{ + const rt_uint32_t reg = PCIE_MISC_CONTROL_1_OFF; + + if (enable) + { + dw_pcie_writel_dbi(pci, reg, dw_pcie_readl_dbi(pci, reg) | PCIE_DBI_RO_WR_EN); + } + else + { + dw_pcie_writel_dbi(pci, reg, dw_pcie_readl_dbi(pci, reg) & ~PCIE_DBI_RO_WR_EN); + } +} + +rt_inline rt_uint8_t dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) +{ + return dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) == 0xffffffff ? 1 : 0; +} + +rt_inline rt_uint32_t dw_pcie_readl_ob_unroll(struct dw_pcie *pci, + rt_uint32_t index, rt_uint32_t reg) +{ + return dw_pcie_readl_atu(pci, PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index) + reg); +} + +rt_inline void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, + rt_uint32_t index, rt_uint32_t reg, rt_uint32_t val) +{ + dw_pcie_writel_atu(pci, PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index) + reg, val); +} + +rt_inline rt_uint32_t dw_pcie_readl_ib_unroll(struct dw_pcie *pci, + rt_uint32_t index, rt_uint32_t reg) +{ + return dw_pcie_readl_atu(pci, PCIE_GET_ATU_INB_UNR_REG_OFFSET(index) + reg); +} + +rt_inline void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, + rt_uint32_t index, rt_uint32_t reg, rt_uint32_t val) +{ + dw_pcie_writel_atu(pci, reg + PCIE_GET_ATU_INB_UNR_REG_OFFSET(index), val); +} + +HOST_API rt_err_t dw_handle_msi_irq(struct dw_pcie_port *port) HOST_RET(-RT_ENOSYS) +HOST_API void dw_pcie_msi_init(struct dw_pcie_port *port) HOST_RET() +HOST_API void dw_pcie_free_msi(struct dw_pcie_port *port) HOST_RET() + +HOST_API void dw_pcie_setup_rc(struct dw_pcie_port *port) HOST_RET() + +HOST_API rt_err_t dw_pcie_host_init(struct dw_pcie_port *port) HOST_RET(-RT_ENOSYS) +HOST_API void dw_pcie_host_deinit(struct dw_pcie_port *port) HOST_RET() + +HOST_API void dw_pcie_host_free(struct dw_pcie_port *port) HOST_RET() + +HOST_API void *dw_pcie_own_conf_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg) HOST_RET(RT_NULL) + +EP_API rt_err_t dw_pcie_ep_init(struct dw_pcie_ep *ep) EP_RET(-RT_ENOSYS) +EP_API rt_err_t dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) EP_RET(-RT_ENOSYS) +EP_API void dw_pcie_ep_exit(struct dw_pcie_ep *ep) EP_RET() + +EP_API rt_err_t dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no) EP_RET(-RT_ENOSYS) +EP_API rt_err_t dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, unsigned irq) EP_RET(-RT_ENOSYS) +EP_API rt_err_t dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, unsigned irq) EP_RET(-RT_ENOSYS) +EP_API rt_err_t dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, rt_uint8_t func_no, unsigned irq) EP_RET(-RT_ENOSYS) + +EP_API void dw_pcie_ep_reset_bar(struct dw_pcie *pci, int bar_idx) EP_RET() + +EP_API rt_err_t dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, rt_uint8_t func_no, + int bar_idx, rt_ubase_t cpu_addr, enum dw_pcie_aspace_type aspace_type) EP_RET(-RT_ENOSYS) +EP_API rt_err_t dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, rt_uint8_t func_no, + rt_ubase_t phys_addr, rt_uint64_t pci_addr, rt_size_t size) EP_RET(-RT_ENOSYS) + +EP_API struct dw_pcie_ep_func *dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, rt_uint8_t func_no) EP_RET() + +#endif /* __PCIE_DESIGNWARE_H__ */ diff --git a/components/drivers/pci/host/dw/pcie-dw_ep.c b/components/drivers/pci/host/dw/pcie-dw_ep.c new file mode 100644 index 0000000000..b52f6b5324 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_ep.c @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.dw-ep" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +struct dw_pcie_ep_func *dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, rt_uint8_t func_no) +{ + struct dw_pcie_ep_func *ep_func; + + rt_list_for_each_entry(ep_func, &ep->func_nodes, list) + { + if (ep_func->func_no == func_no) + { + return ep_func; + } + } + + return RT_NULL; +} + +static rt_uint8_t dw_pcie_ep_func_select(struct dw_pcie_ep *ep, rt_uint8_t func_no) +{ + rt_uint8_t func_offset = 0; + + if (ep->ops->func_select) + { + func_offset = ep->ops->func_select(ep, func_no); + } + + return func_offset; +} + +static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, rt_uint8_t func_no, + int bar_idx, int flags) +{ + rt_uint32_t reg; + rt_uint8_t func_offset = 0; + struct dw_pcie_ep *ep = &pci->endpoint; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = func_offset + PCIR_BAR(bar_idx); + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + dw_pcie_writel_dbi2(pci, reg, 0x0); + dw_pcie_writel_dbi(pci, reg, 0x0); + + if (flags & PCIM_BAR_MEM_TYPE_64) + { + dw_pcie_writel_dbi2(pci, reg + 4, 0x0); + dw_pcie_writel_dbi(pci, reg + 4, 0x0); + } + + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); +} + +void dw_pcie_ep_reset_bar(struct dw_pcie *pci, int bar_idx) +{ + rt_uint8_t func_no, funcs = pci->endpoint.epc->max_functions; + + for (func_no = 0; func_no < funcs; ++func_no) + { + __dw_pcie_ep_reset_bar(pci, func_no, bar_idx, 0); + } +} + +static rt_uint8_t __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, rt_uint8_t func_no, + rt_uint8_t cap_ptr, rt_uint8_t cap) +{ + rt_uint16_t reg; + rt_uint8_t func_offset = 0, cap_id, next_cap_ptr; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + if (!cap_ptr) + { + return 0; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); + cap_id = (reg & 0x00ff); + + if (cap_id > PCIY_MAX) + { + return 0; + } + + if (cap_id == cap) + { + return cap_ptr; + } + + next_cap_ptr = (reg & 0xff00) >> 8; + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + +static rt_uint8_t dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, rt_uint8_t func_no, + rt_uint8_t cap) +{ + rt_uint16_t reg; + rt_uint8_t func_offset = 0, next_cap_ptr; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = dw_pcie_readw_dbi(pci, func_offset + PCIR_CAP_PTR); + next_cap_ptr = reg & 0x00ff; + + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + +rt_err_t dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, rt_uint8_t func_no, + int bar_idx, rt_ubase_t cpu_addr, enum dw_pcie_aspace_type aspace_type) +{ + rt_err_t err; + rt_uint32_t free_win; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + free_win = rt_bitmap_next_clear_bit(ep->ib_window_map, 0, ep->num_ib_windows); + if (free_win >= ep->num_ib_windows) + { + LOG_E("No free inbound window"); + return -RT_EEMPTY; + } + + err = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar_idx, cpu_addr, aspace_type); + if (err) + { + LOG_E("Failed to program IB window error = %s", rt_strerror(err)); + return err; + } + + ep->bar_to_atu[bar_idx] = free_win; + rt_bitmap_set_bit(ep->ib_window_map, free_win); + + return RT_EOK; +} + +rt_err_t dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, rt_uint8_t func_no, + rt_ubase_t phys_addr, rt_uint64_t pci_addr, rt_size_t size) +{ + rt_uint32_t free_win; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + free_win = rt_bitmap_next_clear_bit(ep->ob_window_map, 0, ep->num_ob_windows); + if (free_win >= ep->num_ob_windows) + { + LOG_E("No free outbound window"); + return -RT_EEMPTY; + } + + dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM, + phys_addr, pci_addr, size); + + ep->outbound_addr[free_win] = phys_addr; + rt_bitmap_set_bit(ep->ob_window_map, free_win); + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_write_header(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_header *hdr) +{ + rt_uint8_t func_offset = 0; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + dw_pcie_writew_dbi(pci, func_offset + PCIR_VENDOR, hdr->vendor); + dw_pcie_writew_dbi(pci, func_offset + PCIR_DEVICE, hdr->device); + dw_pcie_writeb_dbi(pci, func_offset + PCIR_REVID, hdr->revision); + dw_pcie_writeb_dbi(pci, func_offset + PCIR_PROGIF, hdr->progif); + dw_pcie_writew_dbi(pci, func_offset + PCIR_SUBCLASS, hdr->subclass | hdr->class_code << 8); + dw_pcie_writeb_dbi(pci, func_offset + PCIR_CACHELNSZ, hdr->cache_line_size); + dw_pcie_writew_dbi(pci, func_offset + PCIR_SUBVEND_0, hdr->subsystem_vendor); + dw_pcie_writew_dbi(pci, func_offset + PCIR_SUBDEV_0, hdr->subsystem_device); + dw_pcie_writeb_dbi(pci, func_offset + PCIR_INTPIN, hdr->intx); + + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + return 0; +} + +static rt_err_t dw_pcie_ep_clear_bar(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_bar *bar, int bar_idx) +{ + rt_uint32_t atu_index; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + atu_index = ep->bar_to_atu[bar_idx]; + __dw_pcie_ep_reset_bar(pci, func_no, bar_idx, ep->epc_bar[bar_idx]->bus.flags); + + dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND); + rt_bitmap_clear_bit(ep->ib_window_map, atu_index); + ep->epc_bar[bar_idx] = RT_NULL; + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_set_bar(struct rt_pci_ep *epc, rt_uint8_t func_no, + struct rt_pci_ep_bar *bar, int bar_idx) +{ + rt_err_t err; + rt_uint32_t reg; + rt_uint8_t func_offset = 0; + rt_size_t size = bar->bus.size; + rt_ubase_t flags = bar->bus.flags; + enum dw_pcie_aspace_type aspace_type; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = PCIR_BAR(bar_idx) + func_offset; + + if (!(flags & PCIM_BAR_SPACE)) + { + aspace_type = DW_PCIE_ASPACE_MEM; + } + else + { + aspace_type = DW_PCIE_ASPACE_IO; + } + + err = dw_pcie_ep_inbound_atu(ep, func_no, bar_idx, bar->bus.base, aspace_type); + if (err) + { + return err; + } + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + dw_pcie_writel_dbi2(pci, reg, rt_lower_32_bits(size - 1)); + dw_pcie_writel_dbi(pci, reg, flags); + + if (flags & PCIM_BAR_MEM_TYPE_64) + { + dw_pcie_writel_dbi2(pci, reg + 4, rt_upper_32_bits(size - 1)); + dw_pcie_writel_dbi(pci, reg + 4, 0); + } + + ep->epc_bar[bar_idx] = bar; + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + return 0; +} + +static rt_err_t dw_pcie_find_index(struct dw_pcie_ep *ep, + rt_ubase_t addr, rt_uint32_t *atu_index) +{ + for (rt_uint32_t index = 0; index < ep->num_ob_windows; ++index) + { + if (ep->outbound_addr[index] != addr) + { + continue; + } + + *atu_index = index; + + return RT_EOK; + } + + return -RT_EINVAL; +} + +static rt_err_t dw_pcie_ep_unmap_addr(struct rt_pci_ep *epc, rt_uint8_t func_no, + rt_ubase_t addr) +{ + rt_err_t err; + rt_uint32_t atu_index; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + if ((err = dw_pcie_find_index(ep, addr, &atu_index))) + { + return err; + } + + dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND); + rt_bitmap_clear_bit(ep->ob_window_map, atu_index); + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_map_addr(struct rt_pci_ep *epc, rt_uint8_t func_no, + rt_ubase_t addr, rt_uint64_t pci_addr, rt_size_t size) +{ + rt_err_t err; + struct dw_pcie_ep *ep = epc->priv; + + err = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size); + if (err) + { + LOG_E("Failed to enable address error = %s", rt_strerror(err)); + return err; + } + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_set_msi(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned irq_nr) +{ + rt_uint32_t val, reg; + rt_uint8_t func_offset = 0; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) + { + return -RT_EINVAL; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = ep_func->msi_cap + func_offset + PCIR_MSI_CTRL; + + val = dw_pcie_readw_dbi(pci, reg); + val &= ~PCIM_MSICTRL_MMC_MASK; + val |= (irq_nr << 1) & PCIM_MSICTRL_MMC_MASK; + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + dw_pcie_writew_dbi(pci, reg, val); + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_get_msi(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned *out_irq_nr) +{ + rt_uint32_t val, reg; + rt_uint8_t func_offset = 0; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) + { + return -RT_EINVAL; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = ep_func->msi_cap + func_offset + PCIR_MSI_CTRL; + + val = dw_pcie_readw_dbi(pci, reg); + if (!(val & PCIM_MSICTRL_MSI_ENABLE)) + { + return -RT_EINVAL; + } + + *out_irq_nr = (val & PCIM_MSICTRL_MME_MASK) >> 4; + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_set_msix(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned irq_nr, int bar_idx, rt_off_t offset) +{ + rt_uint32_t val, reg; + rt_uint8_t func_offset = 0; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + { + return -RT_EINVAL; + } + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = ep_func->msix_cap + func_offset + PCIR_MSIX_CTRL; + + val = dw_pcie_readw_dbi(pci, reg); + val &= ~PCIM_MSIXCTRL_TABLE_SIZE; + val |= irq_nr; + dw_pcie_writew_dbi(pci, reg, val); + + reg = ep_func->msix_cap + func_offset + PCIR_MSIX_TABLE; + val = offset | bar_idx; + dw_pcie_writel_dbi(pci, reg, val); + + reg = ep_func->msix_cap + func_offset + PCIR_MSIX_PBA; + val = (offset + (irq_nr * PCIM_MSIX_ENTRY_SIZE)) | bar_idx; + dw_pcie_writel_dbi(pci, reg, val); + + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_get_msix(struct rt_pci_ep *epc, rt_uint8_t func_no, + unsigned *out_irq_nr) +{ + rt_uint32_t val, reg; + rt_uint8_t func_offset = 0; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + { + return -RT_EINVAL; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = ep_func->msix_cap + func_offset + PCIR_MSIX_CTRL; + + val = dw_pcie_readw_dbi(pci, reg); + if (!(val & PCIM_MSIXCTRL_MSIX_ENABLE)) + { + return -RT_EINVAL; + } + + *out_irq_nr = val & PCIM_MSIXCTRL_TABLE_SIZE; + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_raise_irq(struct rt_pci_ep *epc, rt_uint8_t func_no, + enum rt_pci_ep_irq type, unsigned irq) +{ + struct dw_pcie_ep *ep = epc->priv; + + if (!ep->ops->raise_irq) + { + return -RT_ENOSYS; + } + + return ep->ops->raise_irq(ep, func_no, type, irq); +} + +static rt_err_t dw_pcie_ep_stop(struct rt_pci_ep *epc) +{ + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + if (pci->ops->stop_link) + { + pci->ops->stop_link(pci); + } + + return RT_EOK; +} + +static rt_err_t dw_pcie_ep_start(struct rt_pci_ep *epc) +{ + struct dw_pcie_ep *ep = epc->priv; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + if (pci->ops->start_link) + { + return pci->ops->start_link(pci); + } + + return RT_EOK; +} + +static const struct rt_pci_ep_ops dw_pcie_ep_ops = +{ + .write_header = dw_pcie_ep_write_header, + .set_bar = dw_pcie_ep_set_bar, + .clear_bar = dw_pcie_ep_clear_bar, + .map_addr = dw_pcie_ep_map_addr, + .unmap_addr = dw_pcie_ep_unmap_addr, + .set_msi = dw_pcie_ep_set_msi, + .get_msi = dw_pcie_ep_get_msi, + .set_msix = dw_pcie_ep_set_msix, + .get_msix = dw_pcie_ep_get_msix, + .raise_irq = dw_pcie_ep_raise_irq, + .start = dw_pcie_ep_start, + .stop = dw_pcie_ep_stop, +}; + +rt_err_t dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no) +{ + LOG_E("EP cannot trigger legacy IRQs"); + + return -RT_EINVAL; +} + +rt_err_t dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, + unsigned irq) +{ + rt_err_t err; + rt_off_t aligned_offset; + rt_uint8_t func_offset = 0; + rt_uint64_t msg_addr; + rt_uint16_t msg_ctrl, msg_data; + rt_uint32_t msg_addr_lower, msg_addr_upper, reg; + struct rt_pci_ep *epc = ep->epc; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) + { + return -RT_EINVAL; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ + reg = ep_func->msi_cap + func_offset + PCIR_MSI_CTRL; + msg_ctrl = dw_pcie_readw_dbi(pci, reg); + reg = ep_func->msi_cap + func_offset + PCIR_MSI_ADDR; + msg_addr_lower = dw_pcie_readl_dbi(pci, reg); + + if (!!(msg_ctrl & PCIM_MSICTRL_64BIT)) + { + reg = ep_func->msi_cap + func_offset + PCIR_MSI_ADDR_HIGH; + msg_addr_upper = dw_pcie_readl_dbi(pci, reg); + reg = ep_func->msi_cap + func_offset + PCIR_MSI_DATA_64BIT; + msg_data = dw_pcie_readw_dbi(pci, reg); + } + else + { + msg_addr_upper = 0; + reg = ep_func->msi_cap + func_offset + PCIR_MSI_DATA; + msg_data = dw_pcie_readw_dbi(pci, reg); + } + + aligned_offset = msg_addr_lower & (ep->page_size - 1); + msg_addr = ((rt_uint64_t)msg_addr_upper << 32) | (msg_addr_lower & ~aligned_offset); + + if ((err = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phy, msg_addr, ep->page_size))) + { + return err; + } + + HWREG32(ep->msi_mem + aligned_offset) = msg_data | (irq - 1); + dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phy); + + return RT_EOK; +} + +rt_err_t dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, rt_uint8_t func_no, + unsigned irq) +{ + rt_uint32_t msg_data; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + { + return -RT_EINVAL; + } + + msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) | (irq - 1); + dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data); + + return RT_EOK; +} + +rt_err_t dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, rt_uint8_t func_no, + unsigned irq) +{ + rt_err_t err; + int bar_idx; + rt_uint64_t msg_addr; + rt_uint32_t tbl_offset; + rt_off_t aligned_offset; + rt_uint8_t func_offset = 0; + rt_uint32_t reg, msg_data, vec_ctrl; + struct rt_pci_ep *epc = ep->epc; + struct rt_pci_ep_msix_tbl *msix_tbl; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + { + return -RT_EINVAL; + } + + func_offset = dw_pcie_ep_func_select(ep, func_no); + reg = ep_func->msix_cap + func_offset + PCIR_MSIX_TABLE; + + tbl_offset = dw_pcie_readl_dbi(pci, reg); + bar_idx = (tbl_offset & PCIM_MSIX_BIR_MASK); + tbl_offset &= PCIM_MSIX_TABLE_OFFSET; + + msix_tbl = (void *)ep->epc_bar[bar_idx]->cpu_addr + tbl_offset; + msg_addr = msix_tbl[(irq - 1)].msg_addr; + msg_data = msix_tbl[(irq - 1)].msg_data; + vec_ctrl = msix_tbl[(irq - 1)].vector_ctrl; + + if (vec_ctrl & PCIM_MSIX_ENTRYVECTOR_CTRL_MASK) + { + return -RT_EINVAL; + } + + aligned_offset = msg_addr & (ep->page_size - 1); + + if ((err = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phy, msg_addr, ep->page_size))) + { + return err; + } + + HWREG32(ep->msi_mem + aligned_offset) = msg_data; + dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phy); + + return RT_EOK; +} + +void dw_pcie_ep_exit(struct dw_pcie_ep *ep) +{ + struct rt_pci_ep *epc = ep->epc; + + if (ep->msi_mem) + { + rt_pci_ep_mem_free(epc, ep->msi_mem, ep->msi_mem_phy, ep->page_size); + } + + if (!rt_list_isempty(&ep->func_nodes)) + { + struct dw_pcie_ep_func *ep_func, *ep_func_next; + + rt_list_for_each_entry_safe(ep_func, ep_func_next, &ep->func_nodes, list) + { + rt_list_remove(&ep_func->list); + rt_free(ep_func); + } + } + + if (ep->ib_window_map) + { + rt_free(ep->ib_window_map); + } + + if (ep->ob_window_map) + { + rt_free(ep->ob_window_map); + } + + if (ep->outbound_addr) + { + rt_free(ep->outbound_addr); + } + + if (epc) + { + rt_free(epc); + } +} + +static rt_uint32_t dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) +{ + rt_uint32_t header; + int pos = (PCI_REGMAX + 1); + + while (pos) + { + header = dw_pcie_readl_dbi(pci, pos); + + if (PCI_EXTCAP_ID(header) == cap) + { + return pos; + } + + if (!(pos = PCI_EXTCAP_NEXTPTR(header))) + { + break; + } + } + + return 0; +} + +rt_err_t dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) +{ + rt_off_t offset; + rt_size_t bar_nr; + rt_uint32_t reg; + rt_uint8_t hdr_type; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + hdr_type = dw_pcie_readb_dbi(pci, PCIR_HDRTYPE) & PCIM_HDRTYPE; + if (hdr_type != PCIM_HDRTYPE_NORMAL) + { + LOG_E("PCIe controller is not set to EP mode hdr_type = %x", hdr_type); + return -RT_EIO; + } + + offset = dw_pcie_ep_find_ext_capability(pci, PCIZ_RESIZE_BAR); + + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + if (offset) + { + reg = dw_pcie_readl_dbi(pci, offset + PCIM_REBAR_CTRL); + bar_nr = (reg & PCIM_REBAR_CTRL_NBAR_MASK) >> PCIM_REBAR_CTRL_NBAR_SHIFT; + + for (int i = 0; i < bar_nr; ++i, offset += PCIM_REBAR_CTRL) + { + dw_pcie_writel_dbi(pci, offset + PCIM_REBAR_CAP, 0x0); + } + } + + dw_pcie_setup(pci); + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); + + return RT_EOK; +} + +rt_err_t dw_pcie_ep_init(struct dw_pcie_ep *ep) +{ + rt_err_t err; + struct rt_pci_ep *epc = RT_NULL; + struct dw_pcie_ep_func *ep_func; + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + struct rt_device *dev = pci->dev; + + rt_list_init(&ep->func_nodes); + + if (!pci->dbi_base || !pci->dbi_base2) + { + LOG_E("dbi_base/dbi_base2 is not populated"); + return -RT_EINVAL; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "num-ib-windows", &ep->num_ib_windows))) + { + LOG_E("Unable to read 'num-ib-windows' property"); + return err; + } + + if (ep->num_ib_windows > MAX_IATU_IN) + { + LOG_E("Invalid 'num-ib-windows'"); + return -RT_EINVAL; + } + + if ((err = rt_dm_dev_prop_read_u32(dev, "num-ob-windows", &ep->num_ob_windows))) + { + LOG_E("Unable to read 'num-ob-windows' property"); + return err; + } + + if (ep->num_ob_windows > MAX_IATU_OUT) + { + LOG_E("Invalid 'num-ob-windows'"); + return -RT_EINVAL; + } + + ep->ib_window_map = rt_calloc(RT_BITMAP_LEN(ep->num_ib_windows), sizeof(rt_bitmap_t)); + if (!ep->ib_window_map) + { + return -RT_ENOMEM; + } + + ep->ob_window_map = rt_calloc(RT_BITMAP_LEN(ep->num_ob_windows), sizeof(rt_bitmap_t)); + if (!ep->ob_window_map) + { + err = -RT_ENOMEM; + goto _fail; + } + + ep->outbound_addr = rt_calloc(ep->num_ob_windows, sizeof(rt_ubase_t)); + if (!ep->outbound_addr) + { + err = -RT_ENOMEM; + goto _fail; + } + + if (pci->link_gen < 1) + { + pci->link_gen = -1; + rt_dm_dev_prop_read_u32(dev, "max-link-speed", &pci->link_gen); + } + + epc = rt_calloc(1, sizeof(*epc)); + if (!epc) + { + err = -RT_ENOMEM; + goto _fail; + } + + epc->name = rt_dm_dev_get_name(dev); + epc->rc_dev = dev; + epc->ops = &dw_pcie_ep_ops; + epc->priv = ep; + + if ((err = rt_pci_ep_register(epc))) + { + goto _fail; + } + ep->epc = epc; + + if (rt_dm_dev_prop_read_u8(dev, "max-functions", &epc->max_functions)) + { + epc->max_functions = 1; + } + + for (rt_uint8_t func_no = 0; func_no < epc->max_functions; ++func_no) + { + ep_func = rt_calloc(1, sizeof(*ep_func)); + + if (!ep_func) + { + err = -RT_ENOMEM; + goto _fail; + } + + ep_func->func_no = func_no; + ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, PCIY_MSI); + ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, PCIY_MSIX); + + rt_list_init(&ep_func->list); + rt_list_insert_after(&ep->func_nodes, &ep_func->list); + } + + if (ep->ops->ep_init) + { + ep->ops->ep_init(ep); + } + + if ((err = rt_pci_ep_mem_init(epc, ep->aspace, ep->aspace_size, ep->page_size))) + { + goto _fail; + } + + ep->msi_mem = rt_pci_ep_mem_alloc(epc, &ep->msi_mem_phy, ep->page_size); + + if (!ep->msi_mem) + { + LOG_E("Failed to reserve memory for MSI/MSI-X"); + err = -RT_ENOMEM; + goto _fail; + } + + if ((err = dw_pcie_ep_init_complete(ep))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + dw_pcie_ep_exit(ep); + + return err; +} diff --git a/components/drivers/pci/host/dw/pcie-dw_host.c b/components/drivers/pci/host/dw/pcie-dw_host.c new file mode 100644 index 0000000000..05a3dc7779 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_host.c @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#define DBG_TAG "pcie.dw-host" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +static void dw_pcie_irq_ack(struct rt_pic_irq *pirq) +{ + int hwirq = pirq->hwirq; + rt_uint32_t res, bit, ctrl; + struct dw_pcie_port *port = pirq->pic->priv_data; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + ctrl = hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = hwirq % MAX_MSI_IRQS_PER_CTRL; + + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, RT_BIT(bit)); +} + +static void dw_pcie_irq_mask(struct rt_pic_irq *pirq) +{ + rt_ubase_t level; + int hwirq = pirq->hwirq; + rt_uint32_t res, bit, ctrl; + struct dw_pcie_port *port = pirq->pic->priv_data; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + rt_pci_msi_mask_irq(pirq); + + level = rt_spin_lock_irqsave(&port->lock); + + ctrl = hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = hwirq % MAX_MSI_IRQS_PER_CTRL; + + port->irq_mask[ctrl] |= RT_BIT(bit); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, port->irq_mask[ctrl]); + + rt_spin_unlock_irqrestore(&port->lock, level); +} + +static void dw_pcie_irq_unmask(struct rt_pic_irq *pirq) +{ + rt_ubase_t level; + int hwirq = pirq->hwirq; + rt_uint32_t res, bit, ctrl; + struct dw_pcie_port *port = pirq->pic->priv_data; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + rt_pci_msi_unmask_irq(pirq); + + level = rt_spin_lock_irqsave(&port->lock); + + ctrl = hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = hwirq % MAX_MSI_IRQS_PER_CTRL; + + port->irq_mask[ctrl] &= ~RT_BIT(bit); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, port->irq_mask[ctrl]); + + rt_spin_unlock_irqrestore(&port->lock, level); +} + +static void dw_pcie_compose_msi_msg(struct rt_pic_irq *pirq, struct rt_pci_msi_msg *msg) +{ + rt_uint64_t msi_target; + struct dw_pcie_port *port = pirq->pic->priv_data; + + msi_target = (rt_uint64_t)port->msi_data_phy; + + msg->address_lo = rt_lower_32_bits(msi_target); + msg->address_hi = rt_upper_32_bits(msi_target); + + msg->data = pirq->hwirq; +} + +static int dw_pcie_irq_alloc_msi(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc) +{ + rt_ubase_t level; + int irq, hwirq; + struct rt_pic_irq *pirq; + struct dw_pcie_port *port = pic->priv_data; + + level = rt_spin_lock_irqsave(&port->lock); + hwirq = rt_bitmap_next_clear_bit(port->msi_map, 0, port->irq_count); + + if (hwirq >= port->irq_count) + { + irq = -RT_EEMPTY; + goto _out_lock; + } + + pirq = rt_pic_find_irq(pic, hwirq); + + irq = rt_pic_config_irq(pic, hwirq, hwirq); + pirq->mode = RT_IRQ_MODE_EDGE_RISING; + + rt_bitmap_set_bit(port->msi_map, hwirq); + +_out_lock: + rt_spin_unlock_irqrestore(&port->lock, level); + + return irq; +} + +static void dw_pcie_irq_free_msi(struct rt_pic *pic, int irq) +{ + rt_ubase_t level; + struct rt_pic_irq *pirq; + struct dw_pcie_port *port = pic->priv_data; + + pirq = rt_pic_find_pirq(pic, irq); + + if (!pirq) + { + return; + } + + level = rt_spin_lock_irqsave(&port->lock); + rt_bitmap_clear_bit(port->msi_map, pirq->hwirq); + rt_spin_unlock_irqrestore(&port->lock, level); +} + +const static struct rt_pic_ops dw_pci_msi_ops = +{ + .name = "DWPCI-MSI", + .irq_ack = dw_pcie_irq_ack, + .irq_mask = dw_pcie_irq_mask, + .irq_unmask = dw_pcie_irq_unmask, + .irq_compose_msi_msg = dw_pcie_compose_msi_msg, + .irq_alloc_msi = dw_pcie_irq_alloc_msi, + .irq_free_msi = dw_pcie_irq_free_msi, + .flags = RT_PIC_F_IRQ_ROUTING, +}; + +/* MSI int handler */ +rt_err_t dw_handle_msi_irq(struct dw_pcie_port *port) +{ + rt_err_t err; + int i, pos; + rt_bitmap_t status; + rt_uint32_t num_ctrls; + struct rt_pic_irq *pirq; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct rt_pic *msi_pic = port->msi_pic; + + err = -RT_EEMPTY; + num_ctrls = RT_DIV_ROUND_UP(port->irq_count, MAX_MSI_IRQS_PER_CTRL); + + for (i = 0; i < num_ctrls; ++i) + { + status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS + + (i * MSI_REG_CTRL_BLOCK_SIZE)); + + if (!status) + { + continue; + } + + err = RT_EOK; + + rt_bitmap_for_each_set_bit(&status, pos, MAX_MSI_IRQS_PER_CTRL) + { + pirq = rt_pic_find_irq(msi_pic, pos + i * MAX_MSI_IRQS_PER_CTRL); + + dw_pcie_irq_ack(pirq); + + rt_pic_handle_isr(pirq); + } + } + + return err; +} + +static void dw_pcie_msi_isr(int irqno, void *param) +{ + struct dw_pcie_port *port = param; + + dw_handle_msi_irq(port); +} + +void dw_pcie_free_msi(struct dw_pcie_port *port) +{ + if (port->msi_irq >= 0) + { + rt_hw_interrupt_mask(port->msi_irq); + rt_pic_detach_irq(port->msi_irq, port); + } + + if (port->msi_data) + { + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + rt_dma_free_coherent(pci->dev, sizeof(rt_uint64_t), port->msi_data, + port->msi_data_phy); + } +} + +void dw_pcie_msi_init(struct dw_pcie_port *port) +{ +#ifdef RT_PCI_MSI + struct dw_pcie *pci = to_dw_pcie_from_port(port); + rt_uint64_t msi_target = (rt_uint64_t)port->msi_data_phy; + + /* Program the msi_data_phy */ + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, rt_lower_32_bits(msi_target)); + dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, rt_upper_32_bits(msi_target)); +#endif +} + +static const struct rt_pci_ops dw_child_pcie_ops; +static const struct rt_pci_ops dw_pcie_ops; + +rt_err_t dw_pcie_host_init(struct dw_pcie_port *port) +{ + rt_err_t err; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + struct rt_device *dev = pci->dev; + struct rt_pci_host_bridge *bridge; + + rt_spin_lock_init(&port->lock); + + rt_dm_dev_get_address_by_name(dev, "config", &port->cfg0_addr, &port->cfg0_size); + + if (port->cfg0_addr) + { + port->cfg0_base = rt_ioremap((void *)port->cfg0_addr, port->cfg0_size); + + if (!port->cfg0_base) + { + return -RT_EIO; + } + } + else if (!port->cfg0_base) + { + LOG_E("Missing 'config' reg space"); + } + + if (!(bridge = rt_pci_host_bridge_alloc(0))) + { + return -RT_ENOMEM; + } + + bridge->parent.ofw_node = dev->ofw_node; + + if ((err = rt_pci_host_bridge_init(bridge))) + { + goto _err_free_bridge; + } + + port->bridge = bridge; + + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + struct rt_pci_bus_region *region = &bridge->bus_regions[i]; + + switch (region->flags) + { + case PCI_BUS_REGION_F_IO: + port->io_addr = region->cpu_addr; + port->io_bus_addr = region->phy_addr; + port->io_size = region->size; + break; + + case PCI_BUS_REGION_F_NONE: + port->cfg0_size = region->size; + port->cfg0_addr = region->cpu_addr; + + if (!pci->dbi_base) + { + pci->dbi_base = rt_ioremap((void *)port->cfg0_addr, port->cfg0_size); + + if (!pci->dbi_base) + { + LOG_E("Error with ioremap"); + return -RT_ENOMEM; + } + } + break; + + default: + break; + } + } + + if (!port->cfg0_base && port->cfg0_addr) + { + port->cfg0_base = rt_ioremap((void *)port->cfg0_addr, port->cfg0_size); + + if (!port->cfg0_base) + { + return -RT_ENOMEM; + } + } + + if (rt_dm_dev_prop_read_u32(dev, "num-viewport", &pci->num_viewport)) + { + pci->num_viewport = 2; + } + + if (pci->link_gen < 1) + { + pci->link_gen = -1; + rt_dm_dev_prop_read_u32(dev, "max-link-speed", &pci->link_gen); + } + + /* + * If a specific SoC driver needs to change the default number of vectors, + * it needs to implement the set_irq_count callback. + */ + if (!port->ops->set_irq_count) + { + port->irq_count = MSI_DEF_NUM_VECTORS; + } + else + { + port->ops->set_irq_count(port); + + if (port->irq_count > MAX_MSI_IRQS || port->irq_count == 0) + { + LOG_E("Invalid count of irq = %d", port->irq_count); + + return -RT_EINVAL; + } + } + + if (!port->ops->msi_host_init) + { + port->msi_pic = rt_calloc(1, sizeof(*port->msi_pic)); + + if (!port->msi_pic) + { + return -RT_ENOMEM; + } + + port->msi_pic->priv_data = port; + port->msi_pic->ops = &dw_pci_msi_ops; + rt_pic_linear_irq(port->msi_pic, port->irq_count); + rt_pic_user_extends(port->msi_pic); + + if (port->msi_irq) + { + rt_hw_interrupt_install(port->msi_irq, dw_pcie_msi_isr, port, "dwc-pci-msi"); + rt_hw_interrupt_umask(port->msi_irq); + } + + port->msi_data = rt_dma_alloc_coherent(pci->dev, sizeof(rt_uint64_t), + &port->msi_data_phy); + + if (!port->msi_data) + { + err = -RT_ENOMEM; + goto _err_free_msi; + } + } + else + { + if ((err = port->ops->msi_host_init(port))) + { + return err; + } + } + + /* Set default bus ops */ + bridge->ops = &dw_pcie_ops; + bridge->child_ops = &dw_child_pcie_ops; + + if (port->ops->host_init && (err = port->ops->host_init(port))) + { + goto _err_free_msi; + } + + bridge->sysdata = port; + + if ((err = rt_pci_host_bridge_probe(bridge))) + { + goto _err_free_msi; + } + + return RT_EOK; + +_err_free_msi: + if (!port->ops->msi_host_init) + { + dw_pcie_free_msi(port); + + rt_pic_cancel_irq(port->msi_pic); + rt_free(port->msi_pic); + port->msi_pic = RT_NULL; + } + +_err_free_bridge: + rt_pci_host_bridge_free(bridge); + port->bridge = RT_NULL; + + return err; +} + +void dw_pcie_host_deinit(struct dw_pcie_port *port) +{ + if (!port->ops->msi_host_init) + { + dw_pcie_free_msi(port); + } +} + +void dw_pcie_host_free(struct dw_pcie_port *port) +{ + if (!port->ops->msi_host_init) + { + dw_pcie_free_msi(port); + + rt_pic_cancel_irq(port->msi_pic); + rt_free(port->msi_pic); + } + + if (port->bridge) + { + rt_pci_host_bridge_free(port->bridge); + } +} + +static void *dw_pcie_other_conf_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg) +{ + int type; + rt_uint32_t busdev; + struct dw_pcie_port *port = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + /* + * Checking whether the link is up here is a last line of defense + * against platforms that forward errors on the system bus as + * SError upon PCI configuration transactions issued when the link is down. + * This check is racy by definition and does not stop the system from + * triggering an SError if the link goes down after this check is performed. + */ + if (!dw_pcie_link_up(pci)) + { + return RT_NULL; + } + + busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(RT_PCI_SLOT(devfn)) | + PCIE_ATU_FUNC(RT_PCI_FUNC(devfn)); + + if (rt_pci_is_root_bus(bus->parent)) + { + type = PCIE_ATU_TYPE_CFG0; + } + else + { + type = PCIE_ATU_TYPE_CFG1; + } + + dw_pcie_prog_outbound_atu(pci, 0, type, port->cfg0_addr, busdev, port->cfg0_size); + + return port->cfg0_base + reg; +} + +static rt_err_t dw_pcie_other_read_conf(struct rt_pci_bus *bus, + rt_uint32_t devfn, int reg, int width, rt_uint32_t *value) +{ + rt_err_t err; + struct dw_pcie_port *port = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + err = rt_pci_bus_read_config_uxx(bus, devfn, reg, width, value); + + if (!err && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED)) + { + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, + port->io_addr, port->io_bus_addr, port->io_size); + } + + return err; +} + +static rt_err_t dw_pcie_other_write_conf(struct rt_pci_bus *bus, + rt_uint32_t devfn, int reg, int width, rt_uint32_t value) +{ + rt_err_t err; + struct dw_pcie_port *port = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + err = rt_pci_bus_write_config_uxx(bus, devfn, reg, width, value); + + if (!err && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED)) + { + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, + port->io_addr, port->io_bus_addr, port->io_size); + } + + return err; +} + +static const struct rt_pci_ops dw_child_pcie_ops = +{ + .map = dw_pcie_other_conf_map, + .read = dw_pcie_other_read_conf, + .write = dw_pcie_other_write_conf, +}; + +void *dw_pcie_own_conf_map(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg) +{ + struct dw_pcie_port *port = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + if (RT_PCI_SLOT(devfn) > 0) + { + return RT_NULL; + } + + return pci->dbi_base + reg; +} + +static const struct rt_pci_ops dw_pcie_ops = +{ + .map = dw_pcie_own_conf_map, + .read = rt_pci_bus_read_config_uxx, + .write = rt_pci_bus_write_config_uxx, +}; + +void dw_pcie_setup_rc(struct dw_pcie_port *port) +{ + rt_uint32_t val, num_ctrls; + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + /* + * Enable DBI read-only registers for writing/updating configuration. + * Write permission gets disabled towards the end of this function. + */ + dw_pcie_dbi_ro_writable_enable(pci, RT_TRUE); + + dw_pcie_setup(pci); + + if (!port->ops->msi_host_init) + { + num_ctrls = RT_DIV_ROUND_UP(port->irq_count, MAX_MSI_IRQS_PER_CTRL); + + /* Initialize IRQ Status array */ + for (int ctrl = 0; ctrl < num_ctrls; ++ctrl) + { + port->irq_mask[ctrl] = ~0; + + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), port->irq_mask[ctrl]); + dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), ~0); + } + } + + /* Setup RC BARs */ + dw_pcie_writel_dbi(pci, PCIR_BAR(0), PCIM_BAR_MEM_TYPE_64); + dw_pcie_writel_dbi(pci, PCIR_BAR(1), PCIM_BAR_MEM_TYPE_32); + + /* Setup interrupt pins */ + val = dw_pcie_readl_dbi(pci, PCIR_INTLINE); + val &= 0xffff00ff; + val |= 0x00000100; + dw_pcie_writel_dbi(pci, PCIR_INTLINE, val); + + /* Setup bus numbers */ + val = dw_pcie_readl_dbi(pci, PCIR_PRIBUS_1); + val &= 0xff000000; + val |= 0x00ff0100; + dw_pcie_writel_dbi(pci, PCIR_PRIBUS_1, val); + + /* Setup command register */ + val = dw_pcie_readl_dbi(pci, PCIR_COMMAND); + val &= 0xffff0000; + val |= PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN; + dw_pcie_writel_dbi(pci, PCIR_COMMAND, val); + + /* + * If the platform provides its own child bus config accesses, it means + * the platform uses its own address translation component rather than + * ATU, so we should not program the ATU here. + */ + if (pci->port.bridge->child_ops == &dw_child_pcie_ops) + { + int atu_idx = 0; + struct rt_pci_host_bridge *bridge = port->bridge; + + /* Get last memory resource entry */ + for (int i = 0; i < bridge->bus_regions_nr; ++i) + { + struct rt_pci_bus_region *region = &bridge->bus_regions[i]; + + if (region->flags != PCI_BUS_REGION_F_MEM) + { + continue; + } + + if (pci->num_viewport <= ++atu_idx) + { + break; + } + + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_MEM, region->cpu_addr, + region->phy_addr, region->size); + } + + if (port->io_size) + { + if (pci->num_viewport > ++atu_idx) + { + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_IO, port->io_addr, + port->io_bus_addr, port->io_size); + } + else + { + pci->iatu_unroll_enabled |= DWC_IATU_IOCFG_SHARED; + } + } + + if (pci->num_viewport <= atu_idx) + { + LOG_W("Resources exceed number of ATU entries (%d)", pci->num_viewport); + } + } + + dw_pcie_writel_dbi(pci, PCIR_BAR(0), 0); + + /* Program correct class for RC */ + dw_pcie_writew_dbi(pci, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); + + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val |= PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); + + dw_pcie_dbi_ro_writable_enable(pci, RT_FALSE); +} diff --git a/components/drivers/pci/host/dw/pcie-dw_platfrom.c b/components/drivers/pci/host/dw/pcie-dw_platfrom.c new file mode 100644 index 0000000000..878ac41658 --- /dev/null +++ b/components/drivers/pci/host/dw/pcie-dw_platfrom.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "pcie.dw.platfrom" +#define DBG_LVL DBG_INFO +#include + +#include "pcie-dw.h" + +struct dw_dw_platform_pcie_soc_data +{ + enum dw_pcie_device_mode mode; +}; + +struct dw_platform_pcie +{ + struct dw_pcie *pci; + struct rt_syscon *regmap; + const struct dw_dw_platform_pcie_soc_data *soc_data; +}; + +static rt_err_t dw_platform_pcie_host_init(struct dw_pcie_port *port) +{ + struct dw_pcie *pci = to_dw_pcie_from_port(port); + + dw_pcie_setup_rc(port); + dw_pcie_wait_for_link(pci); + dw_pcie_msi_init(port); + + return RT_EOK; +} + +static void dw_platform_set_irq_count(struct dw_pcie_port *pp) +{ + pp->irq_count = MAX_MSI_IRQS; +} + +static const struct dw_pcie_host_ops dw_platform_pcie_host_ops = +{ + .host_init = dw_platform_pcie_host_init, + .set_irq_count = dw_platform_set_irq_count, +}; + +static rt_err_t dw_platform_pcie_establish_link(struct dw_pcie *pci) +{ + return RT_EOK; +} + +static const struct dw_pcie_ops dw_platform_pcie_ops = +{ + .start_link = dw_platform_pcie_establish_link, +}; + +static rt_err_t dw_platform_pcie_ep_init(struct dw_pcie_ep *ep) +{ + struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep); + + for (int bar = 0; bar < PCI_STD_NUM_BARS; ++bar) + { + dw_pcie_ep_reset_bar(pci, bar); + } + + return RT_EOK; +} + +static rt_err_t dw_platform_pcie_ep_raise_irq(struct dw_pcie_ep *ep, + rt_uint8_t func_no, enum rt_pci_ep_irq type, unsigned irq) +{ + switch (type) + { + case RT_PCI_EP_IRQ_LEGACY: + return dw_pcie_ep_raise_legacy_irq(ep, func_no); + + case RT_PCI_EP_IRQ_MSI: + return dw_pcie_ep_raise_msi_irq(ep, func_no, irq); + + case RT_PCI_EP_IRQ_MSIX: + return dw_pcie_ep_raise_msix_irq(ep, func_no, irq); + + default: + LOG_E("Unknown IRQ type = %d", type); + } + + return RT_EOK; +} + +static const struct dw_pcie_ep_ops dw_platform_pcie_ep_ops = +{ + .ep_init = dw_platform_pcie_ep_init, + .raise_irq = dw_platform_pcie_ep_raise_irq, +}; + +static rt_err_t dw_platform_add_pcie_port(struct dw_platform_pcie *plat_pcie, + struct rt_device *dev) +{ + rt_err_t err; + struct dw_pcie *pci = plat_pcie->pci; + struct dw_pcie_port *port = &pci->port; + + port->sys_irq = rt_dm_dev_get_irq(dev, 1); + + if (port->sys_irq < 0) + { + return port->sys_irq; + } + +#ifdef RT_PCI_MSI + port->msi_irq = rt_dm_dev_get_irq(dev, 0); + + if (port->msi_irq < 0) + { + return port->msi_irq; + } +#endif + + port->ops = &dw_platform_pcie_host_ops; + + if ((err = dw_pcie_host_init(port))) + { + LOG_E("Failed to initialize host"); + return err; + } + + return RT_EOK; +} + +static rt_err_t dw_platform_add_pcie_ep(struct dw_platform_pcie *plat_pcie, + struct rt_device *dev) +{ + rt_err_t err; + struct dw_pcie *pci = plat_pcie->pci; + struct dw_pcie_ep *ep = &pci->endpoint; + + pci->dbi_base2 = rt_dm_dev_iomap_by_name(dev, "dbi2"); + + if (!pci->dbi_base2) + { + return -RT_EIO; + } + + err = rt_dm_dev_get_address_by_name(dev, "addr_space", &ep->aspace, &ep->aspace_size); + + if (err) + { + rt_iounmap(pci->dbi_base2); + return err; + } + + ep->ops = &dw_platform_pcie_ep_ops; + + if ((err = dw_pcie_ep_init(ep))) + { + LOG_E("Failed to initialize endpoint"); + return err; + } + + return RT_EOK; +} + +static rt_err_t dw_platform_pcie_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct dw_pcie *pci = RT_NULL; + struct dw_platform_pcie *plat_pcie; + struct rt_device *dev = &pdev->parent; + + if (!(plat_pcie = rt_calloc(1, sizeof(*plat_pcie)))) + { + return -RT_ENOMEM; + } + + if (!(pci = rt_calloc(1, sizeof(*pci)))) + { + err = -RT_ENOMEM; + goto _fail; + } + + plat_pcie->pci = pci; + plat_pcie->soc_data = pdev->id->data; + + pci->dev = dev; + pci->ops = &dw_platform_pcie_ops; + pci->dbi_base = rt_dm_dev_iomap_by_name(dev, "dbi"); + + if (!pci->dbi_base) + { + err = -RT_EIO; + goto _fail; + } + + dev->user_data = plat_pcie; + + switch (plat_pcie->soc_data->mode) + { + case DW_PCIE_RC_TYPE: + if (!RT_KEY_ENABLED(RT_PCI_DW_HOST)) + { + err = -RT_ENOSYS; + goto _fail; + } + + if ((err = dw_platform_add_pcie_port(plat_pcie, dev))) + { + goto _fail; + } + break; + + case DW_PCIE_EP_TYPE: + if (!RT_KEY_ENABLED(RT_PCI_DW_EP)) + { + err = -RT_ENOSYS; + goto _fail; + } + + if ((err = dw_platform_add_pcie_ep(plat_pcie, dev))) + { + goto _fail; + } + break; + + default: + LOG_E("Invalid device type %d", plat_pcie->soc_data->mode); + err = -RT_EINVAL; + goto _fail; + } + + return RT_EOK; + +_fail: + if (pci) + { + if (pci->dbi_base) + { + rt_iounmap(pci->dbi_base); + } + + rt_free(pci); + } + + rt_free(plat_pcie); + + return err; +} + +static rt_err_t dw_platform_pcie_remove(struct rt_platform_device *pdev) +{ + struct dw_platform_pcie *plat_pcie = pdev->parent.user_data; + + rt_pci_host_bridge_remove(plat_pcie->pci->port.bridge); + dw_pcie_host_free(&plat_pcie->pci->port); + + rt_iounmap(plat_pcie->pci->dbi_base); + rt_free(plat_pcie->pci); + + rt_free(plat_pcie); + + return RT_EOK; +} + +static const struct dw_dw_platform_pcie_soc_data dw_platform_pcie_rc_soc_data = +{ + .mode = DW_PCIE_RC_TYPE, +}; + +static const struct dw_dw_platform_pcie_soc_data dw_platform_pcie_ep_soc_data = +{ + .mode = DW_PCIE_EP_TYPE, +}; + +static const struct rt_ofw_node_id dw_platform_pcie_ofw_ids[] = +{ + { .compatible = "snps,dw-pcie", .data = &dw_platform_pcie_rc_soc_data }, + { .compatible = "snps,dw-pcie-ep", .data = &dw_platform_pcie_ep_soc_data }, + { /* sentinel */ } +}; + +static struct rt_platform_driver dw_platform_pcie_driver = +{ + .name = "dw-pcie", + .ids = dw_platform_pcie_ofw_ids, + + .probe = dw_platform_pcie_probe, + .remove = dw_platform_pcie_remove, +}; +RT_PLATFORM_DRIVER_EXPORT(dw_platform_pcie_driver); diff --git a/components/drivers/phy/ofw.c b/components/drivers/phy/ofw.c index 77429ec4c4..316bbc2fde 100644 --- a/components/drivers/phy/ofw.c +++ b/components/drivers/phy/ofw.c @@ -116,7 +116,7 @@ rt_err_t rt_ofw_get_phyid(struct rt_ofw_node *np,rt_uint32_t *id) if (ret) return ret; - ret = sscanf(phy_id,"ethernet-phy-id%4x.%4x",&upper, &lower); + ret = rt_sscanf(phy_id,"ethernet-phy-id%4x.%4x",&upper, &lower); if(ret != 2) return -RT_ERROR; diff --git a/components/drivers/regulator/Kconfig b/components/drivers/regulator/Kconfig new file mode 100644 index 0000000000..99bfdac1e8 --- /dev/null +++ b/components/drivers/regulator/Kconfig @@ -0,0 +1,23 @@ +menuconfig RT_USING_REGULATOR + bool "Using Voltage and Current Regulator" + select RT_USING_ADT + select RT_USING_ADT_REF + depends on RT_USING_DM + default n + +config RT_REGULATOR_FIXED + bool "Fixed regulator support" + depends on RT_USING_REGULATOR + depends on RT_USING_PIN + depends on RT_USING_PINCTRL + default y + +config RT_REGULATOR_GPIO + bool "GPIO regulator support" + depends on RT_USING_REGULATOR + depends on RT_USING_PIN + default y + +if RT_USING_REGULATOR + osource "$(SOC_DM_REGULATOR_DIR)/Kconfig" +endif diff --git a/components/drivers/regulator/SConscript b/components/drivers/regulator/SConscript new file mode 100755 index 0000000000..29b567fad9 --- /dev/null +++ b/components/drivers/regulator/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_REGULATOR']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['regulator.c', 'regulator_dm.c'] + +if GetDepend(['RT_REGULATOR_FIXED']): + src += ['regulator-fixed.c'] + +if GetDepend(['RT_REGULATOR_GPIO']): + src += ['regulator-gpio.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/regulator/regulator-fixed.c b/components/drivers/regulator/regulator-fixed.c new file mode 100644 index 0000000000..5f5773b896 --- /dev/null +++ b/components/drivers/regulator/regulator-fixed.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "regulator_dm.h" + +struct regulator_fixed +{ + struct rt_regulator_node parent; + struct rt_regulator_param param; + + rt_base_t enable_pin; + const char *input_supply; +}; + +#define raw_to_regulator_fixed(raw) rt_container_of(raw, struct regulator_fixed, parent) + +static rt_err_t regulator_fixed_enable(struct rt_regulator_node *reg_np) +{ + struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np); + struct rt_regulator_param *param = &rf->param; + + if (rf->enable_pin < 0 || param->always_on) + { + return RT_EOK; + } + + rt_pin_mode(rf->enable_pin, PIN_MODE_OUTPUT); + rt_pin_write(rf->enable_pin, param->enable_active_high ? PIN_HIGH : PIN_LOW); + + return RT_EOK; +} + +static rt_err_t regulator_fixed_disable(struct rt_regulator_node *reg_np) +{ + struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np); + struct rt_regulator_param *param = &rf->param; + + if (rf->enable_pin < 0 || param->always_on) + { + return RT_EOK; + } + + rt_pin_mode(rf->enable_pin, PIN_MODE_OUTPUT); + rt_pin_write(rf->enable_pin, param->enable_active_high ? PIN_LOW: PIN_HIGH); + + return RT_EOK; +} + +static rt_bool_t regulator_fixed_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_uint8_t active; + struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np); + struct rt_regulator_param *param = &rf->param; + + if (rf->enable_pin < 0 || param->always_on) + { + return RT_TRUE; + } + + rt_pin_mode(rf->enable_pin, PIN_MODE_INPUT); + active = rt_pin_read(rf->enable_pin); + + if (param->enable_active_high) + { + return active == PIN_HIGH; + } + + return active == PIN_LOW; +} + +static int regulator_fixed_get_voltage(struct rt_regulator_node *reg_np) +{ + struct regulator_fixed *rf = raw_to_regulator_fixed(reg_np); + + return rf->param.min_uvolt + (rf->param.max_uvolt - rf->param.min_uvolt) / 2; +} + +static const struct rt_regulator_ops regulator_fixed_ops = +{ + .enable = regulator_fixed_enable, + .disable = regulator_fixed_disable, + .is_enabled = regulator_fixed_is_enabled, + .get_voltage = regulator_fixed_get_voltage, +}; + +static rt_err_t regulator_fixed_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + rt_uint32_t val; + struct rt_device *dev = &pdev->parent; + struct regulator_fixed *rf = rt_calloc(1, sizeof(*rf)); + struct rt_regulator_node *rnp; + + if (!rf) + { + return -RT_ENOMEM; + } + + regulator_ofw_parse(dev->ofw_node, &rf->param); + + rnp = &rf->parent; + rnp->supply_name = rf->param.name; + rnp->ops = ®ulator_fixed_ops; + rnp->param = &rf->param; + rnp->dev = &pdev->parent; + + rf->enable_pin = rt_pin_get_named_pin(dev, "enable", 0, RT_NULL, RT_NULL); + + if (rf->enable_pin < 0) + { + rf->enable_pin = rt_pin_get_named_pin(dev, RT_NULL, 0, RT_NULL, RT_NULL); + } + + if (rf->enable_pin < 0) + { + rf->enable_pin = -1; + } + + rt_pin_ctrl_confs_apply(dev, 0); + + if (!rt_dm_dev_prop_read_u32(dev, "startup-delay-us", &val)) + { + rf->param.enable_delay = val; + } + + if (!rt_dm_dev_prop_read_u32(dev, "off-on-delay-us", &val)) + { + rf->param.off_on_delay = val; + } + + if ((err = rt_regulator_register(rnp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + rt_free(rf); + + return err; +} + +static const struct rt_ofw_node_id regulator_fixed_ofw_ids[] = +{ + { .compatible = "regulator-fixed" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver regulator_fixed_driver = +{ + .name = "reg-fixed-voltage", + .ids = regulator_fixed_ofw_ids, + + .probe = regulator_fixed_probe, +}; + +static int regulator_fixed_register(void) +{ + rt_platform_driver_register(®ulator_fixed_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(regulator_fixed_register); diff --git a/components/drivers/regulator/regulator-gpio.c b/components/drivers/regulator/regulator-gpio.c new file mode 100644 index 0000000000..069831835f --- /dev/null +++ b/components/drivers/regulator/regulator-gpio.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include + +#include "regulator_dm.h" + +struct regulator_gpio_state +{ + rt_uint32_t value; + rt_uint32_t gpios; +}; + +struct regulator_gpio_desc +{ + rt_base_t pin; + rt_uint32_t flags; +}; + +struct regulator_gpio +{ + struct rt_regulator_node parent; + + rt_base_t enable_pin; + + rt_size_t pins_nr; + struct regulator_gpio_desc *pins_desc; + + int state; + rt_size_t states_nr; + struct regulator_gpio_state *states; + + const char *input_supply; + rt_uint32_t startup_delay; + rt_uint32_t off_on_delay; + rt_bool_t enabled_at_boot; + struct rt_regulator_param param; +}; + +#define raw_to_regulator_gpio(raw) rt_container_of(raw, struct regulator_gpio, parent) + +static rt_err_t regulator_gpio_enable(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (param->always_on) + { + return RT_EOK; + } + + if (rg->enable_pin >= 0) + { + rt_pin_mode(rg->enable_pin, PIN_MODE_OUTPUT); + rt_pin_write(rg->enable_pin, param->enable_active_high ? PIN_HIGH : PIN_LOW); + } + + return RT_EOK; +} + +static rt_err_t regulator_gpio_disable(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (param->always_on) + { + return RT_EOK; + } + + if (rg->enable_pin >= 0) + { + rt_pin_mode(rg->enable_pin, PIN_MODE_OUTPUT); + rt_pin_write(rg->enable_pin, param->enable_active_high ? PIN_LOW : PIN_HIGH); + } + + return RT_EOK; +} + +static rt_bool_t regulator_gpio_is_enabled(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + struct rt_regulator_param *param = &rg->param; + + if (param->always_on) + { + return RT_TRUE; + } + + if (rg->enable_pin >= 0) + { + rt_uint8_t active_val = param->enable_active_high ? PIN_LOW : PIN_HIGH; + + rt_pin_mode(rg->enable_pin, PIN_MODE_INPUT); + return rt_pin_read(rg->enable_pin) == active_val; + } + + return RT_TRUE; +} + +static rt_err_t regulator_gpio_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int target = 0, best_val = RT_REGULATOR_UVOLT_INVALID; + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + + for (int i = 0; i < rg->states_nr; ++i) + { + struct regulator_gpio_state *state = &rg->states[i]; + + if (state->value < best_val && + state->value >= min_uvolt && + state->value <= max_uvolt) + { + target = state->gpios; + best_val = state->value; + } + } + + if (best_val == RT_REGULATOR_UVOLT_INVALID) + { + return -RT_EINVAL; + } + + for (int i = 0; i < rg->pins_nr; ++i) + { + int state = (target >> i) & 1; + struct regulator_gpio_desc *gpiod = &rg->pins_desc[i]; + + rt_pin_mode(gpiod->pin, PIN_MODE_OUTPUT); + rt_pin_write(gpiod->pin, gpiod->flags == PIND_OUT_HIGH ? state : !state); + } + + rg->state = target; + + return RT_EOK; +} + +static int regulator_gpio_get_voltage(struct rt_regulator_node *reg_np) +{ + struct regulator_gpio *rg = raw_to_regulator_gpio(reg_np); + + for (int i = 0; i < rg->states_nr; ++i) + { + if (rg->states[i].gpios == rg->state) + { + return rg->states[i].value; + } + } + + return -RT_EINVAL; +} + +static const struct rt_regulator_ops regulator_gpio_ops = +{ + .enable = regulator_gpio_enable, + .disable = regulator_gpio_disable, + .is_enabled = regulator_gpio_is_enabled, + .set_voltage = regulator_gpio_set_voltage, + .get_voltage = regulator_gpio_get_voltage, +}; + +static rt_err_t regulator_gpio_probe(struct rt_platform_device *pdev) +{ + rt_err_t err; + struct rt_device *dev = &pdev->parent; + struct regulator_gpio *rg = rt_calloc(1, sizeof(*rg)); + struct rt_regulator_node *rgp; + + if (!rg) + { + return -RT_ENOMEM; + } + + regulator_ofw_parse(dev->ofw_node, &rg->param); + + rgp = &rg->parent; + rgp->supply_name = rg->param.name; + rgp->ops = ®ulator_gpio_ops; + rgp->param = &rg->param; + rgp->dev = &pdev->parent; + + rt_dm_dev_prop_read_u32(dev, "startup-delay-us", &rg->startup_delay); + rt_dm_dev_prop_read_u32(dev, "off-on-delay-us", &rg->off_on_delay); + + /* GPIO flags are ignored, we check by enable-active-high */ + rg->enable_pin = rt_pin_get_named_pin(dev, "enable", 0, RT_NULL, RT_NULL); + + if (rg->enable_pin < 0 && rg->enable_pin != -RT_EEMPTY) + { + err = rg->enable_pin; + goto _fail; + } + + rg->pins_nr = rt_pin_get_named_pin_count(dev, "gpios"); + + if (rg->pins_nr > 0) + { + rg->pins_desc = rt_malloc(sizeof(*rg->pins_desc) * rg->pins_nr); + + if (!rg->pins_desc) + { + err = -RT_ENOMEM; + + goto _fail; + } + + for (int i = 0; i < rg->pins_nr; ++i) + { + rt_uint32_t val; + struct regulator_gpio_desc *gpiod = &rg->pins_desc[i]; + + gpiod->pin = rt_pin_get_named_pin(dev, RT_NULL, i, RT_NULL, RT_NULL); + + if (gpiod->pin < 0) + { + err = gpiod->pin; + goto _fail; + } + + if (rt_dm_dev_prop_read_u32_index(dev, "gpios-states", i, &val) < 0) + { + gpiod->flags = PIND_OUT_HIGH; + } + else + { + gpiod->flags = val ? PIND_OUT_HIGH : PIND_OUT_LOW; + } + + if (gpiod->flags == PIND_OUT_HIGH) + { + rg->state |= 1 << i; + } + } + } + + rg->states_nr = rt_dm_dev_prop_count_of_u32(dev, "states") / 2; + + if (rg->states_nr < 0) + { + err = -RT_EIO; + + goto _fail; + } + + rg->states = rt_malloc(sizeof(*rg->states) * rg->states_nr); + + if (!rg->states) + { + err = -RT_ENOMEM; + + goto _fail; + } + + for (int i = 0; i < rg->states_nr; ++i) + { + rt_dm_dev_prop_read_u32_index(dev, "states", i * 2, &rg->states[i].value); + rt_dm_dev_prop_read_u32_index(dev, "states", i * 2 + 1, &rg->states[i].gpios); + } + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + return RT_EOK; + +_fail: + if (rg->pins_desc) + { + rt_free(rg->pins_desc); + } + if (rg->states) + { + rt_free(rg->states); + } + rt_free(rg); + + return err; +} + +static const struct rt_ofw_node_id regulator_gpio_ofw_ids[] = +{ + { .compatible = "regulator-gpio" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver regulator_gpio_driver = +{ + .name = "regulator-gpio", + .ids = regulator_gpio_ofw_ids, + + .probe = regulator_gpio_probe, +}; + +static int regulator_gpio_register(void) +{ + rt_platform_driver_register(®ulator_gpio_driver); + + return 0; +} +INIT_SUBSYS_EXPORT(regulator_gpio_register); diff --git a/components/drivers/regulator/regulator.c b/components/drivers/regulator/regulator.c new file mode 100644 index 0000000000..29071e9dc0 --- /dev/null +++ b/components/drivers/regulator/regulator.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include +#include + +#define DBG_TAG "rtdm.regulator" +#define DBG_LVL DBG_INFO +#include + +#include +#include +#include + +struct rt_regulator +{ + struct rt_regulator_node *reg_np; +}; + +static struct rt_spinlock _regulator_lock = { 0 }; + +static rt_err_t regulator_enable(struct rt_regulator_node *reg_np); +static rt_err_t regulator_disable(struct rt_regulator_node *reg_np); + +rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np) +{ + const struct rt_regulator_param *param; + + if (!reg_np || !reg_np->dev || !reg_np->param || !reg_np->ops) + { + return -RT_EINVAL; + } + + rt_list_init(®_np->list); + rt_list_init(®_np->children_nodes); + rt_list_init(®_np->notifier_nodes); + rt_ref_init(®_np->ref); + rt_atomic_store(®_np->enabled_count, 0); + + param = reg_np->param; + + reg_np->parent = RT_NULL; + +#ifdef RT_USING_OFW + if (reg_np->dev->ofw_node) + { + rt_ofw_data(reg_np->dev->ofw_node) = reg_np; + } +#endif /* RT_USING_OFW */ + + if (param->boot_on || param->always_on) + { + regulator_enable(reg_np); + } + + return RT_EOK; +} + +rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + + if (!reg_np) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + if (rt_atomic_load(®_np->enabled_count) != 0) + { + err = -RT_EBUSY; + + LOG_E("%s was enabled by consumer", reg_np->supply_name); + + goto _unlock; + } + + if (!(reg_np->param->boot_on || reg_np->param->always_on)) + { + regulator_disable(reg_np); + } + + if (!rt_list_isempty(®_np->children_nodes) || rt_ref_read(®_np->ref) > 1) + { + err = -RT_EBUSY; + + goto _unlock; + } + + reg_np->parent = RT_NULL; + rt_list_remove(®_np->list); + +_unlock: + rt_hw_spin_unlock(&_regulator_lock.lock); + + return err; +} + +rt_err_t rt_regulator_notifier_register(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier) +{ + struct rt_regulator_node *reg_np; + + if (!reg || !notifier) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + reg_np = reg->reg_np; + notifier->regulator = reg; + + rt_list_init(¬ifier->list); + rt_list_insert_after(®_np->notifier_nodes, ¬ifier->list); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return RT_EOK; +} + +rt_err_t rt_regulator_notifier_unregister(struct rt_regulator *reg, + struct rt_regulator_notifier *notifier) +{ + if (!reg || !notifier) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + rt_list_remove(¬ifier->list); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return RT_EOK; +} + +static rt_err_t regulator_notifier_call_chain(struct rt_regulator_node *reg_np, + rt_ubase_t msg, void *data) +{ + rt_err_t err = RT_EOK; + struct rt_regulator_notifier *notifier; + rt_list_t *head = ®_np->notifier_nodes; + + if (rt_list_isempty(head)) + { + return err; + } + + rt_list_for_each_entry(notifier, head, list) + { + err = notifier->callback(notifier, msg, data); + + if (err == -RT_EIO) + { + break; + } + } + + return err; +} + +static rt_uint32_t regulator_get_enable_time(struct rt_regulator_node *reg_np) +{ + if (reg_np->param->enable_delay) + { + return reg_np->param->enable_delay; + } + + if (reg_np->ops->enable_time) + { + return reg_np->ops->enable_time(reg_np); + } + + return 0; +} + +static void regulator_delay(rt_uint32_t delay) +{ + rt_uint32_t ms = delay / 1000; + rt_uint32_t us = delay % 1000; + + if (ms > 0) + { + /* + * For small enough values, handle super-millisecond + * delays in the usleep_range() call below. + */ + if (ms < 20) + { + us += ms * 1000; + } + else if (rt_thread_self()) + { + rt_thread_mdelay(ms); + } + else + { + rt_hw_us_delay(ms * 1000); + } + } + + /* + * Give the scheduler some room to coalesce with any other + * wakeup sources. For delays shorter than 10 us, don't even + * bother setting up high-resolution timers and just busy-loop. + */ + if (us >= 10) + { + rt_hw_us_delay((us + 100) >> 1); + } + else + { + rt_hw_us_delay(us); + } +} + +static rt_err_t regulator_enable(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + rt_uint32_t enable_delay = regulator_get_enable_time(reg_np); + + if (reg_np->ops->enable) + { + err = reg_np->ops->enable(reg_np); + + if (!err) + { + if (enable_delay) + { + regulator_delay(enable_delay); + } + + rt_atomic_add(®_np->enabled_count, 1); + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_ENABLE, RT_NULL); + } + } + + if (!err && reg_np->parent) + { + err = regulator_enable(reg_np->parent); + } + + return err; +} + +rt_err_t rt_regulator_enable(struct rt_regulator *reg) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + if (rt_regulator_is_enabled(reg)) + { + return RT_EOK; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + err = regulator_enable(reg->reg_np); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return err; +} + +static rt_err_t regulator_disable(struct rt_regulator_node *reg_np) +{ + rt_err_t err = RT_EOK; + + if (reg_np->ops->disable) + { + err = reg_np->ops->disable(reg_np); + + if (!err) + { + if (reg_np->param->off_on_delay) + { + regulator_delay(reg_np->param->off_on_delay); + } + + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_DISABLE, RT_NULL); + } + } + + if (!err && reg_np->parent) + { + err = regulator_disable(reg_np->parent); + } + + return err; +} + +rt_err_t rt_regulator_disable(struct rt_regulator *reg) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + if (!rt_regulator_is_enabled(reg)) + { + return RT_EOK; + } + + if (rt_atomic_load(®->reg_np->enabled_count) != 0) + { + rt_atomic_sub(®->reg_np->enabled_count, 1); + + return RT_EOK; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + err = regulator_disable(reg->reg_np); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return err; +} + +rt_bool_t rt_regulator_is_enabled(struct rt_regulator *reg) +{ + if (!reg) + { + return -RT_EINVAL; + } + + if (reg->reg_np->ops->is_enabled) + { + return reg->reg_np->ops->is_enabled(reg->reg_np); + } + + return rt_atomic_load(®->reg_np->enabled_count) > 0; +} + +static rt_err_t regulator_set_voltage(struct rt_regulator_node *reg_np, int min_uvolt, int max_uvolt) +{ + rt_err_t err = RT_EOK; + + if (reg_np->ops->set_voltage) + { + union rt_regulator_notifier_args args; + + RT_ASSERT(reg_np->ops->get_voltage != RT_NULL); + + args.old_uvolt = reg_np->ops->get_voltage(reg_np); + args.min_uvolt = min_uvolt; + args.max_uvolt = max_uvolt; + + err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_VOLTAGE_CHANGE, &args); + + if (!err) + { + err = reg_np->ops->set_voltage(reg_np, min_uvolt, max_uvolt); + } + + if (err) + { + regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR, + (void *)(rt_base_t)args.old_uvolt); + } + } + + if (!err && reg_np->parent) + { + err = regulator_set_voltage(reg_np->parent, min_uvolt, max_uvolt); + } + + return err; +} + +rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt) +{ + const struct rt_regulator_param *param; + + RT_ASSERT(reg != RT_NULL); + + param = reg->reg_np->param; + + if (!param) + { + return RT_FALSE; + } + + return param->min_uvolt <= min_uvolt && param->max_uvolt >= max_uvolt; +} + +rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt) +{ + rt_err_t err; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + err = regulator_set_voltage(reg->reg_np, min_uvolt, max_uvolt); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return err; +} + +int rt_regulator_get_voltage(struct rt_regulator *reg) +{ + int uvolt = RT_REGULATOR_UVOLT_INVALID; + struct rt_regulator_node *reg_np; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + reg_np = reg->reg_np; + + if (reg_np->ops->get_voltage) + { + uvolt = reg_np->ops->get_voltage(reg->reg_np); + } + else + { + uvolt = -RT_ENOSYS; + } + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return uvolt; +} + +rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode) +{ + rt_err_t err; + struct rt_regulator_node *reg_np; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + reg_np = reg->reg_np; + + if (reg_np->ops->set_mode) + { + err = reg_np->ops->set_mode(reg_np, mode); + } + else + { + err = -RT_ENOSYS; + } + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return err; +} + +rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg) +{ + rt_int32_t mode; + struct rt_regulator_node *reg_np; + + if (!reg) + { + return -RT_EINVAL; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + reg_np = reg->reg_np; + + if (reg_np->ops->get_mode) + { + mode = reg_np->ops->get_mode(reg_np); + } + else + { + mode = -RT_ENOSYS; + } + + rt_hw_spin_unlock(&_regulator_lock.lock); + + return mode; +} + +static void regulator_check_parent(struct rt_regulator_node *reg_np) +{ + if (reg_np->parent) + { + return; + } + else + { + #ifdef RT_USING_OFW + rt_phandle parent_phandle = 0; + struct rt_ofw_node *np = reg_np->dev->ofw_node; + + while (np) + { + if (rt_ofw_prop_read_u32(np, "vin-supply", &parent_phandle)) + { + break; + } + + if (!(np = rt_ofw_find_node_by_phandle(parent_phandle))) + { + break; + } + + if (!(reg_np->parent = rt_ofw_data(np))) + { + LOG_W("%s parent ofw node = %s not init", + reg_np->supply_name, rt_ofw_node_full_name(np)); + + rt_ofw_node_put(np); + break; + } + + rt_list_insert_after(®_np->parent->children_nodes, ®_np->list); + rt_ofw_node_put(np); + } + #endif + } +} + +struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id) +{ + struct rt_regulator *reg = RT_NULL; + struct rt_regulator_node *reg_np = RT_NULL; + + if (!dev || !id) + { + reg = rt_err_ptr(-RT_EINVAL); + goto _end; + } + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + rt_phandle supply_phandle; + struct rt_ofw_node *np = dev->ofw_node; + char supply_name[64]; + + rt_snprintf(supply_name, sizeof(supply_name), "%s-supply", id); + + if (rt_ofw_prop_read_u32(np, supply_name, &supply_phandle)) + { + goto _end; + } + + if (!(np = rt_ofw_find_node_by_phandle(supply_phandle))) + { + reg = rt_err_ptr(-RT_EIO); + goto _end; + } + + if (!rt_ofw_data(np)) + { + rt_platform_ofw_request(np); + } + + reg_np = rt_ofw_data(np); + rt_ofw_node_put(np); + } +#endif + + if (!reg_np) + { + reg = rt_err_ptr(-RT_ENOSYS); + goto _end; + } + + rt_hw_spin_lock(&_regulator_lock.lock); + + regulator_check_parent(reg_np); + + rt_hw_spin_unlock(&_regulator_lock.lock); + + reg = rt_calloc(1, sizeof(*reg)); + + if (!reg) + { + reg = rt_err_ptr(-RT_ENOMEM); + goto _end; + } + + reg->reg_np = reg_np; + rt_ref_get(®_np->ref); + +_end: + return reg; +} + +static void regulator_release(struct rt_ref *r) +{ + struct rt_regulator_node *reg_np = rt_container_of(r, struct rt_regulator_node, ref); + + rt_regulator_unregister(reg_np); +} + +void rt_regulator_put(struct rt_regulator *reg) +{ + if (!reg) + { + return; + } + + rt_ref_put(®->reg_np->ref, ®ulator_release); + rt_free(reg); +} diff --git a/components/drivers/regulator/regulator_dm.c b/components/drivers/regulator/regulator_dm.c new file mode 100644 index 0000000000..d8096c43d3 --- /dev/null +++ b/components/drivers/regulator/regulator_dm.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#include "regulator_dm.h" + +#ifdef RT_USING_OFW +rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param) +{ + rt_uint32_t pval; + + param->name = rt_ofw_prop_read_raw(np, "regulator-name", RT_NULL); + + if (!rt_ofw_prop_read_u32(np, "regulator-min-microvolt", &pval)) + { + param->min_uvolt = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-max-microvolt", &pval)) + { + param->max_uvolt = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-min-microamp", &pval)) + { + param->min_uamp = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-max-microamp", &pval)) + { + param->max_uamp = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-ramp-delay", &pval)) + { + param->ramp_delay = pval; + } + + if (!rt_ofw_prop_read_u32(np, "regulator-enable-ramp-delay", &pval)) + { + param->enable_delay = pval; + } + + param->enable_active_high = rt_ofw_prop_read_bool(np, "enable-active-high"); + param->boot_on = rt_ofw_prop_read_bool(np, "regulator-boot-on"); + param->always_on = rt_ofw_prop_read_bool(np, "regulator-always-on"); + param->soft_start = rt_ofw_prop_read_bool(np, "regulator-soft-start"); + param->pull_down = rt_ofw_prop_read_bool(np, "regulator-pull-down"); + param->over_current_protection = rt_ofw_prop_read_bool(np, "regulator-over-current-protection"); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/regulator/regulator_dm.h b/components/drivers/regulator/regulator_dm.h new file mode 100644 index 0000000000..207bb12794 --- /dev/null +++ b/components/drivers/regulator/regulator_dm.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-23 GuEe-GUI first version + */ + +#ifndef __REGULATOR_DM_H__ +#define __REGULATOR_DM_H__ + +#include +#include + +#ifdef RT_USING_OFW +rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param); +#else +rt_inline rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param); +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +#endif /* __REGULATOR_DM_H__ */ diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index 874db5b7e9..6897dab6d3 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -35,6 +35,9 @@ if GetDepend('RT_USING_SFUD'): elif rtconfig.PLATFORM in ['armcc']: LOCAL_CFLAGS += ' --c99' +if GetDepend('RT_USING_DM'): + src += ['dev_spi_dm.c', 'dev_spi_bus.c'] + src += src_device group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH, LOCAL_CFLAGS = LOCAL_CFLAGS) diff --git a/components/drivers/spi/dev_spi.c b/components/drivers/spi/dev_spi.c index b40ffd90db..3f55fd0eb0 100644 --- a/components/drivers/spi/dev_spi.c +++ b/components/drivers/spi/dev_spi.c @@ -10,6 +10,14 @@ #include #include "drivers/dev_spi.h" +#define DBG_TAG "spi.dev" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_DM +#include "dev_spi_dm.h" +#endif + /* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */ static rt_ssize_t _spi_bus_device_read(rt_device_t dev, rt_off_t pos, @@ -155,3 +163,66 @@ rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name) /* register to device manager */ return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR); } + +#ifdef RT_USING_DM +static rt_err_t spidev_probe(struct rt_spi_device *spi_dev) +{ + const char *bus_name; + struct rt_device *dev = &spi_dev->parent; + + if (spi_dev->parent.ofw_node) + { + if (rt_dm_dev_prop_index_of_string(dev, "compatible", "spidev") >= 0) + { + LOG_E("spidev is not supported in OFW"); + + return -RT_EINVAL; + } + } + + bus_name = rt_dm_dev_get_name(&spi_dev->bus->parent); + rt_dm_dev_set_name(dev, "%s_%d", bus_name, spi_dev->chip_select); + + return RT_EOK; +} + +static const struct rt_spi_device_id spidev_ids[] = +{ + { .name = "dh2228fv" }, + { .name = "ltc2488" }, + { .name = "sx1301" }, + { .name = "bk4" }, + { .name = "dhcom-board" }, + { .name = "m53cpld" }, + { .name = "spi-petra" }, + { .name = "spi-authenta" }, + { .name = "em3581" }, + { .name = "si3210" }, + { /* sentinel */ }, +}; + +static const struct rt_ofw_node_id spidev_ofw_ids[] = +{ + { .compatible = "cisco,spi-petra" }, + { .compatible = "dh,dhcom-board" }, + { .compatible = "lineartechnology,ltc2488" }, + { .compatible = "lwn,bk4" }, + { .compatible = "menlo,m53cpld" }, + { .compatible = "micron,spi-authenta" }, + { .compatible = "rohm,dh2228fv" }, + { .compatible = "semtech,sx1301" }, + { .compatible = "silabs,em3581" }, + { .compatible = "silabs,si3210" }, + { .compatible = "rockchip,spidev" }, + { /* sentinel */ }, +}; + +static struct rt_spi_driver spidev_driver = +{ + .ids = spidev_ids, + .ofw_ids = spidev_ofw_ids, + + .probe = spidev_probe, +}; +RT_SPI_DRIVER_EXPORT(spidev_driver); +#endif /* RT_USING_DM */ diff --git a/components/drivers/spi/dev_spi_bus.c b/components/drivers/spi/dev_spi_bus.c new file mode 100644 index 0000000000..34aa298aea --- /dev/null +++ b/components/drivers/spi/dev_spi_bus.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include "dev_spi_dm.h" + +#define DBG_TAG "spi.bus" +#define DBG_LVL DBG_INFO +#include + +extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name); + +static struct rt_bus spi_bus; + +void spi_bus_scan_devices(struct rt_spi_bus *bus) +{ +#ifdef RT_USING_OFW + if (bus->parent.ofw_node) + { + struct rt_ofw_node *np = bus->parent.ofw_node, *spi_dev_np; + + rt_ofw_foreach_available_child_node(np, spi_dev_np) + { + rt_uint64_t reg_offset; + struct rt_spi_device *spi_dev; + + if (!rt_ofw_prop_read_bool(spi_dev_np, "compatible")) + { + continue; + } + + spi_dev = rt_calloc(1, sizeof(*spi_dev)); + + if (!spi_dev) + { + rt_ofw_node_put(spi_dev_np); + LOG_E("Not memory to create spi device: %s", + rt_ofw_node_full_name(spi_dev_np)); + + return; + } + + rt_ofw_get_address(spi_dev_np, 0, ®_offset, RT_NULL); + + spi_dev->parent.ofw_node = spi_dev_np; + spi_dev->parent.type = RT_Device_Class_Unknown; + spi_dev->name = rt_ofw_node_name(spi_dev_np); + spi_dev->bus = bus; + + rt_dm_dev_set_name(&spi_dev->parent, rt_ofw_node_full_name(spi_dev_np)); + + if (spi_device_ofw_parse(spi_dev)) + { + continue; + } + + rt_spi_device_register(spi_dev); + } + } +#endif /* RT_USING_OFW */ +} + +rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver) +{ + RT_ASSERT(driver != RT_NULL); + + driver->parent.bus = &spi_bus; + + return rt_driver_register(&driver->parent); +} + +rt_err_t rt_spi_device_register(struct rt_spi_device *device) +{ + RT_ASSERT(device != RT_NULL); + + return rt_bus_add_device(&spi_bus, &device->parent); +} + +static rt_bool_t spi_match(rt_driver_t drv, rt_device_t dev) +{ + const struct rt_spi_device_id *id; + struct rt_spi_driver *driver = rt_container_of(drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if ((id = driver->ids)) + { + for (; id->name[0]; ++id) + { + if (!rt_strcmp(id->name, device->name)) + { + device->id = id; + device->ofw_id = RT_NULL; + + return RT_TRUE; + } + } + } + +#ifdef RT_USING_OFW + device->ofw_id = rt_ofw_node_match(device->parent.ofw_node, driver->ofw_ids); + + if (device->ofw_id) + { + device->id = RT_NULL; + + return RT_TRUE; + } +#endif + + return RT_FALSE; +} + +static rt_err_t spi_probe(rt_device_t dev) +{ + rt_err_t err; + struct rt_spi_bus *bus; + struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if (!device->bus) + { + return -RT_EINVAL; + } + + err = driver->probe(device); + + if (err) + { + return err; + } + + bus = device->bus; + + if (bus->pins) + { + device->cs_pin = bus->pins[device->chip_select]; + + rt_pin_mode(device->cs_pin, PIN_MODE_OUTPUT); + } + else + { + device->cs_pin = PIN_NONE; + } + + /* Driver not register SPI device to system */ + if (device->parent.type == RT_Device_Class_Unknown) + { + rt_spidev_device_init(device, rt_dm_dev_get_name(&device->parent)); + } + + return err; +} + +static rt_err_t spi_remove(rt_device_t dev) +{ + struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if (driver && driver->remove) + { + driver->remove(device); + } + rt_free(device); + + return RT_EOK; +} + +static rt_err_t spi_shutdown(rt_device_t dev) +{ + struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent); + struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent); + + if (driver && driver->shutdown) + { + driver->shutdown(device); + } + rt_free(device); + + return RT_EOK; +} + +static struct rt_bus spi_bus = +{ + .name = "spi", + .match = spi_match, + .probe = spi_probe, + .remove = spi_remove, + .shutdown = spi_shutdown, +}; + +static int spi_bus_init(void) +{ + rt_bus_register(&spi_bus); + + return 0; +} +INIT_CORE_EXPORT(spi_bus_init); diff --git a/components/drivers/spi/dev_spi_core.c b/components/drivers/spi/dev_spi_core.c index 648195544d..d84aaac055 100644 --- a/components/drivers/spi/dev_spi_core.c +++ b/components/drivers/spi/dev_spi_core.c @@ -19,6 +19,10 @@ #define DBG_LVL DBG_INFO #include +#ifdef RT_USING_DM +#include "dev_spi_dm.h" +#endif + extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name); extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name); @@ -41,6 +45,46 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, /* set bus mode */ bus->mode = RT_SPI_BUS_MODE_SPI; +#ifdef RT_USING_DM + if (!bus->slave) + { + int pin_count = rt_pin_get_named_pin_count(&bus->parent, "cs"); + + if (pin_count > 0) + { + pin_count = rt_max_t(int, pin_count, bus->num_chipselect); + bus->pins = rt_malloc(sizeof(bus->pins[0]) * pin_count); + + if (!bus->pins) + { + rt_device_unregister(&bus->parent); + return -RT_ENOMEM; + } + + for (int i = 0; i < pin_count; ++i) + { + bus->pins[i] = rt_pin_get_named_pin(&bus->parent, "cs", i, + RT_NULL, RT_NULL); + } + } + else if (pin_count == 0) + { + bus->pins = RT_NULL; + } + else + { + result = pin_count; + + LOG_E("CS PIN find error = %s", rt_strerror(result)); + + rt_device_unregister(&bus->parent); + return result; + } + } + + spi_bus_scan_devices(bus); +#endif + return RT_EOK; } diff --git a/components/drivers/spi/dev_spi_dm.c b/components/drivers/spi/dev_spi_dm.c new file mode 100644 index 0000000000..063615ce62 --- /dev/null +++ b/components/drivers/spi/dev_spi_dm.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include "dev_spi_dm.h" + +#define DBG_TAG "spi.dm" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_OFW +static void ofw_parse_delay(struct rt_ofw_node *np, struct rt_spi_delay *delay, + const char *prop) +{ + rt_uint32_t value; + + if (!rt_ofw_prop_read_u32(np, prop, &value)) + { + if (value > RT_UINT16_MAX) + { + delay->value = RT_DIV_ROUND_UP(value, 1000); + delay->unit = RT_SPI_DELAY_UNIT_USECS; + } + else + { + delay->value = value; + delay->unit = RT_SPI_DELAY_UNIT_NSECS; + } + } +} + +rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev) +{ + rt_err_t err; + rt_uint32_t value; + struct rt_spi_bus *spi_bus = spi_dev->bus; + struct rt_ofw_node *np = spi_dev->parent.ofw_node; + struct rt_spi_configuration *conf = &spi_dev->config; + + if (rt_ofw_prop_read_bool(np, "spi-cpha")) + { + conf->mode |= RT_SPI_CPHA; + } + if (rt_ofw_prop_read_bool(np, "spi-cpol")) + { + conf->mode |= RT_SPI_CPOL; + } + if (rt_ofw_prop_read_bool(np, "spi-3wire")) + { + conf->mode |= RT_SPI_3WIRE; + } + if (rt_ofw_prop_read_bool(np, "spi-lsb-first")) + { + conf->mode |= RT_SPI_LSB; + } + if (rt_ofw_prop_read_bool(np, "spi-cs-high")) + { + conf->mode |= RT_SPI_CS_HIGH; + } + + value = 1; + rt_ofw_prop_read_u32(np, "spi-tx-bus-width", &value); + conf->data_width_tx = value; + + value = 1; + rt_ofw_prop_read_u32(np, "spi-rx-bus-width", &value); + conf->data_width_rx = value; + + if (spi_bus->slave) + { + if (!rt_ofw_node_tag_equ(np, "slave")) + { + LOG_E("Invalid SPI device = %s", rt_ofw_node_full_name(np)); + + return -RT_EINVAL; + } + + return RT_EOK; + } + + if ((err = rt_ofw_prop_read_u32(np, "reg", &value))) + { + LOG_E("Find 'reg' failed"); + + return err; + } + spi_dev->chip_select = value; + + if (!rt_ofw_prop_read_u32(np, "spi-max-frequency", &value)) + { + conf->max_hz = value; + } + + ofw_parse_delay(np, &spi_dev->cs_setup, "spi-cs-setup-delay-ns"); + ofw_parse_delay(np, &spi_dev->cs_hold, "spi-cs-hold-delay-ns"); + ofw_parse_delay(np, &spi_dev->cs_inactive, "spi-cs-inactive-delay-ns"); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/spi/dev_spi_dm.h b/components/drivers/spi/dev_spi_dm.h new file mode 100644 index 0000000000..c124295788 --- /dev/null +++ b/components/drivers/spi/dev_spi_dm.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#ifndef __DEV_SPI_DM_H__ +#define __DEV_SPI_DM_H__ + +#include +#include +#include + +#ifdef RT_USING_OFW +rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev); +#else +rt_inline rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +void spi_bus_scan_devices(struct rt_spi_bus *bus); + +#endif /* __DEV_SPI_DM_H__ */ diff --git a/components/net/at/at_socket/at_socket.c b/components/net/at/at_socket/at_socket.c index 4c5dee2b62..4695d3c102 100644 --- a/components/net/at/at_socket/at_socket.c +++ b/components/net/at/at_socket/at_socket.c @@ -759,7 +759,7 @@ static void at_connect_notice_cb(struct at_socket *sock, at_socket_evt_t event, } new_sock = at_get_socket(new_socket); new_sock->state = AT_SOCKET_CONNECT; - sscanf(buff, "SOCKET:%d", &base_socket); + rt_sscanf(buff, "SOCKET:%d", &base_socket); LOG_D("ACCEPT BASE SOCKET: %d", base_socket); new_sock->user_data = (void *)base_socket; @@ -985,7 +985,7 @@ int at_accept(int socket, struct sockaddr *name, socklen_t *namelen) at_do_event_changes(sock, AT_EVENT_RECV, RT_FALSE); } - sscanf(&receive_buff[0], "SOCKET:%d", &new_socket); + rt_sscanf(&receive_buff[0], "SOCKET:%d", &new_socket); new_sock = at_get_socket(new_socket); ip4_addr_set_any(&remote_addr); ipaddr_port_to_socketaddr(name, &remote_addr, &remote_port); diff --git a/components/utilities/ulog/ulog.c b/components/utilities/ulog/ulog.c index 9545e43ecd..b92787f715 100644 --- a/components/utilities/ulog/ulog.c +++ b/components/utilities/ulog/ulog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2022, RT-Thread Development Team + * Copyright (c) 2006-2024 RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -1262,6 +1262,24 @@ MSH_CMD_EXPORT(ulog_filter, Show ulog filter settings); #endif /* RT_USING_FINSH */ #endif /* ULOG_USING_FILTER */ +/** + * @brief register the backend device into the ulog. + * + * @param backend Backend device handle, a pointer to a "struct ulog_backend" obj. + * @param name Backend device name. + * @param support_color Whether it supports color logs. + * @return rt_err_t - return 0 on success. + * + * @note - This function is used to register the backend device into the ulog, + * ensuring that the function members in the backend device structure are set before registration. + * - about struct ulog_backend: + * 1. The name and support_color properties can be passed in through the ulog_backend_register() function. + * 2. output is the back-end specific output function, and all backends must implement the interface. + * 3. init/deinit is optional, init is called at register, and deinit is called at unregister or ulog_deinit. + * 4. flush is also optional, and some internal output cached backends need to implement this interface. + * For example, some file systems with RAM cache. The flush of the backend is usually called by + * ulog_flush in the case of an exception such as assertion or hardfault. + */ rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool_t support_color) { rt_base_t level; @@ -1287,6 +1305,13 @@ rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool return RT_EOK; } +/** + * @brief unregister a backend device that has already been registered. + * + * @param backend Backend device handle + * @return rt_err_t - return 0 on success. + * @note deinit function will be called at unregister. + */ rt_err_t ulog_backend_unregister(ulog_backend_t backend) { rt_base_t level; @@ -1460,6 +1485,14 @@ void ulog_flush(void) } } +/** + * @brief ulog initialization + * + * @return int return 0 on success, return -5 when failed of insufficient memory. + * + * @note This function must be called to complete ulog initialization before using ulog. + * This function will also be called automatically if component auto-initialization is turned on. + */ int ulog_init(void) { if (ulog.init_ok) @@ -1518,6 +1551,11 @@ int ulog_async_init(void) INIT_PREV_EXPORT(ulog_async_init); #endif /* ULOG_USING_ASYNC_OUTPUT */ +/** + * @brief ulog deinitialization + * + * @note This deinit release resource can be executed when ulog is no longer used. + */ void ulog_deinit(void) { rt_slist_t *node; diff --git a/documentation/basic/basic.md b/documentation/basic/basic.md index d25846e125..ec5215b132 100644 --- a/documentation/basic/basic.md +++ b/documentation/basic/basic.md @@ -669,7 +669,7 @@ Configuration is mainly done by modifying the file under project directory - rtc /* While turning the system FinSH: define the number of historical command lines. */ #define FINSH_HISTORY_LINES 5 -/* While turning the system FinSH: define this macro to open the Tab key, if not defined, close. */ +/* While turning the system FinSH: define this macro to use symbol table in Finsh, if not defined, close. */ #define FINSH_USING_SYMTAB /* While turning the system FinSH: define the priority of the thread. */ diff --git a/documentation/finsh/finsh.md b/documentation/finsh/finsh.md index 1b56c4636e..1d882d6032 100644 --- a/documentation/finsh/finsh.md +++ b/documentation/finsh/finsh.md @@ -421,7 +421,7 @@ The reference configuration example in rtconfig.h is as follows, and can be conf /* Record 5 lines of history commands */ #define FINSH_HISTORY_LINES 5 -/* Enable the use of the Tab key */ +/* Enable the use of symbol table */ #define FINSH_USING_SYMTAB /* Turn on description */ #define FINSH_USING_DESCRIPTION diff --git a/examples/test/avl.c b/examples/test/avl.c index 961b46cc3c..b5141c5d9d 100644 --- a/examples/test/avl.c +++ b/examples/test/avl.c @@ -556,7 +556,7 @@ int main(int argc, char *argv[]) { if (argc == 2) { - sscanf(argv[1], "%d", &loop_count); + rt_sscanf(argv[1], "%d", &loop_count); } else { diff --git a/libcpu/risc-v/SConscript b/libcpu/risc-v/SConscript index 273c997e8e..ca5934b4f3 100644 --- a/libcpu/risc-v/SConscript +++ b/libcpu/risc-v/SConscript @@ -16,6 +16,8 @@ if rtconfig.CPU in common64_arch : else : group += SConscript(os.path.join('common', 'SConscript')) +group += SConscript(os.path.join('vector', 'SConscript')) + # cpu porting code files if 'VENDOR' in vars(rtconfig) and rtconfig.VENDOR != '': group = group + SConscript(os.path.join(rtconfig.VENDOR, rtconfig.CPU, 'SConscript')) diff --git a/libcpu/risc-v/common64/cpuport.h b/libcpu/risc-v/common64/cpuport.h index 0723a3c393..293f681c97 100644 --- a/libcpu/risc-v/common64/cpuport.h +++ b/libcpu/risc-v/common64/cpuport.h @@ -14,6 +14,8 @@ #include #include +#ifndef __ASSEMBLY__ + #ifdef RT_USING_SMP typedef union { unsigned long slock; @@ -24,8 +26,7 @@ typedef union { } rt_hw_spinlock_t; #endif -#ifndef __ASSEMBLY__ -#include +#include rt_inline void rt_hw_dsb(void) { diff --git a/libcpu/risc-v/t-head/c908/SConscript b/libcpu/risc-v/t-head/c908/SConscript index 1f56051d1d..0e2b436623 100644 --- a/libcpu/risc-v/t-head/c908/SConscript +++ b/libcpu/risc-v/t-head/c908/SConscript @@ -5,9 +5,6 @@ cwd = GetCurrentDir() src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S') CPPPATH = [cwd] -if GetDepend('ARCH_RISCV_VECTOR'): - CPPPATH += [cwd + '/../../vector/rvv-1.0'] - group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/libcpu/risc-v/vector/SConscript b/libcpu/risc-v/vector/SConscript new file mode 100644 index 0000000000..69e8318e5c --- /dev/null +++ b/libcpu/risc-v/vector/SConscript @@ -0,0 +1,12 @@ +# RT-Thread building script for component + +from building import * +cwd = GetCurrentDir() +src = [] +CPPPATH = [] + +CPPPATH += [cwd + '/rvv-1.0'] + +group = DefineGroup('libcpu', src, depend = ['ARCH_RISCV_VECTOR'], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/risc-v/virt64/SConscript b/libcpu/risc-v/virt64/SConscript index 0cfbd3cd6a..0e2b436623 100644 --- a/libcpu/risc-v/virt64/SConscript +++ b/libcpu/risc-v/virt64/SConscript @@ -5,9 +5,6 @@ cwd = GetCurrentDir() src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S') CPPPATH = [cwd] -if not GetDepend('ARCH_RISCV_VECTOR'): - SrcRemove(src, ['vector_gcc.S']) - group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/libcpu/risc-v/virt64/rvv_context.h b/libcpu/risc-v/virt64/rvv_context.h deleted file mode 100644 index a416396b1e..0000000000 --- a/libcpu/risc-v/virt64/rvv_context.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2006-2024, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-10-10 RT-Thread the first version, - * compatible to riscv-v-spec-1.0 - */ -#ifndef __RVV_CONTEXT_H__ -#define __RVV_CONTEXT_H__ - -#include "cpuport.h" -#include "encoding.h" - -#if defined(ARCH_VECTOR_VLEN_128) - #define CTX_VECTOR_REGS 64 -#elif defined(ARCH_VECTOR_VLEN_256) - #define CTX_VECTOR_REGS 128 -#else -#error "No supported VLEN" -#endif /* VLEN */ - -#define CTX_VECTOR_REG_NR (CTX_VECTOR_REGS + 4) - -/** - * ================================== - * VECTOR EXTENSION - * ================================== - */ - -#define VEC_FRAME_VSTART (0 * REGBYTES) -#define VEC_FRAME_VTYPE (1 * REGBYTES) -#define VEC_FRAME_VL (2 * REGBYTES) -#define VEC_FRAME_VCSR (3 * REGBYTES) -#define VEC_FRAME_V0 (4 * REGBYTES) - -.macro GET_VEC_FRAME_LEN, xreg - csrr \xreg, vlenb - slli \xreg, \xreg, 5 - addi \xreg, \xreg, 4 * REGBYTES -.endm - -/** - * @brief save vector extension hardware state - * - * @param dst register storing bottom of storage block - * - */ -.macro SAVE_VECTOR, dst - mv t1, \dst - - csrr t0, vstart - STORE t0, VEC_FRAME_VSTART(t1) - csrr t0, vtype - STORE t0, VEC_FRAME_VTYPE(t1) - csrr t0, vl - STORE t0, VEC_FRAME_VL(t1) - csrr t0, vcsr - STORE t0, VEC_FRAME_VCSR(t1) - - addi t1, t1, VEC_FRAME_V0 - - // config vector setting, - // t2 is updated to length of a vector group in bytes - VEC_CONFIG_SETVLI(t2, x0, VEC_IMM_SEW_8, VEC_IMM_LMUL_8) - - vse8.v v0, (t1) - add t1, t1, t2 - vse8.v v8, (t1) - add t1, t1, t2 - vse8.v v16, (t1) - add t1, t1, t2 - vse8.v v24, (t1) -.endm - -/** - * @brief restore vector extension hardware states - * - * @param dst register storing bottom of storage block - * - */ -.macro RESTORE_VECTOR, dst - // restore vector registers first since it will modify vector states - mv t0, \dst - addi t1, t0, VEC_FRAME_V0 - - VEC_CONFIG_SETVLI(t2, x0, VEC_IMM_SEW_8, VEC_IMM_LMUL_8) - - vle8.v v0, (t1) - add t1, t1, t2 - vle8.v v8, (t1) - add t1, t1, t2 - vle8.v v16, (t1) - add t1, t1, t2 - vle8.v v24, (t1) - - mv t1, t0 - - LOAD t0, VEC_FRAME_VSTART(t1) - csrw vstart, t0 - LOAD t0, VEC_FRAME_VCSR(t1) - csrw vcsr, t0 - - LOAD t0, VEC_FRAME_VTYPE(t1) - LOAD t3, VEC_FRAME_VL(t1) - VEC_CONFIG_SET_VL_VTYPE(t3, t0) -.endm - -#endif /* __RVV_CONTEXT_H__ */ diff --git a/libcpu/risc-v/virt64/vector_encoding.h b/libcpu/risc-v/virt64/vector_encoding.h deleted file mode 100644 index 26c2c86f4c..0000000000 --- a/libcpu/risc-v/virt64/vector_encoding.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-10-10 RT-Thread the first version, - * compatible to riscv-v-spec-1.0 - */ - -#ifndef __VECTOR_ENCODING_H__ -#define __VECTOR_ENCODING_H__ - -/* mstatus/sstatus */ -#define MSTATUS_VS 0x00000600 -#define SSTATUS_VS 0x00000600 /* Vector Status */ -#define SSTATUS_VS_INITIAL 0x00000200 -#define SSTATUS_VS_CLEAN 0x00000400 -#define SSTATUS_VS_DIRTY 0x00000600 - -/** - * assembler names used for vset{i}vli vtypei immediate - */ - -#define VEC_IMM_SEW_8 e8 -#define VEC_IMM_SEW_16 e16 -#define VEC_IMM_SEW_32 e32 -#define VEC_IMM_SEW_64 e64 -/* group setting, encoding by multiplier */ -#define VEC_IMM_LMUL_F8 mf8 -#define VEC_IMM_LMUL_F4 mf4 -#define VEC_IMM_LMUL_F2 mf2 -#define VEC_IMM_LMUL_1 m1 -#define VEC_IMM_LMUL_2 m2 -#define VEC_IMM_LMUL_4 m4 -#define VEC_IMM_LMUL_8 m8 -/* TAIL & MASK agnostic bits */ -#define VEC_IMM_TAIL_AGNOSTIC ta -#define VEC_IMM_MASK_AGNOSTIC ma -#define VEC_IMM_TAMA VEC_IMM_TAIL_AGNOSTIC, VEC_IMM_MASK_AGNOSTIC -#define VEC_IMM_TAMU VEC_IMM_TAIL_AGNOSTIC -#define VEC_IMM_TUMA VEC_IMM_MASK_AGNOSTIC - -/** - * configuration setting instruction - */ -#define VEC_CONFIG_SETVLI(xVl, xAvl, vtype...) vsetvli xVl, xAvl, ##vtype -#define VEC_CONFIG_SET_VL_VTYPE(xVl, xVtype) vsetvl x0, xVl, xVtype - -#endif /* __VECTOR_ENCODING_H__ */ \ No newline at end of file diff --git a/libcpu/risc-v/virt64/vector_gcc.S b/libcpu/risc-v/virt64/vector_gcc.S deleted file mode 100644 index 5c9047ec2e..0000000000 --- a/libcpu/risc-v/virt64/vector_gcc.S +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2006-2024, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2018/10/28 Bernard The unify RISC-V porting implementation - * 2018/12/27 Jesven Add SMP support - * 2021/02/02 lizhirui Add userspace support - * 2022/10/22 Shell Support User mode RVV; - * Trimming process switch context - * 2024/09/01 Shell Separated vector ctx from the generic - */ - -#include "cpuport.h" -#include "stackframe.h" - -/** - * @param a0 pointer to frame bottom - */ -.global rt_hw_vector_ctx_save -rt_hw_vector_ctx_save: - SAVE_VECTOR a0 - ret - -/** - * @param a0 pointer to frame bottom - */ -.global rt_hw_vector_ctx_restore -rt_hw_vector_ctx_restore: - RESTORE_VECTOR a0 - ret - -.global rt_hw_disable_vector -rt_hw_disable_vector: - li t0, SSTATUS_VS - csrc sstatus, t0 - ret - -.global rt_hw_enable_vector -rt_hw_enable_vector: - li t0, SSTATUS_VS - csrs sstatus, t0 - ret diff --git a/src/components.c b/src/components.c index b561e227de..9a1db27617 100644 --- a/src/components.c +++ b/src/components.c @@ -90,7 +90,7 @@ void rt_components_board_init(void) const struct rt_init_desc *desc; for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++) { - rt_kprintf("initialize %s", desc->fn_name); + rt_kprintf("initialize %s\n", desc->fn_name); result = desc->fn(); rt_kprintf(":%d done\n", result); } @@ -116,7 +116,7 @@ void rt_components_init(void) rt_kprintf("do components initialization.\n"); for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++) { - rt_kprintf("initialize %s", desc->fn_name); + rt_kprintf("initialize %s\n", desc->fn_name); result = desc->fn(); rt_kprintf(":%d done\n", result); }