未验证 提交 bfd8d21e 编写于 作者: mysterywolf's avatar mysterywolf 提交者: GitHub

Merge branch 'master' into mutexrevert

......@@ -149,10 +149,10 @@ jobs:
if: ${{ matrix.legs.RTT_TOOL_CHAIN == 'sourcery-arm' && success() }}
shell: bash
run: |
wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/arm-2017q2-v6/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2
sudo tar xjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 -C /opt
/opt/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-gcc --version
echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-6-2017-q2-update/bin" >> $GITHUB_ENV
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt
/opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version
echo "RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin" >> $GITHUB_ENV
- name: Install Mips ToolChains
if: ${{ matrix.legs.RTT_TOOL_CHAIN == 'sourcery-mips' && success() }}
......
......@@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
legs:
- {UTEST: "kernel/ipc", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "vexpress-a9", CONFIG_FILE: "examples/utest/configs/utest_self/config.h"}
- {UTEST: "kernel/mem", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "vexpress-a9", CONFIG_FILE: "examples/utest/configs/kernel/config.h"}
- {UTEST: "components/utest", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "vexpress-a9", CONFIG_FILE: "examples/utest/configs/utest_self/config.h"}
env:
......@@ -23,12 +23,12 @@ jobs:
run: |
sudo apt-get update > /dev/null
sudo apt-get -yqq install scons qemu-system-arm git
wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/arm-2017q2-v6/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2
sudo tar xjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 -C /opt
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2
sudo tar xjf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 -C /opt
- name: Build bsp
run: |
export RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-6-2017-q2-update/bin
/opt/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-gcc --version
export RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin
/opt/gcc-arm-none-eabi-10-2020-q4-major/bin/arm-none-eabi-gcc --version
cp $TEST_CONFIG_FILE $TEST_BSP_ROOT/rtconfig.h
scons -j$(nproc) -C $TEST_BSP_ROOT
- name: Start test
......
此差异已折叠。
mainmenu "RT-Thread Project Configuration"
config BSP_DIR
string
option env="BSP_ROOT"
default "."
config RTT_DIR
string
option env="RTT_ROOT"
default "../.."
config PKGS_DIR
string
option env="PKGS_ROOT"
default "packages"
source "$RTT_DIR/Kconfig"
source "$PKGS_DIR/Kconfig"
config FT2004
bool
select ARCH_ARM_CORTEX_A
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN
select RT_USING_GIC_V3
default y
source "./libraries/Kconfig"
# ft2004 四核开发板 BSP 说明
## 简介
本文档为 飞腾技术公司 ft2000/4 开发板的 BSP (板级支持包) 说明。
主要内容如下:
- 开发板资源介绍
- BSP 外设支持
- 使用方法
- 相关实验
### 1. 开发板资源介绍
FT-2000/4 是一款面向桌面应用的高性能通用 4 核处理器。每 2 个核构成 1
个处理器核簇(Cluster),并共享 L2 Cache。主要技术特征如下:
- 兼容 ARM v8 64 位指令系统,兼容 32 位指令
- 支持单精度、双精度浮点运算指令
- 支持 ASIMD 处理指令
- 集成 2 个 DDR4 通道,可对 DDR 存储数据进行实时加密
- 集成 34 Lane PCIE3.0 接口:2 个 X16(每个可拆分成 2 个 X8),2 个 X1
- 集成 2 个 GMAC,RGMII 接口,支持 10/100/1000 自适应
- 集成 1 个 SD 卡控制器,兼容 SD 2.0 规范
- 集成 1 个 HDAudio,支持音频输出,可同时支持最多 4 个 Codec
- 集成 SM2、SM3、SM4 模块
- 集成 4 个 UART,1 个 LPC,32 个 GPIO,4 个 I2C,1 个 QSPI,2 个通
用 SPI,2 个 WDT,16 个外部中断(和 GPIO 共用 IO)
- 集成温度传感器
### 2. BSP 外设支持
| 外设名 | 支持情况 | 备注 |
| -------- | -------- | ---------------------- |
| ft_gicv3 | 支持 | gicv3 中断控制器 |
| ft_gmac | 支持 | ft gmac 千兆网卡控制器 |
| ft_i2c | 支持 | FT I2C |
| ft_qspi | 支持 | FT qspi 控制器 |
| ft_sd | 支持 | FT mmcsd 控制器 |
| ft_uart | 支持 | PrimeCell PL011 |
| ft_spi | 支持 | FT spi 控制器 |
| ft_gpio | 支持 | FT gpio 控制器 |
| ft_can | 支持 | FT can 控制器 |
### 3. 使用方法
#### ubuntu 上环境搭建
1. 在 ubuntu 环境下通过指令,下载并安装交叉编译链
```
sudo apt-get install gcc-arm-none-eabi
```
2. 安装之后,通过指令,确定交叉编译链安装完毕
```
arm-none-eabi-gcc -v
```
3. 搭建 tftp 环境
- 在主机安装 tftp 服务
> 使用 ubuntu 完成下列操作
```
sudo apt-get install tftp-hpa tftpd-hpa
sudo apt-get install xinetd
```
- 新建 tftboot 目录,如:
`/mnt/d/tftboot`
> 需要给 tftboot 目录执行权限`chmod 777 /**/tftboot`
- 配置主机 tftpboot 服务
新建并配置文件/etc/xinetd.d/tftp
```
# /etc/xinetd.d/tftp
server tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /mnt/d/tftboot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
```
- 启动主机 tftp 服务
```
sudo service tftpd-hpa start
```
- 修改主机 tftp 配置
修改/etc/default/tftpd-hpa
```
sudo nano /etc/default/tftpd-hpa
# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/mnt/d/tftboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-l -c -s"
```
- 重启主机 tftp 服务
> 每次开机要重启一次
```
sudo service tftpd-hpa restart
```
- 测试主机 tftp 服务的可用性
> 登录 tftp 服务,获取一个文件
```
$ tftp 192.168.4.50
tftp> get test1234
tftp> q
```
#### 执行
1. 将本 bsp 包拷贝至 RT-THREAD bsp/目录下
1. 在 Ubuntu 终端下,切换至 bsp 目录
```
cd rt-thread/bsp/ft2004
```
3. 使用 scons -c 清空工程缓存
4. 使用 scons --menuconfig 配置需要的外设
![](./figures/onchipPeripheral.png)
5. 使用 scons 编译代码,得到 rtthread.bin,并将 rtthread.bin 放入之前配置的 tftp 路径下。
6. 连接开发板对应串口到 PC, 在终端工具里打开相应的串口(115200-8-1-N)。
7. 将开发板网线接入局域网中
8. 本开发板自带 uboot,使用 uboot 自带 指令进行将 bin 文件下载至 ram 中
```
setenv ipaddr 192.168.x.x # 设置开发板ip
setenv serverip 192.168.x.x # 设置tftp服务器ip
setenv gatewayip 192.168.x.x # 设置网关ip
tftpboot 80100000 rtthread.bin # 在主机 /tftpboot目录中的rtthread.bin文件下载到开发板内存的80100000地址中。
```
7. 执行跳转指令,便可以正常执行
```
bootvx32 80100000
boot32 80100000
```
![](./figures/启动演示图.png)
### 5. 相关实验
#### 网卡
- 主机 ping 本机 指令 sudo ping 192.168.3.20 (默认)
- rtt ping 主机 指令 ping 192.168.x.x (根据实际情况)
- 通过界面
![](./figures/rttPing通过界面.png)
#### sd 卡调试
- 通过基本命令进行,mv ,echo ,ls ,cd ,rm ....
![](./figures/rttsd调试.png)
#### spi flash 卡调试
- 找一块有 spi flash 插槽的 ft-2004 开发板,插入 sf25s 或 gd25q 系列 spi flash
- 配置 rt-thread 的编译选项,打开 BSP_USE_SPI 和 BSP_USE_GPIO 配置,关闭 BSP_USE_QSPI 配置,打开 rt-thread 的 SFUD 调试开关
- 编译 rt-thread,加载版本启动,启动后显示 spi flash probe 成功
- 执行 sf 基本操作,read, write, erase
#### 推荐指令
1. sf probe S25FS256
2. sf read 0x1FFF000 16
3. sf write 0x1FFF000 16 25 68 78 95 15 75 20
4. sf read 0x1FFF000 16
5. sf erase 0x1FFF000 16
#### can 测试
1. 使用 scons menuconfig 选中 Enable Can
2. 然后选中 Enable can0 ,Enable can0 work in loop back
3. 烧录程序并且烧录
4. 打开 can 盒,将波特率设为 1000000
5. 然后通过 can 盒发送对应的数据(标准帧,扩展帧),就可以看见回复同样的内容
## 6. 参考资源
- ARM Architecture Reference Manual
- FT-2000/4 软件编程手册-V1.4
## 7. 联系人信息
请联系飞腾嵌入式软件部
huanghe@phytium.com.cn
zhugengyu@phytium.com.cn
# for module compiling
import os
Import('RTT_ROOT')
cwd = str(Dir('#'))
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')
import os
import sys
import rtconfig
if os.getenv('RTT_ROOT'):
RTT_ROOT = os.getenv('RTT_ROOT')
else:
RTT_ROOT = os.path.join(os.getcwd(), '..', '..')
sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
from building import *
TARGET = 'ft2004.' + rtconfig.TARGET_EXT
DefaultEnvironment(tools=[])
env = Environment(tools = ['mingw'],
AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
CXX= rtconfig.CXX, CXXFLAGS = rtconfig.CFLAGS,
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')
# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT)
# make a building
DoBuilding(TARGET, objs)
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-12-05 Bernard the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "ft_cpu.h"
#include "ft_generic_timer.h"
#include <board.h>
#ifdef RT_USING_SMP
struct rt_thread test_core[RT_CPUS_NR];
static char *core_thread_name[RT_CPUS_NR] = {
"core0_test",
"core1_test",
"core2_test",
"core3_test"};
static rt_uint8_t core_stack[RT_CPUS_NR][1024];
static void demo_core_thread(void *parameter)
{
rt_base_t level;
while (1)
{
/* code */
level = rt_cpus_lock();
rt_kprintf("Hi, core%d \r\n", FCpu_IdGet());
rt_cpus_unlock(level);
rt_thread_mdelay(20000);
}
}
void demo_core(void)
{
rt_ubase_t i;
rt_uint8_t cpu_id = 0;
for (i = 0; i < RT_CPUS_NR; i++)
{
cpu_id = i;
rt_thread_init(&test_core[i],
core_thread_name[i],
demo_core_thread,
RT_NULL,
&core_stack[i],
1024,
20,
32);
rt_thread_control(&test_core[i], RT_THREAD_CTRL_BIND_CPU, (void *)cpu_id);
rt_thread_startup(&test_core[i]);
}
}
#endif
int main(void)
{
int count = 1;
#ifdef RT_USING_SMP
demo_core();
#endif
while (count++)
{
rt_thread_mdelay(2000);
}
return RT_EOK;
}
from building import *
cwd = GetCurrentDir()
src = Glob('*.S')
src += Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-04 Carl the first version
*
*/
#include <rtthread.h>
#include "ft_printf.h"
#include "ft_assert.h"
#include "ft_cpu.h"
#include "ft_psci.h"
#include "ft_parameters.h"
#include "board.h"
#include "gtimer.h"
#include "ft_generic_timer.h"
#include <gicv3.h>
#include "interrupt.h"
#include <mmu.h>
#include "cp15.h"
#include "ft2004.h"
#define DDR_MEM (SHARED | AP_RW | DOMAIN0 | MEMWT | DESC_SEC)
struct mem_desc platform_mem_desc[] = {
{0x80000000,
0x80000000 + 0x7f000000,
0x80000000,
DDR_MEM},
{0, //< QSPI
0x1FFFFFFF,
0,
DEVICE_MEM},
{0x20000000, //<! LPC
0x27FFFFFF,
0x20000000,
DEVICE_MEM},
{FT_DEV_BASE_ADDR, //<! Device register
FT_DEV_END_ADDR,
FT_DEV_BASE_ADDR,
DEVICE_MEM},
{0x30000000, //<! debug
0x39FFFFFF,
0x30000000,
DEVICE_MEM},
{0x3A000000, //<! Internal register space in the on-chip network
0x3AFFFFFF,
0x3A000000,
DEVICE_MEM},
{FT_PCI_CONFIG_BASEADDR,
FT_PCI_CONFIG_BASEADDR + FT_PCI_CONFIG_REG_LENGTH,
FT_PCI_CONFIG_BASEADDR,
DEVICE_MEM},
{FT_PCI_IO_CONFIG_BASEADDR,
FT_PCI_IO_CONFIG_BASEADDR + FT_PCI_IO_CONFIG_REG_LENGTH,
FT_PCI_IO_CONFIG_BASEADDR,
DEVICE_MEM},
{FT_PCI_MEM32_BASEADDR,
FT_PCI_MEM32_BASEADDR + FT_PCI_MEM32_REG_LENGTH,
FT_PCI_MEM32_BASEADDR,
DEVICE_MEM},
};
const rt_uint32_t platform_mem_desc_size = sizeof(platform_mem_desc) / sizeof(platform_mem_desc[0]);
rt_uint32_t platform_get_gic_dist_base(void)
{
return FT_GICV3_DISTRIBUTOR_BASEADDRESS;
}
static rt_uint32_t timerStep;
void rt_hw_timer_isr(int vector, void *parameter)
{
gtimer_set_load_value(timerStep);
rt_tick_increase();
}
int rt_hw_timer_init(void)
{
rt_hw_interrupt_install(30, rt_hw_timer_isr, RT_NULL, "tick");
rt_hw_interrupt_umask(30);
timerStep = gtimer_get_counter_frequency();
timerStep /= RT_TICK_PER_SECOND;
gtimer_set_load_value(timerStep);
gtimer_set_control(1);
return 0;
}
INIT_BOARD_EXPORT(rt_hw_timer_init);
static void AssertCallback(const char *File, s32 Line)
{
Ft_printf("Assert Error is %s : %d \r\n", File, Line);
}
#ifdef RT_USING_SMP
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
#endif
/**
* This function will initialize hardware board
*/
void rt_hw_board_init(void)
{
/* bsp debug */
FCpu_SpinLockInit();
Ft_GenericTimer_Init(0, RT_NULL);
Ft_vsprintfRegister((vsprintf_p)rt_vsprintf);
Ft_assertSetCallBack((Ft_assertCallback)AssertCallback);
/* interrupt init */
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + 0, 0);
#if RT_CPUS_NR == 2
Ft_printf("arm_gic_redist_address_set is 2 \r\n");
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + (2U << 16), 1);
#elif RT_CPUS_NR == 3
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + (2U << 16), 1);
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + 2 * (2U << 16), 2);
#elif RT_CPUS_NR == 4
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + (2U << 16), 1);
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + 2 * (2U << 16), 2);
arm_gic_redist_address_set(0, FT_GICV3_RD_BASEADDRESS + 3 * (2U << 16), 3);
#endif
rt_hw_interrupt_init();
rt_components_board_init();
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
/* 初始化内存池 */
#ifdef RT_USING_HEAP
rt_system_heap_init(HEAP_BEGIN, HEAP_END);
#endif
#ifdef RT_USING_SMP
/* install IPI handle */
rt_hw_interrupt_set_priority(RT_SCHEDULE_IPI, 16);
rt_hw_ipi_handler_install(RT_SCHEDULE_IPI, rt_scheduler_ipi_handler);
rt_hw_interrupt_umask(RT_SCHEDULE_IPI);
#endif
}
static void ft_reset(void)
{
FPsci_Reset();
}
MSH_CMD_EXPORT_ALIAS(ft_reset, ft_reset, ft_reset);
/*@}*/
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard the first version
*/
#ifndef __BOARD_H__
#define __BOARD_H__
#include "ft_parameters.h"
#include "ft2004.h"
#if defined(__CC_ARM)
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)
#elif defined(__GNUC__)
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
#endif
#define HEAP_END (void *)(0x80000000 + 1024 * 1024 * 1024)
void rt_hw_board_init(void);
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-11 Carl the first version
*/
#include "drv_can.h"
#include "interrupt.h"
#include <string.h>
#ifdef BSP_USE_CAN
#define LOG_TAG "drv_can"
#include <drv_log.h>
#define _CAN0_NAME "can0"
#define _CAN1_NAME "can1"
#define RTHW_CAN_WAIT(_can) rt_sem_take(&_can->recv_semaphore, RT_WAITING_FOREVER);
#define RTHW_CAN_SEND(_can) rt_sem_release(&_can->recv_semaphore);
#ifdef BSP_USING_CAN0
struct ft2004_can drv_can0 =
{
.name = _CAN0_NAME,
.can_handle.Config.InstanceId = 0};
#endif
#ifdef BSP_USING_CAN1
struct ft2004_can drv_can1 =
{
.name = _CAN1_NAME,
.can_handle.Config.InstanceId = 1};
#endif
static void _can_recv_irq(void *args)
{
struct ft2004_can *drv_can = (struct ft2004_can *)args;
RTHW_CAN_SEND(drv_can);
}
static void rt_hw_inner_can_isr(int irqno, void *param)
{
FCan_IntrHandler(param);
}
static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
{
struct FCan_Bittiming bit_timing = {0};
struct ft2004_can *drv_can;
RT_ASSERT(can);
RT_ASSERT(cfg);
drv_can = (struct ft2004_can *)can->parent.user_data;
RT_ASSERT(drv_can);
FCan_CfgInitialize(&drv_can->can_handle, FCan_LookupConfig(drv_can->can_handle.Config.InstanceId));
FCan_SetHandler(&drv_can->can_handle, FCAN_HANDLER_RECV, _can_recv_irq, drv_can);
bit_timing.bitrate = cfg->baud_rate;
if (FCan_CalcBittiming(&bit_timing) != FCAN_SUCCESS)
{
LOG_E("Setting baud rate %x is not valid \r\n", bit_timing.bitrate);
return -RT_ERROR;
}
FCan_SetTiming(&drv_can->can_handle, &bit_timing);
rt_hw_interrupt_set_priority(drv_can->can_handle.Config.IrqNum, 16);
rt_hw_interrupt_install(drv_can->can_handle.Config.IrqNum, rt_hw_inner_can_isr, &drv_can->can_handle, drv_can->name);
rt_hw_interrupt_umask(drv_can->can_handle.Config.IrqNum);
FCan_Enable(&drv_can->can_handle);
return RT_EOK;
}
static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
{
return RT_EOK;
}
static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
{
struct ft2004_can *drv_can;
struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
struct FCan_Frame can_frame = {0};
RT_ASSERT(can);
drv_can = (struct ft2004_can *)can->parent.user_data;
RT_ASSERT(drv_can);
/* Check the parameters */
RT_ASSERT(pmsg->len <= 8U);
if (RT_CAN_STDID == pmsg->ide)
{
can_frame.CanId = pmsg->id;
}
else
{
can_frame.CanId = pmsg->id;
can_frame.CanId |= CAN_EFF_FLAG;
}
if (RT_CAN_DTR == pmsg->rtr)
{
}
else
{
can_frame.CanId |= CAN_RTR_FLAG;
}
can_frame.CanDlc = pmsg->len & 0x0FU;
memcpy(can_frame.data, pmsg->data, 8);
return (FCan_SendByIrq(&drv_can->can_handle, &can_frame, 1, RT_NULL) == 1) ? RT_EOK : -RT_ERROR;
}
static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
{
struct ft2004_can *drv_can;
struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
RT_ASSERT(can);
struct FCan_Frame recv_frame = {0};
drv_can = (struct ft2004_can *)can->parent.user_data;
RT_ASSERT(drv_can);
RTHW_CAN_WAIT(drv_can);
if (FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1) == 0)
{
LOG_E("rx msg is error");
return -RT_ERROR;
}
if (CAN_EFF_FLAG & recv_frame.CanId)
{
pmsg->ide = RT_CAN_EXTID;
pmsg->id = (recv_frame.CanId & ~(RT_CAN_EXTID));
}
else
{
pmsg->ide = RT_CAN_STDID;
pmsg->id = recv_frame.CanId;
}
if (CAN_RTR_FLAG & recv_frame.CanId)
{
pmsg->id &= ~CAN_RTR_FLAG;
pmsg->rtr = RT_CAN_RTR;
}
else
{
pmsg->rtr = RT_CAN_DTR;
}
/* get len */
pmsg->len = recv_frame.CanDlc;
return RT_EOK;
}
static const struct rt_can_ops _can_ops =
{
_can_config,
_can_control,
_can_sendmsg,
_can_recvmsg,
};
int rt_hw_can_init(void)
{
#ifdef BSP_USING_CAN0
drv_can0.can_handle.Config.InstanceId = 0;
rt_sem_init(&drv_can0.recv_semaphore, "can0_recv", 0, RT_IPC_FLAG_FIFO);
drv_can0.device.config.ticks = 20000;
drv_can0.device.config.baud_rate = 1000000;
rt_hw_can_register(&drv_can0.device,
drv_can0.name,
&_can_ops,
&drv_can0);
#endif
#ifdef BSP_USING_CAN1
drv_can1.can_handle.Config.InstanceId = 1;
drv_can0.device.config.baud_rate = 1000000;
rt_sem_init(&drv_can1.recv_semaphore, "can1_recv", 0, RT_IPC_FLAG_FIFO);
rt_hw_can_register(&drv_can1.device,
drv_can1.name,
&_can_ops,
&drv_can1);
#endif
return 0;
}
INIT_BOARD_EXPORT(rt_hw_can_init);
#ifdef BSP_USING_CAN0_DEBUG
struct can_test_struct
{
const char *name;
struct rt_can_filter_config *filter;
rt_device_t candev;
struct rt_semaphore _sem;
};
static struct can_test_struct can0_test_obj = {
.name = _CAN0_NAME};
void can_recv_irq(void *param)
{
struct can_test_struct *_can_obj = (struct can_test_struct *)param;
rt_kprintf("can_recv_iqr \r\n");
rt_sem_release(&_can_obj->_sem);
}
static void rt_can_test_loopback_thread_entry(void *param)
{
struct can_test_struct *_can_obj = (struct can_test_struct *)param;
struct FCan_Frame recv_frame;
struct ft2004_can *drv_can;
rt_uint32_t i;
_can_obj->candev = rt_device_find(_can_obj->name);
RT_ASSERT(_can_obj->candev);
drv_can = (struct ft2004_can *)_can_obj->candev->user_data;
rt_sem_init(&_can_obj->_sem, "canrx_wait", 0, RT_IPC_FLAG_FIFO);
rt_device_open(_can_obj->candev, RT_DEVICE_OFLAG_RDWR);
while (1)
{
rt_kprintf(" start to wait loopback \r\n");
RTHW_CAN_WAIT(drv_can);
while (0 != FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1))
{
rt_kprintf("CanId %x \r\n", recv_frame.CanId);
rt_kprintf("CanDlc %x \r\n", recv_frame.CanDlc);
for (i = 0; i < recv_frame.CanDlc; i++)
{
rt_kprintf("data [%d] %x \r\n", i, recv_frame.data[i]);
}
FCan_SendByIrq(&drv_can->can_handle, &recv_frame, 1, RT_NULL);
}
}
}
int rt_can0_test(void)
{
rt_thread_t tid;
tid = rt_thread_create("can0_loopback",
rt_can_test_loopback_thread_entry, &can0_test_obj,
1024, 16, 20);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
INIT_APP_EXPORT(rt_can0_test);
#endif
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-05-11 Carl the first version
*/
#ifndef __DRV_CAN_H__
#define __DRV_CAN_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <board.h>
#include <rtdevice.h>
#include <rtthread.h>
#include "ft_can.h"
struct ft2004_can
{
const char *name;
FCan_t can_handle;
struct rt_semaphore recv_semaphore;
struct rt_can_device device; /* inherit from can device */
};
int rt_hw_can_init(void);
#ifdef __cplusplus
}
#endif
#endif // !
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-09 Carl the first version
*/
#include "board.h"
#include <netif/ethernetif.h>
#include "lwipopts.h"
#include "ft_parameters.h"
#include "ft_gmac.h"
#include "ft_cache.h"
#include "ft_gmac_hw.h"
#include "ft_status.h"
#include "ft_io.h"
#include "drv_eth.h"
#ifdef BSP_USING_GMAC
#define LOG_TAG "drv.gmac"
#include <drv_log.h>
#define MAX_ADDR_LEN 6
#define LINK_THREAD_STACK_LENGTH 0x400
struct drv_gmac
{
struct eth_device parent; /* inherit from ethernet device */
Ft_Gmac_t Gmac; /* Gmac driver */
#ifndef PHY_USING_INTERRUPT_MODE
rt_timer_t poll_link_timer;
#endif
rt_uint8_t *rx_buffer; /* Buffer for RxDesc */
rt_uint8_t *tx_buffer; /* Buffer for TxDesc */
uint32_t eth_speed; /* eth_speed */
uint32_t eth_mode; /* ETH_Duplex_Mode */
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* MAC address */
struct rt_event link_event;
struct rt_thread _link_thread;
rt_uint8_t _link_thread_stack[LINK_THREAD_STACK_LENGTH];
rt_thread_t _debug_tid;
};
static void rt_ft2004_status_check(void *Args, u32 MacPhyStatus);
//
#if defined(RAW_DATA_PRINT)
#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
{
unsigned char *buf = (unsigned char *)ptr;
int i, j;
for (i = 0; i < buflen; i += 16)
{
rt_kprintf("%08X: ", i);
for (j = 0; j < 16; j++)
if (i + j < buflen)
rt_kprintf("%02X ", buf[i + j]);
else
rt_kprintf(" ");
rt_kprintf(" ");
for (j = 0; j < 16; j++)
if (i + j < buflen)
rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
rt_kprintf("\n");
}
}
#endif
#endif
/**
* @name: rt_gmacmem_create
* @msg: Initialize the Gmac TX/Rx Describe Memory 。
* @param {*}
* @return {*}
*/
static void rt_gmacmem_create(struct drv_gmac *pOsGmac)
{
pOsGmac->rx_buffer = rt_calloc(1, RX_DESCNUM * GMAC_MAX_PACKET_SIZE);
if (pOsGmac->rx_buffer == NULL)
{
LOG_E("rx_buffer Malloc is error ");
RT_ASSERT(0)
}
pOsGmac->tx_buffer = rt_calloc(1, TX_DESCNUM * GMAC_MAX_PACKET_SIZE);
if (pOsGmac->tx_buffer == NULL)
{
LOG_E("tx_buffer Malloc is error ");
RT_ASSERT(0)
}
pOsGmac->Gmac.TxDesc = rt_calloc(1, TX_DESCNUM * sizeof(FGmac_DmaDesc_t));
if (pOsGmac->Gmac.TxDesc == NULL)
{
LOG_E("TxDesc Malloc is error ");
RT_ASSERT(0)
}
pOsGmac->Gmac.RxDesc = rt_calloc(1, RX_DESCNUM * sizeof(FGmac_DmaDesc_t) + 128);
if (pOsGmac->Gmac.RxDesc == NULL)
{
LOG_E("RxDesc Malloc is error ");
RT_ASSERT(0)
}
#define ROUND_UP(x, align) (((long)(x) + ((long)align - 1)) & \
~((long)align - 1))
pOsGmac->Gmac.RxDesc = (FGmac_DmaDesc_t *)ROUND_UP(pOsGmac->Gmac.RxDesc, 128);
LOG_D("RxDesc fit after addr %x ", pOsGmac->Gmac.RxDesc);
}
static void rt_gmacmem_free(struct drv_gmac *pOsGmac)
{
if (pOsGmac->rx_buffer)
{
rt_free(pOsGmac->rx_buffer);
}
if (pOsGmac->tx_buffer)
{
rt_free(pOsGmac->tx_buffer);
}
if (pOsGmac->Gmac.RxDesc)
{
rt_free(pOsGmac->Gmac.RxDesc);
}
if (pOsGmac->Gmac.TxDesc)
{
rt_free(pOsGmac->Gmac.TxDesc);
}
}
static void rt_hw_gmac_isr(int irqno, void *param)
{
FGmac_IntrHandler(param);
}
static void rt_hw_gmac_recv_isr(void *Args)
{
struct drv_gmac *pOsMac;
rt_err_t result = 0;
if (RT_NULL == Args)
{
LOG_E("Args is NULL");
return;
}
pOsMac = (struct drv_gmac *)Args;
result = eth_device_ready(&(pOsMac->parent));
if (result != RT_EOK)
{
LOG_I("RxCpltCallback err = %d", result);
}
}
static rt_err_t
rt_ft2004_gmac_start(struct drv_gmac *pOsMac)
{
Ft_Gmac_t *pGmac;
pGmac = &pOsMac->Gmac;
if (FST_SUCCESS != Ft_Gmac_HwInitialize(pGmac))
{
return -RT_ERROR;
}
FGmac_SetHandler(pGmac, FT_GMAC_RX_COMPLETE_CB_ID, rt_hw_gmac_recv_isr, pOsMac);
FGmac_SetHandler(pGmac, FT_GMAC_MAC_PHY_STATUS_CB_ID, rt_ft2004_status_check, pOsMac);
/* Initialize Rx Description list : ring Mode */
FGmac_DmaRxDescRingInit(pGmac, pGmac->RxDesc, pOsMac->rx_buffer, GMAC_MAX_PACKET_SIZE, RX_DESCNUM);
/* Initialize Tx Description list : ring Mode */
FGmac_DmaTxDescRingInit(pGmac, pGmac->TxDesc, pOsMac->tx_buffer, GMAC_MAX_PACKET_SIZE, TX_DESCNUM);
Ft_Gmac_Start(pGmac);
/* Gmac interrupt init */
rt_hw_interrupt_install(pGmac->Config.IRQ_NUM, rt_hw_gmac_isr, pGmac, "Gmac");
rt_hw_interrupt_umask(pGmac->Config.IRQ_NUM);
return RT_EOK;
}
void rt_ft2004_gmac_stop(struct drv_gmac *pOsMac)
{
Ft_Gmac_t *pGmac;
pGmac = &pOsMac->Gmac;
Ft_Gmac_Stop(pGmac);
}
/* GMAC initialization function */
static rt_err_t rt_ft2004_gmac_init(rt_device_t dev)
{
struct drv_gmac *pOsMac;
struct eth_device *pGmacParent;
FGmac_Config_t *pConfig;
pGmacParent = rt_container_of(dev, struct eth_device, parent);
if (NULL == pGmacParent)
{
return -RT_ENOMEM;
}
pOsMac = rt_container_of(pGmacParent, struct drv_gmac, parent);
if (NULL == pOsMac)
{
return -RT_ENOMEM;
}
pConfig = Ft_Gmac_LookupConfig(pOsMac->Gmac.Config.InstanceId);
if (NULL == pConfig)
{
return -RT_ENOMEM;
}
Ft_Gmac_UseDefaultMacAddr(&pOsMac->Gmac, pOsMac->Gmac.Config.MacAddr);
if (FST_SUCCESS != Ft_GmacCfgInitialize(&pOsMac->Gmac, pConfig))
{
return -RT_ERROR;
}
return rt_ft2004_gmac_start(pOsMac);
}
static rt_err_t rt_ft2004_gmac_open(rt_device_t dev, rt_uint16_t oflag)
{
LOG_D("gmac open");
return RT_EOK;
}
static rt_err_t rt_ft2004_gmac_close(rt_device_t dev)
{
LOG_D("gmac close");
return RT_EOK;
}
static rt_size_t rt_ft2004_gmac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
LOG_D("gmac read");
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_size_t rt_ft2004_gmac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
LOG_D("gmac write");
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t rt_ft2004_gmac_control(rt_device_t dev, int cmd, void *args)
{
struct drv_gmac *pOsMac;
struct eth_device *pGmacParent;
pGmacParent = rt_container_of(dev, struct eth_device, parent);
if (NULL == pGmacParent)
{
return -RT_ENOMEM;
}
pOsMac = rt_container_of(pGmacParent, struct drv_gmac, parent);
if (NULL == pOsMac)
{
return -RT_ENOMEM;
}
switch (cmd)
{
case NIOCTL_GADDR:
/* get mac address */
if (args)
rt_memcpy(args, pOsMac->dev_addr, 6);
else
return -RT_ERROR;
break;
default:
break;
}
return RT_EOK;
}
rt_err_t rt_ft2004_gmac_tx(rt_device_t dev, struct pbuf *p)
{
struct drv_gmac *pOsMac;
Ft_Gmac_t *pGmac;
struct eth_device *pGmacParent;
err_t errval;
struct pbuf *q;
u8 *Buffer = NULL;
volatile FGmac_DmaDesc_t *DmaTxDesc;
u32 FrameLength = 0;
u32 BufferOffset = 0;
u32 BytesLeftToCopy = 0;
u32 PayLoadOffset = 0;
pGmacParent = rt_container_of(dev, struct eth_device, parent);
if (NULL == pGmacParent)
{
return -RT_ENOMEM;
}
pOsMac = rt_container_of(pGmacParent, struct drv_gmac, parent);
if (NULL == pOsMac)
{
return -RT_ENOMEM;
}
pGmac = &pOsMac->Gmac;
DmaTxDesc = &pGmac->TxDesc[pGmac->TxDescRingData.DescBufIndex];
Buffer = (u8 *)DmaTxDesc->Buffer1Addr;
if (Buffer == NULL)
{
LOG_E("Buffer is NULL \r\n");
RT_ASSERT(0)
}
#if RT_LWIP_ETH_PAD_SIZE
pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
#endif
for (q = p; q != NULL; q = q->next)
{
/* Is this buffer available? If not, goto error */
if ((DmaTxDesc->Status & DMA_TDES0_OWN) != 0)
{
errval = ERR_USE;
LOG_E("error errval = ERR_USE; \r\n");
goto error;
}
/* Get bytes in current lwIP buffer */
BytesLeftToCopy = q->len;
PayLoadOffset = 0;
/* Check if the length of data to copy is bigger than Tx buffer size*/
while ((BytesLeftToCopy + BufferOffset) > GMAC_MAX_PACKET_SIZE)
{
/* Copy data to Tx buffer*/
memcpy((u8 *)((u8 *)Buffer + BufferOffset), (u8 *)((u8 *)q->payload + PayLoadOffset), (GMAC_MAX_PACKET_SIZE - BufferOffset));
FCache_cpuDcacheClean((rt_uint32_t *)DmaTxDesc->Buffer1Addr, GMAC_MAX_PACKET_SIZE);
GMAC_INC_DESC(pGmac->TxDescRingData.DescBufIndex, pGmac->TxDescRingData.DescMaxNumber);
/* Point to next descriptor */
DmaTxDesc = &pGmac->TxDesc[pGmac->TxDescRingData.DescBufIndex];
/* Check if the Bufferis available */
if ((DmaTxDesc->Status & DMA_TDES0_OWN) != (u32)0)
{
errval = ERR_USE;
LOG_E("Check if the Bufferis available \r\n");
goto error;
}
Buffer = (u8 *)(DmaTxDesc->Buffer1Addr);
BytesLeftToCopy = BytesLeftToCopy - (GMAC_MAX_PACKET_SIZE - BufferOffset);
PayLoadOffset = PayLoadOffset + (GMAC_MAX_PACKET_SIZE - BufferOffset);
FrameLength = FrameLength + (GMAC_MAX_PACKET_SIZE - BufferOffset);
BufferOffset = 0;
if (Buffer == NULL)
{
LOG_E(" error Buffer is 0 \r\n");
RT_ASSERT(0)
}
}
/* Copy the remaining bytes */
memcpy((u8 *)((u8 *)Buffer + BufferOffset), (u8 *)((u8 *)q->payload + PayLoadOffset), BytesLeftToCopy);
BufferOffset = BufferOffset + BytesLeftToCopy;
FrameLength = FrameLength + BytesLeftToCopy;
}
/* 指向下一个位置 */
FCache_cpuDcacheClean((rt_uint32_t *)DmaTxDesc->Buffer1Addr, GMAC_MAX_PACKET_SIZE);
GMAC_INC_DESC(pGmac->TxDescRingData.DescBufIndex, pGmac->TxDescRingData.DescMaxNumber);
#if RT_LWIP_ETH_PAD_SIZE
pbuf_header(p, RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#ifdef ETH_TX_DUMP
dump_hex(Buffer, p->tot_len);
#endif
FGmac_TransmitframeRingPoll(pGmac, FrameLength);
error:
FGmac_SetTransmitUnderflow(pGmac);
return errval;
}
struct pbuf *rt_ft2004_gmac_rx(rt_device_t dev)
{
struct drv_gmac *pOsMac;
Ft_Gmac_t *pGmac;
struct eth_device *pGmacParent;
struct pbuf *p = NULL;
struct pbuf *q = NULL;
u16 Length = 0;
u8 *Buffer;
volatile FGmac_DmaDesc_t *DmaRxDesc;
u32 BufferOffset = 0;
u32 PayLoadOffset = 0;
u32 BytesLeftToCopy = 0;
u32 DescBufIndex; /* For Current Desc buffer buf position */
pGmacParent = rt_container_of(dev, struct eth_device, parent);
if (NULL == pGmacParent)
{
return RT_NULL;
}
pOsMac = rt_container_of(pGmacParent, struct drv_gmac, parent);
if (NULL == pOsMac)
{
return RT_NULL;
}
pGmac = &pOsMac->Gmac;
/* get received frame */
if (FST_SUCCESS != FGmac_RingGetReceivedFrame_IT(pGmac))
{
return NULL;
}
DescBufIndex = pGmac->RxDescRingData.DescBufIndex;
Length = (pGmac->RxDesc[DescBufIndex].Status & DMA_RDES0_FRAME_LEN_MASK) >> DMA_RDES0_FRAME_LEN_SHIFT;
Buffer = (u8 *)pGmac->RxDesc[DescBufIndex].Buffer1Addr;
#if RT_LWIP_ETH_PAD_SIZE
Length += RT_LWIP_ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
if (Length > 0)
{
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
p = pbuf_alloc(PBUF_RAW, Length, PBUF_POOL);
}
#ifdef ETH_RX_DUMP
dump_hex(Buffer, (u32)Length);
#endif
if (p != NULL)
{
#if RT_LWIP_ETH_PAD_SIZE
pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
#endif
DmaRxDesc = &pGmac->RxDesc[DescBufIndex];
BufferOffset = 0;
for (q = p; q != NULL; q = q->next)
{
BytesLeftToCopy = q->len;
PayLoadOffset = 0;
/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
while ((BytesLeftToCopy + BufferOffset) > GMAC_MAX_PACKET_SIZE)
{
/* Copy data to pbuf */
memcpy((u8 *)((u8 *)q->payload + PayLoadOffset), (u8 *)((u8 *)Buffer + BufferOffset), (GMAC_MAX_PACKET_SIZE - BufferOffset));
/* Point to next descriptor */
GMAC_INC_DESC(DescBufIndex, pGmac->RxDescRingData.DescMaxNumber);
if (DescBufIndex == pGmac->RxDescRingData.DescIndex)
{
break;
}
DmaRxDesc = &pGmac->RxDesc[DescBufIndex];
Buffer = (u8 *)(DmaRxDesc->Buffer1Addr);
BytesLeftToCopy = BytesLeftToCopy - (GMAC_MAX_PACKET_SIZE - BufferOffset);
PayLoadOffset = PayLoadOffset + (GMAC_MAX_PACKET_SIZE - BufferOffset);
BufferOffset = 0;
}
/* Copy remaining data in pbuf */
memcpy((u8 *)((u8 *)q->payload + PayLoadOffset), (u8 *)((u8 *)Buffer + BufferOffset), BytesLeftToCopy);
BufferOffset = BufferOffset + BytesLeftToCopy;
}
#if RT_LWIP_ETH_PAD_SIZE
pbuf_header(p, RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
#endif
}
/* Release descriptors to DMA */
/* Point to first descriptor */
DmaRxDesc = &pGmac->RxDesc[DescBufIndex];
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
for (DescBufIndex = pGmac->RxDescRingData.DescBufIndex; DescBufIndex != pGmac->RxDescRingData.DescIndex; GMAC_INC_DESC(DescBufIndex, pGmac->RxDescRingData.DescMaxNumber))
{
FCache_cpuDcacheInvalidate((rt_uint32_t *)pGmac->RxDesc[DescBufIndex].Buffer1Addr, GMAC_MAX_PACKET_SIZE);
DmaRxDesc->Status |= DMA_RDES0_OWN;
DmaRxDesc = &pGmac->RxDesc[DescBufIndex];
}
/* Sync index */
pGmac->RxDescRingData.DescBufIndex = pGmac->RxDescRingData.DescIndex;
FGmac_ResumeTransmissionReception(pGmac);
return p;
}
static void rt_ft2004_status_check(void *Args, u32 MacPhyStatus)
{
struct drv_gmac *pOsMac;
pOsMac = (struct drv_gmac *)Args;
if (MacPhyStatus & 0x8)
{
rt_event_send(&pOsMac->link_event, FT_NETIF_LINKUP);
}
else
{
rt_event_send(&pOsMac->link_event, FT_NETIF_DOWN);
}
}
static void ethernet_link_thread(void *Args)
{
struct drv_gmac *pOsMac;
rt_uint32_t status;
u32 LastStatus = FT_NETIF_DOWN;
u32 Flg;
if (RT_NULL == Args)
{
return;
}
pOsMac = (struct drv_gmac *)Args;
while (1)
{
status = 0;
if (rt_event_recv(&pOsMac->link_event, FT_NETIF_LINKUP | FT_NETIF_DOWN, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &status) != RT_EOK)
{
LOG_E("wait completed timeout");
continue;
}
if (status & FT_NETIF_DOWN)
{
eth_device_linkchange(&pOsMac->parent, RT_FALSE);
LastStatus = FT_NETIF_DOWN;
}
else if (status & FT_NETIF_LINKUP)
{
Flg = (LastStatus == FT_NETIF_LINKUP) ? 0 : 1;
LastStatus = FT_NETIF_LINKUP;
}
else
{
LOG_I(" EventGroup is error \r\n");
RT_ASSERT(0)
}
if (Flg)
{
Flg = 0;
// eth_device_linkchange(&pOsMac->parent, RT_FALSE);
LOG_I(" Start Linkup \r\n");
rt_ft2004_gmac_stop(pOsMac);
rt_ft2004_gmac_start(pOsMac);
LOG_I(" HardWare is ok \r\n");
if (LastStatus == FT_NETIF_LINKUP)
{
rt_thread_mdelay(5000);
eth_device_linkchange(&pOsMac->parent, RT_TRUE);
}
}
}
}
#ifdef BSP_USING_GMAC0
struct drv_gmac os_drv_gmac0;
static char *os_drv_gmac0_name = "gmac0";
#endif
#ifdef BSP_USING_GMAC1
struct drv_gmac os_drv_gmac1;
static char *os_drv_gmac1_name = "gmac1";
#endif
static int rt_hw_gmac_init(struct drv_gmac *pOsMac, const char *name)
{
rt_err_t state = RT_EOK;
// rt_thread_t tid;
rt_gmacmem_free(pOsMac);
rt_gmacmem_create(pOsMac);
pOsMac->eth_speed = GMAC_SPEED_1000M;
pOsMac->eth_mode = GMAC_MODE_FULLDUPLEX;
pOsMac->parent.parent.init = rt_ft2004_gmac_init;
pOsMac->parent.parent.open = rt_ft2004_gmac_open;
pOsMac->parent.parent.close = rt_ft2004_gmac_close;
pOsMac->parent.parent.read = rt_ft2004_gmac_read;
pOsMac->parent.parent.write = rt_ft2004_gmac_write;
pOsMac->parent.parent.control = rt_ft2004_gmac_control;
pOsMac->parent.parent.user_data = RT_NULL;
pOsMac->parent.eth_rx = rt_ft2004_gmac_rx;
pOsMac->parent.eth_tx = rt_ft2004_gmac_tx;
Ft_Gmac_UseDefaultMacAddr(&pOsMac->Gmac, pOsMac->dev_addr);
state = rt_event_init(&pOsMac->link_event, name, RT_IPC_FLAG_FIFO);
LOG_I("rt_event_init is ok \r\n");
if (RT_EOK != state)
{
rt_kprintf("init gmac0 event failed.\n");
return -RT_ERROR;
}
/* register eth device */
state = eth_device_init(&(pOsMac->parent), name);
if (RT_EOK != state)
{
LOG_E("gmac device init faild: %d", state);
return -RT_ERROR;
}
state = rt_thread_init(&pOsMac->_link_thread,
name,
ethernet_link_thread,
pOsMac,
&pOsMac->_link_thread_stack[0],
sizeof(pOsMac->_link_thread_stack),
10, 2);
if (RT_EOK == state)
{
rt_thread_startup(&pOsMac->_link_thread);
}
else
{
LOG_E("rt_thread_init is error");
return -RT_ERROR;
}
return RT_EOK;
}
static int rt_hw_ft2004_eth_init(void)
{
rt_err_t state = RT_EOK;
#ifdef BSP_USING_GMAC0
os_drv_gmac0.Gmac.Config.InstanceId = 0;
state = rt_hw_gmac_init(&os_drv_gmac0, os_drv_gmac0_name);
if (RT_EOK != state)
{
goto __exit;
}
#endif
#ifdef BSP_USING_GMAC1
os_drv_gmac1.Gmac.Config.InstanceId = 1;
state = rt_hw_gmac_init(&os_drv_gmac1, os_drv_gmac1_name);
if (RT_EOK != state)
{
goto __exit;
}
#endif
__exit:
return state;
}
INIT_DEVICE_EXPORT(rt_hw_ft2004_eth_init);
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-09 Carl the first version
*/
#ifndef __DRV_ETH_H__
#define __DRV_ETH_H__
#ifdef __cplusplus
extern "C"
{
#endif
#define FT_NETIF_LINKUP 0x1U
#define FT_NETIF_DOWN 0x2U
#ifdef __cplusplus
}
#endif
#endif // !
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-11-15 SummerGift first version
*/
/*
* NOTE: DO NOT include this file on the header file.
*/
#ifndef LOG_TAG
#define DBG_TAG "drv"
#else
#define DBG_TAG LOG_TAG
#endif /* LOG_TAG */
#ifdef DRV_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif /* DRV_DEBUG */
#include <rtdbg.h>
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-11 Carl the first version
*/
#include "drv_qspi.h"
#include <rtthread.h>
#include "rtdevice.h"
#include "ft_qspi.h"
#include "ft_parameters.h"
#ifdef BSP_USE_QSPI
#define DRV_DEBUG
#define LOG_TAG "drv.qspi"
#include <drv_log.h>
struct ft2004_qspi_bus
{
FQSpi_t fqspi;
char *name;
rt_uint32_t init; /* 1 is init already */
};
static struct rt_spi_bus _qspi_bus;
static struct ft2004_qspi_bus _ft2004_qspi_bus;
static int ft2004_qspi_init(struct rt_qspi_device *device, struct rt_qspi_configuration *qspi_cfg)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(qspi_cfg != RT_NULL);
// struct rt_spi_configuration *cfg = &qspi_cfg->parent;
struct ft2004_qspi_bus *qspi_bus_p = device->parent.bus->parent.user_data;
if (qspi_bus_p->init == 0)
{
qspi_bus_p->init = 1;
FQSpi_CfgInitialize(&qspi_bus_p->fqspi, FQSpi_LookupConfig(0));
}
return RT_EOK;
}
static rt_err_t ft2004_cmdOperation(struct ft2004_qspi_bus *qspi_bus_p, struct rt_spi_message *message)
{
struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message;
const rt_uint8_t *sndb = message->send_buf;
rt_uint8_t *rcvb = message->recv_buf;
ft_error_t ret;
RT_ASSERT(qspi_bus_p != RT_NULL);
RT_ASSERT(message != RT_NULL);
struct FQSpi_CmdPack cmd_pack = {0};
if (qspi_message->instruction.qspi_lines == 0)
{
LOG_E("instruction is not valid");
return RT_ERROR;
}
cmd_pack.cmd = qspi_message->instruction.content;
if (qspi_message->address.qspi_lines != 0)
{
cmd_pack.flags |= FQSPI_CMD_NEED_ADDR_MASK;
cmd_pack.addr = qspi_message->address.content;
}
if (qspi_message->address.size == 24)
{
cmd_pack.flags |= FQSPI_CMD_ADDRESS_3BYTE_MASK;
}
else if (qspi_message->address.size == 32)
{
cmd_pack.flags |= FQSPI_CMD_ADDRESS_4BYTE_MASK;
}
if (qspi_message->qspi_data_lines != 0)
{
if (sndb && (message->length > 0))
{
cmd_pack.flags |= FQSPI_CMD_NEED_SET_MASK;
cmd_pack.txBuf = sndb;
cmd_pack.length = message->length;
}
else if (rcvb && (message->length > 0))
{
cmd_pack.flags |= FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rcvb;
cmd_pack.length = message->length;
}
else
{
cmd_pack.flags &= ~(FQSPI_CMD_NEED_GET_MASK | FQSPI_CMD_NEED_SET_MASK);
}
}
if (qspi_message->dummy_cycles)
{
cmd_pack.flags |= FQSPI_CMD_NEED_DUMMY_MASK;
cmd_pack.dummyCycle = qspi_message->dummy_cycles;
}
if (cmd_pack.cmd == 0x20)
{
if (qspi_message->address.size == 32)
{
cmd_pack.cmd = 0xdc;
}
}
#ifdef BSP_QSPI_DEBUG
LOG_I("flags %x", cmd_pack.flags);
#endif
ret = FQSpi_CmdOperation(&qspi_bus_p->fqspi, &cmd_pack);
#ifdef BSP_QSPI_DEBUG
if (ret == FQSPI_SUCCESS)
if (cmd_pack.cmd == 5)
{
LOG_I("cmd05 0x%x", cmd_pack.rxBuf[0]);
}
#endif
return (ret == FQSPI_SUCCESS) ? RT_EOK : RT_ERROR;
}
static rt_uint32_t ft2004_qspi_xfer(struct ft2004_qspi_bus *qspi_bus_p, struct rt_spi_message *message)
{
struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message;
rt_uint32_t ret_length = 0;
const rt_uint8_t *sndb = message->send_buf;
rt_uint8_t *rcvb = message->recv_buf;
rt_int32_t length = message->length;
rt_uint32_t cmd;
rt_uint32_t addr;
FQSpi_t *qspi_p;
FQSpi_Config_t *qspi_config_p;
struct FQSpi_DataPack data_pack = {0};
qspi_p = &qspi_bus_p->fqspi;
qspi_config_p = &qspi_bus_p->fqspi.config;
cmd = qspi_message->instruction.content;
addr = qspi_message->address.content;
#ifdef BSP_QSPI_DEBUG
LOG_I("cmd is %x ", cmd);
LOG_I("length %d , rcvb %x sndb %x addr %x dummy_cycles %x ", length, rcvb, sndb, addr, qspi_message->dummy_cycles);
#endif
if (qspi_config_p->channel >= FT_QSPI_MAX_CS_NUM)
{
LOG_E("invalid channel[%x] ", qspi_config_p->channel);
return RT_ERROR;
}
switch (cmd)
{
case FQSPI_FLASH_CMD_PP:
{
if (RT_NULL != sndb)
{
data_pack.cmd = cmd;
data_pack.addr = addr;
if (qspi_message->address.size == 24)
{
data_pack.flags |= FQSPI_DATA_ADDRESS_3BYTE_MASK;
}
else
{
data_pack.flags |= FQSPI_DATA_ADDRESS_4BYTE_MASK;
}
LOG_E("write flags %x ", data_pack.flags);
data_pack.txBuf = sndb;
data_pack.length = length;
ret_length = ((FQSpi_Write(qspi_p, &data_pack) == FQSPI_SUCCESS) ? length : 0);
}
else
{
LOG_E("pp cmd %x sndb is null", cmd);
ret_length = 0;
}
}
break;
case FQSPI_FLASH_CMD_WRDI: /* for sufd qspi fast read */
FQSpi_FlashRegSet(qspi_p, cmd, RT_NULL, 0);
case FQSPI_FLASH_CMD_READ:
{
if (RT_NULL != rcvb)
{
data_pack.cmd = FQSPI_FLASH_CMD_READ;
data_pack.addr = addr;
if (qspi_message->address.size == 24)
{
data_pack.flags |= FQSPI_DATA_ADDRESS_3BYTE_MASK;
}
else
{
data_pack.flags |= FQSPI_DATA_ADDRESS_4BYTE_MASK;
}
if (qspi_message->dummy_cycles)
{
data_pack.flags |= FQSPI_DATA_NEED_DUMMY_MASK;
data_pack.dummyCycle = qspi_message->dummy_cycles;
}
data_pack.rxBuf = rcvb;
data_pack.length = length;
ret_length = ((FQSpi_Read(qspi_p, &data_pack) == FQSPI_SUCCESS) ? length : 0);
}
else
{
// LOG_E("read cmd %x rcvb is null", cmd);
ret_length = 0;
}
}
break;
default:
{
if (ft2004_cmdOperation(qspi_bus_p, message) == RT_EOK)
{
ret_length = 1;
}
else
{
LOG_E("ft2004_cmdOperation error");
ret_length = 0;
}
}
}
return ret_length;
}
static rt_uint32_t qspixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
struct ft2004_qspi_bus *qspi_bus_p = device->bus->parent.user_data;
return ft2004_qspi_xfer(qspi_bus_p, message);
}
static rt_err_t qspi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device;
return ft2004_qspi_init(qspi_device, &qspi_device->config);
}
static const struct rt_spi_ops ft2004_qspi_ops =
{
.configure = qspi_configure,
.xfer = qspixfer,
};
static int ft2004_qspi_register_bus(struct ft2004_qspi_bus *qspi_bus, const char *name)
{
RT_ASSERT(qspi_bus != RT_NULL);
RT_ASSERT(name != RT_NULL);
_qspi_bus.parent.user_data = qspi_bus;
return rt_qspi_bus_register(&_qspi_bus, name, &ft2004_qspi_ops);
}
rt_err_t ft2004_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)())
{
struct rt_qspi_device *qspi_device = RT_NULL;
rt_err_t result = RT_EOK;
RT_ASSERT(bus_name != RT_NULL);
RT_ASSERT(device_name != RT_NULL);
RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
if (qspi_device == RT_NULL)
{
LOG_E("no memory, qspi bus attach device failed!");
result = RT_ENOMEM;
goto __exit;
}
qspi_device->enter_qspi_mode = enter_qspi_mode;
qspi_device->exit_qspi_mode = exit_qspi_mode;
qspi_device->config.qspi_dl_width = data_line_width;
result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, RT_NULL);
__exit:
if (result != RT_EOK)
{
if (qspi_device)
{
rt_free(qspi_device);
}
}
return result;
}
static int rt_hw_qspi_bus_init(void)
{
return ft2004_qspi_register_bus(&_ft2004_qspi_bus, FT2004_QSPI_NAME);
}
INIT_BOARD_EXPORT(rt_hw_qspi_bus_init);
#ifdef BSP_QSPI_DEBUG
static void cmd05_check(void)
{
struct FQSpi_CmdPack cmd_pack = {0};
u8 rx_buffer[1];
cmd_pack.cmd = 0x6;
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x5;
cmd_pack.flags = FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rx_buffer;
cmd_pack.length = sizeof(rx_buffer);
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
for (u32 i = 0; i < cmd_pack.length; i++)
{
LOG_I("cnt %d, 0x%x ", i, rx_buffer[i]);
}
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x4;
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x5;
cmd_pack.flags = FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rx_buffer;
cmd_pack.length = sizeof(rx_buffer);
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
for (u32 i = 0; i < cmd_pack.length; i++)
{
LOG_I("cnt %d, 0x%x ", i, rx_buffer[i]);
}
}
MSH_CMD_EXPORT_ALIAS(cmd05_check, cmd05_check, cmd05_check);
#endif
#ifdef BSP_QSPI_DEBUG
static void cmd35_check(void)
{
struct FQSpi_CmdPack cmd_pack = {0};
u8 rx_buffer[1];
cmd_pack.cmd = 0x6;
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x5;
cmd_pack.flags = FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rx_buffer;
cmd_pack.length = sizeof(rx_buffer);
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
for (u32 i = 0; i < cmd_pack.length; i++)
{
LOG_I("cnt %d, 0x%x ", i, rx_buffer[i]);
}
cmd_pack.cmd = 0xB7;
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x35;
cmd_pack.flags = FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rx_buffer;
cmd_pack.length = sizeof(rx_buffer);
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
for (u32 i = 0; i < cmd_pack.length; i++)
{
LOG_I("cnt %d, 0x%x ", i, rx_buffer[i]);
}
}
MSH_CMD_EXPORT_ALIAS(cmd35_check, cmd35_check, cmd35_check);
#endif
#ifdef BSP_QSPI_DEBUG
static void cmd15_check(void)
{
struct FQSpi_CmdPack cmd_pack = {0};
u8 rx_buffer[1];
// cmd_pack.cmd = 0xB7;
// FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
rt_memset(&cmd_pack, 0, sizeof(&cmd_pack));
cmd_pack.cmd = 0x15;
cmd_pack.flags = FQSPI_CMD_NEED_GET_MASK;
cmd_pack.rxBuf = rx_buffer;
cmd_pack.length = sizeof(rx_buffer);
FQSpi_CmdOperation(&_ft2004_qspi_bus.fqspi, &cmd_pack);
for (u32 i = 0; i < cmd_pack.length; i++)
{
LOG_I("cnt %d, 0x%x ", i, rx_buffer[i]);
}
}
MSH_CMD_EXPORT_ALIAS(cmd15_check, cmd15_check, cmd15_check);
#endif
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-11 Carl the first version
*/
#ifndef __DRT_QSPI_H__
#define __DRT_QSPI_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define FT2004_QSPI_NAME "qspi"
rt_err_t ft2004_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)());
#ifdef __cplusplus
}
#endif
#endif // !DRT_QSPI_H
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-08 Carl the first version
*/
#include <board.h>
#include <drv_qspi.h>
#include <rtdevice.h>
#include <rthw.h>
#include <finsh.h>
#ifdef BSP_USE_QSPI
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#define _QSPI_DEVICE_NAME "qspiflash"
static int
rt_hw_qspi_flash_with_sfud_init(void)
{
ft2004_qspi_bus_attach_device(FT2004_QSPI_NAME, _QSPI_DEVICE_NAME, 1, RT_NULL, RT_NULL);
/* init gd */
rt_kprintf("start rt_sfud_flash_probe \r\n");
if (RT_NULL == rt_sfud_flash_probe("GD25LQ256D", _QSPI_DEVICE_NAME))
{
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_qspi_flash_with_sfud_init);
#endif /* BSP_USING_QSPI_FLASH */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-18 Carl the first version
*/
#include <rtthread.h>
#ifdef BSP_USING_SDC
#include <dfs_elm.h>
#include <dfs_fs.h>
#include <dfs_posix.h>
#include "drv_sdctrl.h"
#define DBG_TAG "app.card"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static rt_err_t _sdcard_mount(void)
{
rt_device_t device;
device = rt_device_find("sd0");
rt_kprintf("rt_device_find %x \r\n", device);
if (device == NULL)
{
mmcsd_wait_cd_changed(0);
ft2004_mmcsd_change();
if (mmcsd_wait_cd_changed(rt_tick_from_millisecond(5000)) == -RT_ETIMEOUT)
{
rt_kprintf("timeout \r\n");
return RT_ERROR;
}
device = rt_device_find("sd0");
}
rt_thread_mdelay(1000);
LOG_I("dfs_mount \r\n");
if (device != RT_NULL)
{
if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK)
{
LOG_I("sd card mount to '/'");
}
else
{
LOG_W("sd card mount to '/' failed!");
return RT_ERROR;
}
}
return RT_EOK;
}
static void _sdcard_unmount(void)
{
rt_thread_mdelay(200);
dfs_unmount("/");
LOG_I("Unmount \"/\"");
mmcsd_wait_cd_changed(0);
ft2004_mmcsd_change();
mmcsd_wait_cd_changed(rt_tick_from_millisecond(5000));
LOG_I("Unmount is over \r\n");
}
static void sd_mount(void *parameter)
{
rt_uint8_t state = 0; /* 1. is valid card ,0 is removal */
#ifdef BSP_SDC_IRQ_CARD_REMOVE
rt_uint32_t status;
#endif
while (1)
{
switch (state)
{
case 0:
if (ft2004_card_status() == 1)
{
#ifdef BSP_SDC_IRQ_CARD_REMOVE
ft2004_card_remove_check(0, RT_NULL); /* Clear removal flag bit */
#endif
if (_sdcard_mount() == RT_EOK)
{
state = 1;
}
else
{
/* For the critical case of frequent plug */
rt_kprintf("dfs_unmount \r\n");
_sdcard_unmount();
ft2004_sdctrl_reset();
}
}
else
{
rt_thread_mdelay(100);
}
break;
case 1:
#ifdef BSP_SDC_IRQ_CARD_REMOVE
if (ft2004_card_remove_check(RT_WAITING_FOREVER, &status) == RT_EOK)
{
if (status & SDCTR_CARD_REMOVE_FLG)
{
state = 0;
_sdcard_unmount();
}
}
#else
if (ft2004_card_status() == 0)
{
state = 0;
_sdcard_unmount();
}
#endif
else
{
rt_thread_mdelay(100);
}
break;
default:
state = 0;
break;
}
}
}
int ft2004_sdcard_mount(void)
{
rt_thread_t tid;
tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
8192, 2, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_E("create sd_mount thread err!");
}
return RT_EOK;
}
INIT_APP_EXPORT(ft2004_sdcard_mount);
#endif /* BSP_USING_SDCARD */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-18 Carl the first version
*/
#include "drv_sdctrl.h"
#include "ft_sdctrl_hw.h"
#include "ft_sdctrl.h"
#include "ft_debug.h"
#include "ft_types.h"
#include "ft_generic_timer.h"
#include <drivers/mmcsd_core.h>
#include "interrupt.h"
#include "rtconfig.h"
#include "ft_cache.h"
#ifdef BSP_USING_SDC
#define LOG_TAG "drv.sdmmc"
#include <drv_log.h>
#define RTHW_SDCTRL_LOCK(_sdctrl) rt_mutex_take(&_sdctrl->mutex, RT_WAITING_FOREVER)
#define RTHW_SDCTRL_UNLOCK(_sdctrl) rt_mutex_release(&_sdctrl->mutex);
struct mmcsd_pkg
{
struct rt_mmcsd_cmd *cmd;
void *buff;
rt_uint32_t flag;
};
typedef struct
{
FtsdCtrl_t ft_sdctrl;
struct rt_mmcsd_host *host;
struct rt_event event;
struct rt_mutex mutex;
struct mmcsd_pkg *pkg;
} ft_sdctrl_class_t;
ft_sdctrl_class_t sdctrl_class;
ALIGN(SDCTR_ALIGN_LEN)
static rt_uint8_t cache_buf[SDCTR_BUFF_SIZE];
static void rthw_sdctrl_send_command(ft_sdctrl_class_t *class_p, struct mmcsd_pkg *pkg);
static void demo_dump_sdc(void)
{
Ft_DumpHexWord((const rt_uint32_t *)(0x28207C00), 256);
}
MSH_CMD_EXPORT_ALIAS(demo_dump_sdc, dump_sdc, output all dump_sdc);
static void rthw_sdctrl_delay(u32 delayCnt)
{
Ft_GenericTimer_UsDelay(delayCnt);
}
static u32 rthw_sdctrl_rasp2type(u32 rasp)
{
switch (rasp)
{
case RESP_NONE:
return FTSDCTRL_CMD_RES_NONE;
case RESP_R2:
return FTSDCTRL_CMD_RES_LONG;
default:
return FTSDCTRL_CMD_RES_SHORT;
}
return FTSDCTRL_CMD_RES_SHORT;
}
static void rthw_sdctrl_transfer_by_dma(ft_sdctrl_class_t *class_p, struct mmcsd_pkg *pkg)
{
struct rt_mmcsd_data *data;
struct rt_mmcsd_cmd *cmd;
u32 rasp;
u32 *buff;
FtsdCtrl_t *ft_sdctrl_p;
if ((RT_NULL == class_p))
{
LOG_E("rthw_sdctrl_transfer_by_dma invalid class_p");
return;
}
ft_sdctrl_p = &class_p->ft_sdctrl;
if ((RT_NULL == pkg))
{
LOG_E("rthw_sdctrl_transfer_by_dma invalid args");
return;
}
data = pkg->cmd->data;
if (RT_NULL == data)
{
LOG_E("rthw_sdctrl_transfer_by_dma invalid args");
return;
}
buff = pkg->buff;
if (RT_NULL == buff)
{
LOG_E("rthw_sdctrl_transfer_by_dma invalid args");
return;
}
cmd = pkg->cmd;
rasp = resp_type(pkg->cmd);
rasp = rthw_sdctrl_rasp2type(rasp);
if (data->flags & DATA_DIR_WRITE)
{
#ifdef BSP_SDC_DEBUG_PRINT
rt_kprintf("DATA_DIR_WRITE %x \r\n", cmd->arg);
#endif
FCache_cpuDcacheClean(buff, data->blks * data->blksize);
/* data, card, blk: card : data + blk */
FSdCtrl_WriteData(ft_sdctrl_p, (UINTPTR)buff, cmd->arg, data->blks);
cmd->err = FSdCtrl_WaitCmdEnd(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay, rasp, cmd->resp);
#ifdef BSP_SDC_DEBUG_PRINT
for (int i = 0; i < 4; i++)
{
rt_kprintf("cmdRsp[%d] %x \r\n", i, cmd->resp[i]);
}
Ft_DumpHexWord(buff, 256);
#endif
FSdCtrl_WaitWriteDataEnd(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay, data->blks);
FCache_cpuDcacheInvalidate(buff, data->blks * data->blksize);
}
else if (data->flags & DATA_DIR_READ)
{
#ifdef BSP_SDC_DEBUG_PRINT
rt_kprintf("DATA_DIR_READ %x \r\n", cmd->arg);
#endif
if ((cmd->flags & CMD_ADTC) && (data->blksize < 512))
{
#ifdef BSP_SDC_DEBUG_PRINT
LOG_E("CMD_ADTC \r\n");
#endif
FSdCtrl_DoACmd(ft_sdctrl_p, cmd->cmd_code, rasp, cmd->arg);
rt_thread_mdelay(10);
}
FCache_cpuDcacheInvalidate(buff, data->blks * data->blksize);
FSdCtrl_ReadData(ft_sdctrl_p, (UINTPTR)buff, cmd->arg, data->blks);
cmd->err = FSdCtrl_WaitCmdEnd(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay, rasp, cmd->resp);
#ifdef BSP_SDC_DEBUG_PRINT
for (int i = 0; i < 4; i++)
{
rt_kprintf("cmdRsp[%d] %x \r\n", i, cmd->resp[i]);
}
#endif
FSdCtrl_WaitReadDataEnd(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay, data->blks);
FCache_cpuDcacheClean(buff, data->blks * data->blksize);
#ifdef BSP_SDC_DEBUG_PRINT
Ft_DumpHexWord(buff, data->blks * data->blksize);
#endif
}
}
static void rthw_sdctrl_docmd(ft_sdctrl_class_t *class_p, struct mmcsd_pkg *pkg)
{
struct rt_mmcsd_cmd *cmd;
u32 rasp;
FtsdCtrl_t *ft_sdctrl_p;
if ((RT_NULL == class_p))
{
LOG_E("rthw_sdctrl_docmd invalid class_p");
return;
}
ft_sdctrl_p = &class_p->ft_sdctrl;
if ((RT_NULL == pkg))
{
LOG_E("rthw_sdctrl_docmd invalid args");
return;
}
cmd = pkg->cmd;
rasp = resp_type(pkg->cmd);
rasp = rthw_sdctrl_rasp2type(rasp);
FSdCtrl_DoCmd(ft_sdctrl_p, pkg->cmd->cmd_code, rasp, cmd->arg);
cmd->err = FSdCtrl_WaitCmdEnd(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay, rasp, cmd->resp);
#ifdef BSP_SDC_DEBUG_PRINT
for (int i = 0; i < 4; i++)
{
rt_kprintf("cmdRsp[%d] %x \r\n", i, cmd->resp[i]);
}
#endif
}
static void rthw_sdctrl_send_command(ft_sdctrl_class_t *class_p, struct mmcsd_pkg *pkg)
{
struct rt_mmcsd_cmd *cmd = pkg->cmd;
struct rt_mmcsd_data *data = cmd->data;
/* save pkg */
class_p->pkg = pkg;
/* config data reg */
if (data != RT_NULL && data->blks)
{
/* transfer config */
rthw_sdctrl_transfer_by_dma(class_p, pkg);
}
else
{
rthw_sdctrl_docmd(class_p, pkg);
}
}
/**
* @brief This function send sdio request.
* @param host rt_mmcsd_host
* @param req request
* @retval None
*/
static void rthw_sdctrl_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
{
struct mmcsd_pkg pkg;
ft_sdctrl_class_t *class_p = host->private_data;
struct rt_mmcsd_data *data;
RTHW_SDCTRL_LOCK(class_p);
if (req->cmd != RT_NULL)
{
rt_memset(&pkg, 0, sizeof(pkg));
data = req->cmd->data;
pkg.cmd = req->cmd;
if (pkg.cmd->cmd_code == 5 || pkg.cmd->cmd_code == 1)
{
rt_kprintf("cmd_code is not vaild %x \r\n", pkg.cmd->cmd_code);
pkg.cmd->err = RT_EINVAL;
goto _exit;
}
#ifdef BSP_SDC_DEBUG_PRINT
struct rt_mmcsd_cmd *cmd;
cmd = req->cmd;
LOG_E("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
cmd->cmd_code,
cmd->arg,
resp_type(cmd) == RESP_NONE ? "NONE" : "",
resp_type(cmd) == RESP_R1 ? "R1" : "",
resp_type(cmd) == RESP_R1B ? "R1B" : "",
resp_type(cmd) == RESP_R2 ? "R2" : "",
resp_type(cmd) == RESP_R3 ? "R3" : "",
resp_type(cmd) == RESP_R4 ? "R4" : "",
resp_type(cmd) == RESP_R5 ? "R5" : "",
resp_type(cmd) == RESP_R6 ? "R6" : "",
resp_type(cmd) == RESP_R7 ? "R7" : "",
data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
data ? data->blks * data->blksize : 0,
data ? data->blksize : 0);
#endif
if (data != RT_NULL)
{
rt_uint32_t size = data->blks * data->blksize;
RT_ASSERT(size <= SDCTR_BUFF_SIZE);
pkg.buff = data->buf;
if ((rt_uint32_t)data->buf & (SDCTR_ALIGN_LEN - 1))
{
pkg.buff = cache_buf;
if (data->flags & DATA_DIR_WRITE)
{
rt_memcpy(cache_buf, data->buf, size);
}
}
}
rthw_sdctrl_send_command(class_p, &pkg);
if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDCTR_ALIGN_LEN - 1)))
{
rt_memcpy(data->buf, cache_buf, data->blksize * data->blks);
}
}
if (req->stop != RT_NULL)
{
rt_memset(&pkg, 0, sizeof(pkg));
pkg.cmd = req->stop;
rthw_sdctrl_send_command(class_p, &pkg);
}
_exit:
RTHW_SDCTRL_UNLOCK(class_p);
mmcsd_req_complete(class_p->host);
}
static void rthw_sdctrl_clk_divider(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
{
ft_sdctrl_class_t *class_p = host->private_data;
FtsdCtrl_t *sd_ctrl = &(class_p->ft_sdctrl);
/* bus mode is pull push */
FSdCtrl_ClkFreqSetup(sd_ctrl, io_cfg->clock);
return;
}
static void rthw_sdctrl_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
{
ft_sdctrl_class_t *class_p = host->private_data;
RTHW_SDCTRL_LOCK(class_p);
/* calculate and set clk divider */
rthw_sdctrl_clk_divider(host, io_cfg);
RTHW_SDCTRL_UNLOCK(class_p);
}
rt_int32_t rthw_sdctrl_detect(struct rt_mmcsd_host *host)
{
ft_sdctrl_class_t *class_p = host->private_data;
return FSdCtrl_CardDetect(&class_p->ft_sdctrl);
}
static const struct rt_mmcsd_host_ops ops =
{
rthw_sdctrl_request,
rthw_sdctrl_iocfg,
rthw_sdctrl_detect,
RT_NULL,
};
void rthw_sdctrl_nomarl_callback(void *args)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)args;
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
status = FSdCtrl_GetNormalIrqStatus(pFtsdCtrl);
if (status & NORMAL_INT_STATUS_CR)
{
rt_event_send(&class_p->event, SDCTR_CARD_REMOVE_FLG);
}
else if (status & NORMAL_INT_STATUS_CC)
{
rt_event_send(&class_p->event, SDCTR_CMD_IS_COMPLETE_FLG);
}
else if (status & NORMAL_INT_STATUS_EI)
{
rt_event_send(&class_p->event, SDCTR_CMD_IS_ERROR_FLG);
}
return;
}
void rthw_sdctrl_dma_callback(void *args)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)args;
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
status = FSdCtrl_GetDataIrqStatus(pFtsdCtrl);
if (status & BD_ISR_REG_TRS)
{
/* send write complete event */
rt_event_send(&class_p->event, SDCTR_WRITE_IS_COMPLETE_FLG);
}
if (status & BD_ISR_REG_RESPE)
{
/* send read complete event */
rt_event_send(&class_p->event, SDCTR_READ_IS_COMPLETE_FLG);
}
if (status & BD_ISR_REG_DAIS)
{
/* send dma errror event */
rt_event_send(&class_p->event, SDCTR_DMA_IS_ERROR_FLG);
}
}
void rthw_sdctrl_error_callback(void *args)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)args;
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
status = FSdCtrl_GetErrorIrqStatus(pFtsdCtrl);
if (status & SDCTR_CMD_TIMEOUT_FLG)
{
rt_event_send(&class_p->event, SDCTR_CMD_TIMEOUT_FLG);
}
if (status & ERROR_INT_EN_CNR)
{
rt_event_send(&class_p->event, SDCTR_CMD_RECEIVE_IS_ERROR_FLG);
}
if (status & ERROR_INT_EN_CCRCE)
{
rt_event_send(&class_p->event, SDCTR_CMD_CRC_IS_ERROR_FLG);
}
}
void rthw_sdctrl_normal_irq(int vector, void *param)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)param;
FSdCtrl_NormalIrq(pFtsdCtrl);
}
void rthw_sdctrl_dma_irq(int vector, void *param)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)param;
FSdCtrl_DmaIrq(pFtsdCtrl);
}
void rthw_sdctrl_err_irq(int vector, void *param)
{
FtsdCtrl_t *pFtsdCtrl = (FtsdCtrl_t *)param;
FSdCtrl_ErrIrq(pFtsdCtrl);
}
ft_error_t rthw_sdctrl_cmd_wait(FtsdCtrl_t *pFtsdCtrl)
{
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return FTSDC_INVALID_PARAM;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
if (rt_event_recv(&class_p->event, SDCTR_CMD_IS_COMPLETE_FLG | SDCTR_CMD_IS_ERROR_FLG | SDCTR_CMD_CRC_IS_ERROR_FLG, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR,
rt_tick_from_millisecond(50000), &status) != RT_EOK)
{
/* wait cmd completed timeout */
LOG_E("wait cmd completed timeout");
return FTSDC_TIMEOUT;
}
if (SDCTR_CMD_IS_COMPLETE_FLG == (status & SDCTR_CMD_IS_COMPLETE_FLG))
{
return FTSDC_SUCCESS;
}
else
{
LOG_E("wait cmd is error %x ", status);
return FTSDC_FAILURE;
}
}
ft_error_t rthw_sdctrl_read_wait(FtsdCtrl_t *pFtsdCtrl)
{
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return FTSDC_INVALID_PARAM;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
if (rt_event_recv(&class_p->event, SDCTR_READ_IS_COMPLETE_FLG | SDCTR_CMD_RECEIVE_IS_ERROR_FLG,
RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR,
rt_tick_from_millisecond(50000), &status) != RT_EOK)
{
/* wait read completed timeout */
LOG_E("wait read completed timeout");
return FTSDC_TIMEOUT;
}
if (SDCTR_READ_IS_COMPLETE_FLG == (status & SDCTR_READ_IS_COMPLETE_FLG))
{
return FTSDC_SUCCESS;
}
else
{
LOG_E("wait read is error %x ", status);
return FTSDC_FAILURE;
}
}
ft_error_t rthw_sdctrl_write_wait(FtsdCtrl_t *pFtsdCtrl)
{
rt_uint32_t status;
ft_sdctrl_class_t *class_p;
if (RT_NULL == pFtsdCtrl)
{
return FTSDC_INVALID_PARAM;
}
class_p = rt_container_of(pFtsdCtrl, ft_sdctrl_class_t, ft_sdctrl);
if (rt_event_recv(&class_p->event, SDCTR_WRITE_IS_COMPLETE_FLG, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR,
rt_tick_from_millisecond(50000), &status) != RT_EOK)
{
/* wait write completed timeout */
LOG_E("wait write completed timeout");
return FTSDC_TIMEOUT;
}
if (SDCTR_WRITE_IS_COMPLETE_FLG == (status & SDCTR_WRITE_IS_COMPLETE_FLG))
{
return FTSDC_SUCCESS;
}
else
{
LOG_E("wait write is error %x ", status);
return FTSDC_FAILURE;
}
}
static rt_err_t rthw_sdctrl_create(ft_sdctrl_class_t *class_p)
{
struct rt_mmcsd_host *host;
host = mmcsd_alloc_host();
if (host == RT_NULL)
{
LOG_E("L:%d F:%s mmcsd alloc host fail");
return RT_ENOMEM;
}
class_p->ft_sdctrl.config = *(FSdCtrl_Config_t *)FSdCtrl_LookupConfig(0);
rt_event_init(&class_p->event, "sdctrl", RT_IPC_FLAG_FIFO);
rt_mutex_init(&class_p->mutex, "sdctrl", RT_IPC_FLAG_FIFO);
class_p->host = host;
host->ops = &ops;
/* range of sd work speed */
host->freq_min = 400 * 1000;
host->freq_max = 48 * 1000000;
host->valid_ocr = 0X00FFFF80; /* The voltage range supported is 1.65v-3.6v */
host->flags = MMCSD_BUSWIDTH_4;
host->private_data = class_p;
/* ready to change */
return RT_EOK;
}
int rthw_sdctrl_init(void)
{
FtsdCtrl_t *ft_sdctrl_p;
#ifdef BSP_SDC_USE_IRQ
FSdCtrl_Config_t *config_p;
FSdCtrl_NormalIrqSelect_t normalIrqFlgs = 0;
#endif
rt_kprintf("rthw_sdctrl_init \r\n");
RT_ASSERT(rthw_sdctrl_create(&sdctrl_class) == RT_EOK);
ft_sdctrl_p = &sdctrl_class.ft_sdctrl;
FSdCtrl_Reset(ft_sdctrl_p, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay);
FsdCtrl_Init(ft_sdctrl_p);
#ifdef BSP_SDC_USE_IRQ
config_p = &ft_sdctrl_p->config;
#ifdef BSP_SDC_IRQ_CARD_REMOVE
normalIrqFlgs |= NORMAL_IRQ_CR;
#endif
normalIrqFlgs |= NORMAL_IRQ_CC;
/* register handler、irq enable bit and wait callback */
FSdCtrl_SetHandler(ft_sdctrl_p, FTSDCTRL_CMDIRQID, rthw_sdctrl_nomarl_callback, ft_sdctrl_p);
FSdCtrl_NormalIrqSet(ft_sdctrl_p, normalIrqFlgs);
FSdCtrl_CmdWaitRegister(ft_sdctrl_p, rthw_sdctrl_cmd_wait);
FSdCtrl_SetHandler(ft_sdctrl_p, FTSDCTRL_DMADATAIRQID, rthw_sdctrl_dma_callback, ft_sdctrl_p);
FSdCtrl_BdIrqSet(ft_sdctrl_p, BD_IRQ_TRS | BD_IRQ_RESPE);
FSdCtrl_WriteWaitRegister(ft_sdctrl_p, rthw_sdctrl_write_wait);
FSdCtrl_ReadWaitRegister(ft_sdctrl_p, rthw_sdctrl_read_wait);
config_p->workMode = FTSDCTRL_CMD_IRQ_MASK | FTSDCTRL_DATA_WRITE_IRQ_MASK | FTSDCTRL_DATA_READ_IRQ_MASK;
#else
#endif
/* install normal irq */
rt_hw_interrupt_install(ft_sdctrl_p->config.normalIrqNum, rthw_sdctrl_normal_irq,
&sdctrl_class.ft_sdctrl, "normalIrq");
rt_hw_interrupt_umask(ft_sdctrl_p->config.normalIrqNum);
rt_hw_interrupt_install(ft_sdctrl_p->config.dmaIrqNum, rthw_sdctrl_dma_irq,
&sdctrl_class.ft_sdctrl, "dmaIrq");
rt_hw_interrupt_umask(ft_sdctrl_p->config.dmaIrqNum);
return 0;
}
INIT_DEVICE_EXPORT(rthw_sdctrl_init);
void ft2004_mmcsd_change(void)
{
mmcsd_change(sdctrl_class.host);
}
rt_bool_t ft2004_card_status(void)
{
return FSdCtrl_CardDetect(&sdctrl_class.ft_sdctrl);
}
rt_err_t ft2004_card_remove_check(rt_int32_t timeout, rt_uint32_t *status)
{
return rt_event_recv(&sdctrl_class.event, SDCTR_CARD_REMOVE_FLG, RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_OR,
timeout, status);
}
void ft2004_sdctrl_reset(void)
{
FSdCtrl_Reset(&sdctrl_class.ft_sdctrl, (pFtsdCtrl_delayTimer_t)rthw_sdctrl_delay);
FsdCtrl_Init(&sdctrl_class.ft_sdctrl);
#ifdef BSP_SDC_USE_IRQ
FSdCtrl_NormalIrqSet(&sdctrl_class.ft_sdctrl, NORMAL_IRQ_CC | NORMAL_IRQ_CR | NORMAL_IRQ_EI);
FSdCtrl_BdIrqSet(&sdctrl_class.ft_sdctrl, BD_IRQ_TRS | BD_IRQ_RESPE);
#endif
}
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-18 Carl the first version
*/
#ifndef __DRV_SDCTRL_H__
#define __DRV_SDCTRL_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define SDCTR_CMD_IS_COMPLETE_FLG 0x1UL /* Command is complete */
#define SDCTR_WRITE_IS_COMPLETE_FLG 0x2UL
#define SDCTR_READ_IS_COMPLETE_FLG 0x4UL
#define SDCTR_CMD_IS_ERROR_FLG 0x8UL
#define SDCTR_CMD_CRC_IS_ERROR_FLG 0x10UL /* Command CRC error */
#define SDCTR_DMA_IS_ERROR_FLG 0x20UL /* */
#define SDCTR_CARD_REMOVE_FLG 0x40UL /* Card remove */
#define SDCTR_CMD_TIMEOUT_FLG 0x70UL /* command timeout */
#define SDCTR_CMD_RECEIVE_IS_ERROR_FLG 0x80UL /* CMD receive is error */
#ifndef SDCTR_BUFF_SIZE
#define SDCTR_BUFF_SIZE (512 * 128)
#endif
#ifndef SDCTR_ALIGN_LEN
#define SDCTR_ALIGN_LEN (32)
#endif
void ft2004_mmcsd_change(void);
rt_bool_t ft2004_card_status(void);
rt_err_t ft2004_card_remove_check(rt_int32_t timeout, rt_uint32_t *status);
void ft2004_sdctrl_reset(void);
#ifdef __cplusplus
}
#endif
#endif // !
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
* @Date: 2021-04-25 14:01:29
* @LastEditTime: 2021-05-26 15:42:52
* @Description:  This files is for
*
* @Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#include "drv_spi.h"
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#include "ft_spi.h"
#include "ft_mux.h"
#include "ft_trace.h"
#include "ft_generic_timer.h"
#ifdef BSP_USE_SPI
#define DRV_DEBUG
#define LOG_TAG "drv.spi"
#include <drv_log.h>
typedef void (*spi_cs_handler_t)(const rt_bool_t select);
typedef struct
{
FSpi_Ctrl_t spi_ctrl;
struct rt_spi_bus spi_bus;
uint16_t spi_cs_pin;
spi_cs_handler_t spi_cs_handler;
} ft2004_spi_class;
void ft2004_spi_cs(const rt_bool_t select);
static ft2004_spi_class spi_obj = {
.spi_cs_handler = ft2004_spi_cs,
.spi_ctrl = {
.CtrlId = SPI_CTRL_ID_0,
.DevId = SPI_DEV_ID_0,
.IsReady = FALSE,
.CsPin = 5, /* use pin 5 in gpio group a as cs signal pin */
},
};
static const FSpi_Conf_t spi_conf[NUM_OF_SPI_CTRL] =
{
{
.DevAddr = {0x00, 0x00, 0x00, 0x00},
.DevAddrLen = SPI_4_BYTE_ADDR,
.WorkMode = SPI_CTRL_MASTER_MODE,
/* mode 2 CPOL = 1, CPHA = 0 */
.Cpol = SPI_CTRL_CPOL_HIGH,
.Cpha = SPI_CTRL_CPHA_1EDGE,
.BaudRDiv = SPI_SCKDV_4,
},
{
.DevAddr = {0x00, 0x00, 0x00, 0x00},
.DevAddrLen = SPI_4_BYTE_ADDR,
.WorkMode = SPI_CTRL_MASTER_MODE,
.Cpol = SPI_CTRL_CPOL_HIGH,
.Cpha = SPI_CTRL_CPHA_1EDGE,
.BaudRDiv = SPI_SCKDV_MAX,
}};
inline static ft2004_spi_class *ft2004_spi_get_class()
{
return &spi_obj;
}
inline static FSpi_Ctrl_t *ft2004_spi_get_ctrl()
{
return &(ft2004_spi_get_class()->spi_ctrl);
}
static const FSpi_Conf_t *ft2004_lookup_conf(FT_IN FSpi_CtrlId_t CtrlId)
{
return &spi_conf[CtrlId];
}
void ft2004_spi_cs(const rt_bool_t select)
{
FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
FSpi_SelectSlave(ctrl_p, ctrl_p->DevId, (bool_t)select);
}
/**spi flash operations***/
u32 ft2004_spi_transcation(const u8 tx_data, u8 *rx_data_p)
{
FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
u32 ret = ERR_SPI_OK;
ret = FSpi_ReadWriteByte(ctrl_p, tx_data, rx_data_p);
return ret;
}
/**spi flash operations***/
static rt_err_t ft2004_spi_init(struct rt_spi_configuration *cfg)
{
FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
FSpi_DevId_t dev_id;
u32 ret = ERR_SPI_OK;
//RT_ASSERT(cfg != RT_NULL);
RT_ASSERT(ctrl_p != RT_NULL);
dev_id = ctrl_p->DevId;
/* get spi flash default config */
ctrl_p->Config = *(ft2004_lookup_conf(dev_id));
/* change config according to inputs, cfg could be RT_NULL */
/* reset ctrl block */
ctrl_p->IsReady = FALSE;
/* set spi pin mux */
Ft_setSpiMux(ctrl_p->CtrlId);
/* init spi ctrl */
ret = FSpi_Init(ctrl_p);
if (ERR_SPI_OK == ret)
{
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
static rt_uint32_t spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
rt_size_t message_length, loop;
rt_uint8_t *recv_buf;
const rt_uint8_t *send_buf;
u32 tx_rx_result = ERR_SPI_OK;
spi_cs_handler_t cs_handler = ft2004_spi_get_class()->spi_cs_handler;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(device->bus != RT_NULL);
RT_ASSERT(device->bus->parent.user_data != RT_NULL);
RT_ASSERT(message != RT_NULL);
if (message->cs_take && cs_handler)
{
cs_handler(TRUE);
}
message_length = message->length;
recv_buf = message->recv_buf;
send_buf = message->send_buf;
/* handle msg */
for (loop = 0; loop < message_length; loop++)
{
/* start data exchange */
if ((message->recv_buf) && (message->send_buf))
{
/* need tx and rx */
tx_rx_result |= ft2004_spi_transcation(*send_buf, recv_buf);
send_buf++;
recv_buf++;
}
else if (message->send_buf)
{
/* tx only */
tx_rx_result |= ft2004_spi_transcation(*send_buf, RT_NULL);
send_buf++;
}
else
{
/* rx only */
tx_rx_result |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, recv_buf);
recv_buf++;
}
}
if (ERR_SPI_OK != tx_rx_result)
{
LOG_E("spi transfer error : 0x%x", tx_rx_result);
message->length = 0;
}
else
{
}
if (message->cs_release && cs_handler)
{
cs_handler(FALSE);
}
return message->length;
}
static rt_err_t spi_configure(struct rt_spi_device *device,
struct rt_spi_configuration *configuration)
{
RT_ASSERT(device != RT_NULL);
RT_ASSERT(configuration != RT_NULL);
return ft2004_spi_init(configuration);
}
static const struct rt_spi_ops ft2004_spi_ops =
{
.configure = spi_configure,
.xfer = spi_xfer,
};
/**
* Attach the spi device to SPI bus, this function must be used after initialization.
*/
rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, uint16_t cs_gpio_pin)
{
rt_err_t result;
struct rt_spi_device *spi_device;
ft2004_spi_class *spi_class = ft2004_spi_get_class();
RT_ASSERT(spi_class != RT_NULL);
spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
RT_ASSERT(spi_device != RT_NULL);
result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, RT_NULL);
LOG_I("attach result 0x%x", result);
if (result != RT_EOK)
{
if (spi_device)
{
rt_free(spi_device);
}
}
return result;
}
static int rt_hw_spi_bus_init(void)
{
rt_err_t result;
ft2004_spi_class *spi_class = ft2004_spi_get_class();
LOG_I("init spi ctrl");
spi_class->spi_bus.parent.user_data = &spi_class->spi_bus;
result = rt_spi_bus_register(&spi_class->spi_bus, SPI_BUS_NAME, &ft2004_spi_ops);
return result;
}
int rt_hw_spi_init(void)
{
return rt_hw_spi_bus_init();
}
INIT_BOARD_EXPORT(rt_hw_spi_init);
static void rthw_spi_delay(u32 delayCnt)
{
Ft_GenericTimer_UsDelay(delayCnt);
}
/************spi flash operatiosn implemented for sample test****************/
/* definition of s25fs maunfactor id */
typedef struct
{
u8 Mid;
u8 MemoryType;
u8 Density;
u8 RemainBytes;
u8 PhySectArch;
u8 FamilyID;
} ft2004_manuid_t;
/* definition of cmd for s25fs */
#define S25FS_ENABLE_WR 0x06
#define S25FS_DISABLE_WR 0x04
#define S25FS_READ_ID 0x9F
#define S25FS_READ_4BYTE_ADD 0x13
#define S25FS_ERASE_4BYTE_ADD 0x21
#define S25FS_READ_STATUS_1 0x05
#define S25FS_READ_FLASH_PARAM 0x5A
static void ft2004_dump_manuid(const ft2004_manuid_t *pId)
{
rt_kprintf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\r\n",
pId->Mid, pId->MemoryType, pId->Density, pId->RemainBytes,
pId->PhySectArch, pId->FamilyID);
}
static u32 ft2004_read_in_4byte_addr(const u32 ReadAddr, const u32 BytesToRead, u8 *pBuf)
{
u32 ret = ERR_SPI_OK;
u32 loop;
RT_ASSERT(RT_NULL != pBuf);
ft2004_spi_cs(TRUE);
ret |= ft2004_spi_transcation(S25FS_READ_4BYTE_ADD, RT_NULL);
/* only 4-bytes address, MSB first */
ret |= ft2004_spi_transcation((u8)(ReadAddr >> 24), RT_NULL);
ret |= ft2004_spi_transcation((u8)(ReadAddr >> 16), RT_NULL);
ret |= ft2004_spi_transcation((u8)(ReadAddr >> 8), RT_NULL);
ret |= ft2004_spi_transcation((u8)ReadAddr, RT_NULL);
/* read out data */
for (loop = 0; loop < BytesToRead; loop++)
{
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, pBuf + loop);
if (ERR_SPI_OK != ret)
{
break;
}
}
ft2004_spi_cs(FALSE);
return ret;
}
u32 ft2004_spi_enable_wr(const bool_t enable)
{
u32 ret = ERR_SPI_OK;
ft2004_spi_cs(TRUE);
if (enable)
{
ret |= ft2004_spi_transcation(S25FS_ENABLE_WR, RT_NULL);
}
else
{
ret |= ft2004_spi_transcation(S25FS_DISABLE_WR, RT_NULL);
}
ft2004_spi_cs(FALSE);
return ret;
}
u32 ft2004_erase_sector_in_4byte_addr(const u32 sector_addr)
{
u32 Ret = ERR_SPI_OK;
ft2004_spi_enable_wr(TRUE);
LOG_I("erase sector 0x%x", Ret);
if (ERR_SPI_OK != Ret)
{
return Ret;
}
ft2004_spi_cs(TRUE);
Ret |= ft2004_spi_transcation(S25FS_ERASE_4BYTE_ADD, RT_NULL);
Ret |= ft2004_spi_transcation((u8)(sector_addr >> 24), RT_NULL);
Ret |= ft2004_spi_transcation((u8)(sector_addr >> 16), RT_NULL);
Ret |= ft2004_spi_transcation((u8)(sector_addr >> 8), RT_NULL);
Ret |= ft2004_spi_transcation((u8)(sector_addr), RT_NULL);
ft2004_spi_cs(FALSE);
return Ret;
}
u32 ft2004_spi_read_params(const u32 Addr)
{
u32 Ret = ERR_SPI_OK;
u8 dat[8] = {0};
u32 loop;
ft2004_spi_cs(TRUE);
Ret |= ft2004_spi_transcation(S25FS_READ_FLASH_PARAM, RT_NULL);
Ret |= ft2004_spi_transcation((u8)(Addr >> 16), RT_NULL);
Ret |= ft2004_spi_transcation((u8)(Addr >> 8), RT_NULL);
Ret |= ft2004_spi_transcation((u8)(Addr), RT_NULL);
for (loop = 0; loop < 8; loop++)
{
Ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, dat + loop);
rt_kprintf("%d: 0x%x", loop, *(dat + loop));
}
ft2004_spi_cs(FALSE);
return Ret;
}
static u32 ft2004_spi_readid_for_test(ft2004_manuid_t *pId)
{
FSpi_Ctrl_t *ctrl_p = ft2004_spi_get_ctrl();
u32 ret = ERR_SPI_OK;
if (!ctrl_p->IsReady)
{
return ERR_SPI_NOT_READY;
}
RT_ASSERT(RT_NULL != pId);
ft2004_spi_cs(TRUE);
/* shifting the command code “90H” followed by a 24-bit address */
ret |= ft2004_spi_transcation(S25FS_READ_ID, RT_NULL);
/* Manufacturer ID and the Device ID are shifted out */
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->Mid);
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->MemoryType);
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->Density);
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->RemainBytes);
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->PhySectArch);
ret |= ft2004_spi_transcation(SPI_DUMMY_TX_DATA, &pId->FamilyID);
ft2004_spi_cs(FALSE);
if (ERR_SPI_OK == ret)
{
ft2004_dump_manuid(pId);
}
return ret;
}
static void spi_9f_s25fs_sample(int argc, char *argv[])
{
ft2004_manuid_t dev_id;
u32 ret = ERR_SPI_OK;
u32 delay = SPI_TIMEOUT * 10;
rt_kprintf("test s25fs spi flash\r\n");
ret |= ft2004_spi_init(RT_NULL);
ret |= ft2004_spi_readid_for_test(&dev_id);
rt_kprintf("result is: 0x%x \r\n", ret);
while (--delay)
{
rthw_spi_delay(10);
}
}
MSH_CMD_EXPORT(spi_9f_s25fs_sample, "spi s25fs cmd 9fH sample");
static u8 read_buf[256];
static void spi_5a_s25fs_sample(int argc, char *argv[])
{
u32 ret = ERR_SPI_OK;
u32 delay = SPI_TIMEOUT * 10;
u32 read_addr = 0x0000;
rt_kprintf("test s25fs spi flash\r\n");
ret |= ft2004_spi_init(RT_NULL);
ret |= ft2004_spi_read_params(read_addr);
ret |= ft2004_read_in_4byte_addr(read_addr, 256, read_buf);
rt_kprintf("result is: 0x%x \r\n", ret);
while (--delay)
{
rthw_spi_delay(10);
}
}
MSH_CMD_EXPORT(spi_5a_s25fs_sample, "spi s25fs cmd 5aH sample");
#endif
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
* @Date: 2021-04-25 14:01:39
* @LastEditTime: 2021-04-29 09:40:13
* @Description:  This files is for
*
* @Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#ifndef FT_DRIVERS_RTT_SPI_H
#define FT_DRIVERS_RTT_SPI_H
#include <rtthread.h>
#define SPI_BUS_NAME "spi0"
#define SPI_DEV_NAME "S25FS256"
rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, uint16_t cs_gpio_pin);
#ifdef __cplusplus
extern "C"
{
#endif
#endif
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
* @Date: 2021-04-25 14:01:16
* @LastEditTime: 2021-04-30 14:43:12
* @Description:  This files is for
*
* @Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#include <board.h>
#include <drv_spi.h>
#include <rtdevice.h>
#include <rthw.h>
#include <finsh.h>
#include "ft_spi.h"
#ifdef BSP_USE_SPI
#include "spi_flash.h"
#include "spi_flash_sfud.h"
static int rt_hw_spi_flash_init(void)
{
uint16_t cs_pin = 5;
rt_hw_spi_device_attach(SPI_BUS_NAME, SPI_DEV_NAME, cs_pin);
rt_kprintf("attach spi flash\r\n");
/* lookup flah */
if (RT_NULL == rt_sfud_flash_probe("S25FS256S", SPI_DEV_NAME))
{
rt_kprintf("attach spi flash failed\r\n");
return -RT_ERROR;
}
return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-04 Carl the first version
*/
#include "board.h"
#include "drv_usart.h"
#include "interrupt.h"
#include "serial.h"
#include "rtconfig.h"
#ifdef RT_USING_SERIAL
extern u32 FUart_GetInterruptMask(Ft_Uart *uart_ptr);
static void Ft_Os_Uart_Callback(void *Args, u32 Event, u32 EventData);
static void rt_hw_uart_isr(int irqno, void *param)
{
Ft_Uart *uart_ptr = (Ft_Uart *)param;
FUart_InterruptHandler(uart_ptr);
}
static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
struct drv_usart *uart = RT_NULL;
Ft_Uart *uart_ptr = RT_NULL;
u32 RegTemp;
u32 ret;
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
uart = rt_container_of(serial, struct drv_usart, serial);
uart_ptr = uart->handle;
RT_ASSERT(FUart_CfgInitialize(uart_ptr, FUart_LookupConfig(uart_ptr->Config.InstanceId)) == FST_SUCCESS);
FUart_SetHandler(uart_ptr, Ft_Os_Uart_Callback, serial);
rt_hw_interrupt_install(uart_ptr->Config.IsrNum, rt_hw_uart_isr, uart_ptr, "uart");
rt_hw_interrupt_umask(uart_ptr->Config.IsrNum);
//<! 设置波特率
ret = FUart_SetBaudRate(uart_ptr, cfg->baud_rate);
RT_ASSERT(ret == FST_SUCCESS);
//<! 打开接收中断
RegTemp = FUart_GetInterruptMask(uart_ptr);
RegTemp |= UARTMIS_RTMIS;
FUart_SetInterruptMask(uart_ptr, RegTemp);
FUart_SetOptions(uart_ptr, FUART_OPTION_UARTEN | FUART_OPTION_RXEN | FUART_OPTION_TXEN | FUART_OPTION_FIFOEN);
return RT_EOK;
}
static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
struct drv_usart *uart = RT_NULL;
Ft_Uart *uart_ptr = RT_NULL;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct drv_usart, serial);
uart_ptr = uart->handle;
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
/* disable rx irq */
rt_hw_interrupt_mask(uart_ptr->Config.IsrNum);
break;
case RT_DEVICE_CTRL_SET_INT:
/* enable rx irq */
rt_hw_interrupt_umask(uart_ptr->Config.IsrNum);
break;
}
return RT_EOK;
}
static void Ft_Os_Uart_Callback(void *Args, u32 Event, u32 EventData)
{
struct rt_serial_device *serial = (struct rt_serial_device *)Args;
if (FUART_EVENT_RECV_DATA == Event || FUART_EVENT_RECV_TOUT == Event)
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
}
else if (FUART_EVENT_RECV_ERROR == Event)
{
}
else if (FUART_EVENT_SENT_DATA == Event)
{
}
else if (FUART_EVENT_PARE_FRAME_BRKE == Event)
{
}
else if (FUART_EVENT_RECV_ORERR == Event)
{
}
if (FUART_EVENT_SENT_DATA == Event)
{
}
else
{
}
}
static int uart_putc(struct rt_serial_device *serial, char c)
{
struct drv_usart *uart = RT_NULL;
Ft_Uart *uart_ptr = RT_NULL;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct drv_usart, serial);
uart_ptr = uart->handle;
FUart_SendByte(uart_ptr->Config.BaseAddress, c);
return 1;
}
static int uart_getc(struct rt_serial_device *serial)
{
int ch;
struct drv_usart *uart = RT_NULL;
Ft_Uart *uart_ptr = RT_NULL;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct drv_usart, serial);
uart_ptr = uart->handle;
ch = FUart_GetChar(uart_ptr->Config.BaseAddress);
if (ch == 0xff)
ch = -1;
return ch;
}
static const struct rt_uart_ops _uart_ops =
{
uart_configure,
uart_control,
uart_putc,
uart_getc,
};
#ifdef RT_USING_UART0
static Ft_Uart Ft_Uart0;
static struct drv_usart _RtUart0;
#endif
#ifdef RT_USING_UART1
static Ft_Uart Ft_Uart1;
static struct drv_usart _RtUart1;
#endif
int rt_hw_uart_init(void)
{
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
#ifdef RT_USING_UART0
config.bufsz = RT_SERIAL_RB_BUFSZ;
_RtUart0.serial.ops = &_uart_ops;
_RtUart0.serial.config = config;
Ft_Uart0.Config.InstanceId = FT_UART0_ID;
_RtUart0.Handle = &Ft_Uart0;
rt_hw_serial_register(&_RtUart0.serial, "uart0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
&_RtUart0);
#endif
#ifdef RT_USING_UART1
config.bufsz = RT_SERIAL_RB_BUFSZ;
_RtUart1.serial.ops = &_uart_ops;
_RtUart1.serial.config = config;
Ft_Uart1.Config.InstanceId = FT_UART1_ID;
_RtUart1.handle = &Ft_Uart1;
rt_hw_serial_register(&_RtUart1.serial, "uart1",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
&_RtUart1);
#endif
return 0;
}
INIT_BOARD_EXPORT(rt_hw_uart_init);
#endif /* RT_USING_SERIAL */
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-04 Carl the first version
*/
#ifndef __DRV_USART_H__
#define __DRV_USART_H__
#include <rtthread.h>
#include "rtdevice.h"
#include "ft_uart.h"
struct drv_usart
{
Ft_Uart *handle;
struct rt_serial_device serial;
};
#endif // !
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-29 Carl the first version
*
*/
#include <rtthread.h>
#include "ft2004.h"
#include "gicv3.h"
rt_uint64_t get_main_cpu_affval(void)
{
return 0;
}
rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list)
{
if (*cpu_mask == 0)
{
return 0;
}
*target_list = 0;
*cluster_id = 0;
if (*cpu_mask & 0x3)
{
if ((*cpu_mask & 0x3) == 0x3)
{
*target_list = 3;
}
else if ((*cpu_mask & 0x1))
{
*target_list = 1;
}
else
{
*target_list = 2;
}
*cpu_mask &= ~0x3;
}
else if (*cpu_mask & 0xc)
{
*cluster_id = 0x100;
if ((*cpu_mask & 0xc) == 0xc)
{
*target_list = 3;
}
else if ((*cpu_mask & 0x4))
{
*target_list = 1;
}
else
{
*target_list = 2;
}
*cpu_mask &= ~0xc;
}
else
{
*cpu_mask = 0;
return 0;
}
return 1;
}
#ifdef RT_USING_SMP
void send_core_isg(void)
{
for (size_t i = 0; i <= 0xf; i++)
{
/* code */
rt_kprintf("i %x \r\n", i);
arm_gic_send_affinity_sgi(0, 0, i, 0);
rt_thread_mdelay(100);
}
}
MSH_CMD_EXPORT(send_core_isg, send_core_isg);
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-29 Carl the first version
*
*/
#ifndef __FT2004_H__
#define __FT2004_H__
#include <rthw.h>
#include <rtthread.h>
#define ARM_GIC_NR_IRQS 160
#define ARM_GIC_MAX_NR 1
#define MAX_HANDLERS 160
#define GIC_IRQ_START 0
rt_uint64_t get_main_cpu_affval(void);
#endif // !
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-29 Carl the first version
*
*/
#include "rtconfig.h"
.globl rt_hw_cpu_id
rt_hw_cpu_id:
mrc p15, 0, r0, c0, c0, 5
ubfx r0, r0, #0, #12
cmp r0, #0
beq core0
cmp r0, #1
beq core1
cmp r0, #256
beq core2
mov r1 ,#257
cmp r0, r1
beq core3
b default
core0:
mov r0, #0
b return
core1:
mov r0, #1
b return
core2:
mov r0, #2
b return
core3:
mov r0, #3
b return
default:
and r0, r0, #15
return:
bx lr
/*
* @ : Copyright (c) 2020 Phytium Information Technology, Inc.
*
* SPDX-License-Identifier: Apache-2.0.
*
* @Date: 2021-05-26 10:09:45
* @LastEditTime: 2021-05-26 10:31:44
* @Description:  This files is for
*
* @Modify History:
*  Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#include <rtthread.h>
#include "board.h"
#include <gicv3.h>
#ifdef RT_USING_SMP
#include <interrupt.h>
#include "ft_psci.h"
#include "ft_generic_timer.h"
extern int rt_hw_timer_init(void);
extern void secondary_cpu_start(void);
void rt_hw_secondary_cpu_up(void)
{
rt_uint32_t i;
rt_uint32_t cpu_mask = 0;
rt_kprintf("rt_hw_secondary_cpu_up is processing \r\n");
for (i = 1; i < RT_CPUS_NR; i++)
{
if (i == 1)
{
/* code */
FPsci_CpuOn(1 << i, (rt_uint32_t)secondary_cpu_start);
cpu_mask = 2;
}
else if (i == 2)
{
FPsci_CpuOn(1 << i, (rt_uint32_t)secondary_cpu_start);
cpu_mask = 4;
}
else if (i == 3)
{
FPsci_CpuOn(1 << i, (rt_uint32_t)secondary_cpu_start);
cpu_mask = 8;
}
else
{
continue;
}
__asm__ volatile("dsb" ::
: "memory");
rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
Ft_GenericTimer_UsDelay(1000000);
}
}
void secondary_cpu_c_start(void)
{
rt_hw_vector_init();
rt_hw_spin_lock(&_cpus_lock);
arm_gic_cpu_init(0);
arm_gic_redist_init(0);
rt_hw_timer_init();
rt_hw_interrupt_set_priority(RT_SCHEDULE_IPI, 16);
rt_hw_interrupt_umask(RT_SCHEDULE_IPI);
rt_system_scheduler_start();
}
void rt_hw_secondary_cpu_idle_exec(void)
{
asm volatile("wfe" ::
: "memory", "cc");
}
#endif
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-04-29 Carl the first version
*
*/
#ifndef __UART_H__
#define __UART_H__
#include <board.h>
int rt_hw_uart_init(void);
#endif
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SECTIONS
{
. = 0x80100000;
__text_start = .;
.text :
{
*(.vectors)
*(.text)
*(.text.*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
/* section information for initialization */
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
} =0
__text_end = .;
__rodata_start = .;
.rodata : { *(.rodata) *(.rodata.*) }
__rodata_end = .;
. = ALIGN(4);
.ctors :
{
PROVIDE(__ctors_start__ = .);
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
PROVIDE(__ctors_end__ = .);
}
.dtors :
{
PROVIDE(__dtors_start__ = .);
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
PROVIDE(__dtors_end__ = .);
}
. = ALIGN(16 * 1024);
.l1_page_table :
{
__l1_page_table_start = .;
. += 16K;
}
. = ALIGN(8);
__data_start = .;
.data :
{
*(.data)
*(.data.*)
}
__data_end = .;
. = ALIGN(8);
__bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
}
. = ALIGN(4);
__bss_end = .;
.heap :
{
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
__HeapBase = .;
. += 0x400;
__HeapLimit = .;
__heap_limit = .; /* Add for _sbrk */
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
_end = .;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
*
* @Date: 2021-04-27 15:31:44
* @LastEditTime: 2021-04-27 15:31:44
* @Description:  Description of file
* @Modify History:
* * * Ver   Who        Date         Changes
* * ----- ------     --------    --------------------------------------
*/
#include "ft_can.h"
#include "ft_parameters.h"
FCan_Config_t FCan_Config[FT_CAN_NUM] =
{
{
.InstanceId = 0, /* Id of device */
.CanBaseAddress = FT_CAN0_BASEADDR, /* Can base Address */
.IrqNum = FT_CAN0_IRQNUM,
.BaudRate = 250000,
.TxFifoDeepth = 16,
},
{
.InstanceId = 1, /* Id of device */
.CanBaseAddress = FT_CAN1_BASEADDR, /* Can base Address */
.IrqNum = FT_CAN1_IRQNUM,
.BaudRate = 250000,
.TxFifoDeepth = 16,
},
{
.InstanceId = 2, /* Id of device */
.CanBaseAddress = FT_CAN2_BASEADDR, /* Can base Address */
.IrqNum = FT_CAN2_IRQNUM,
.BaudRate = 250000,
.TxFifoDeepth = 16,
}};
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
*
* @Date: 2021-04-27 13:52:41
* @LastEditTime: 2021-04-27 13:52:41
* @Description:  Description of file
* @Modify History:
* * * Ver   Who        Date         Changes
* * ----- ------     --------    --------------------------------------
*/
#include "ft_can_hw.h"
#include "ft_can.h"
#include "ft_mux.h"
#include "ft_parameters.h"
#include "ft_math.h"
#include "ft_assert.h"
#include "ft_debug.h"
#define CAN_HW_DEBUG_TAG "CAN_HW"
#define CAN_HW_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(CAN_HW_DEBUG_TAG, format, ##__VA_ARGS__)
#define CAN_HW_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(CAN_HW_DEBUG_TAG, format, ##__VA_ARGS__)
#define CAN_HW_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(CAN_HW_DEBUG_TAG, format, ##__VA_ARGS__)
void FCan_Reset(FCan_t *Can_p)
{
u32 RegValue;
FCan_Config_t *Config_p;
Ft_assertVoid(Can_p != NULL);
Ft_assertVoid(Can_p->IsReady == FT_COMPONENT_IS_READLY);
Config_p = &Can_p->Config;
RegValue = FCan_ReadReg(Config_p->CanBaseAddress, FCAN_CTRL_OFFSET);
if (RegValue & FCAN_CTRL_XFER_MASK)
{
CAN_HW_DEBUG_E("FT can is not in configration mode\n");
Ft_assertVoid(0);
return;
}
FCan_WriteReg(FT_PIN_DEMUX_BASE, FT_PIN_DEMUX_REG204_OFFSET, 0x89999990); // Reuse can IO
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_CTRL_OFFSET, FCAN_CTRL_RESET_MASK);
FCan_SetBit(Config_p->CanBaseAddress, FCAN_CTRL_OFFSET, FCAN_CTRL_AIME_MASK);
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_ACC_ID0_MASK_OFFSET, FCAN_ACC_IDN_MASK);
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_ACC_ID1_MASK_OFFSET, FCAN_ACC_IDN_MASK);
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_ACC_ID2_MASK_OFFSET, FCAN_ACC_IDN_MASK);
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_ACC_ID3_MASK_OFFSET, FCAN_ACC_IDN_MASK);
FCan_ClearBit(Config_p->CanBaseAddress, FCAN_CTRL_OFFSET, FCAN_CTRL_RESET_MASK);
FCan_WriteReg(Config_p->CanBaseAddress, FCAN_INTR_OFFSET, FCAN_INTR_TEIE_MASK | FCAN_INTR_REIE_MASK);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
* @Date: 2021-04-07 09:53:07
* @LastEditTime: 2021-04-07 13:24:16
* @Description:  This files is for gmac descrption
*
* @Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
*/
#ifndef GMAC_DESC_H
#define GMAC_DESC_H
#include "ft_gmac.h"
#endif // !
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册