移植平台:瑞芯微RV1109(kernel版本:4.19 SDK:RV1126_RV1109_LINUX_SDK_V1.8.0_20210224) 海思3861L(SDK:Hi3861V100R001C00SPC025 + patch_Hi3861V100C001R001SPC025_for_hichannel_001)
项目前期没有PCB板,我们只能通过开发板调试外设功能,而RV1109开发板与wifi之间是采用SDIO通讯的,SDIO是高速通讯信号,一般的开发板不会将sdio引出。但是庆幸的是,sd卡也是通过sdio与主控进行通讯的,我们完全可以打一个金手指样式的PCB转接板,将SDIO与wifi模块连接起来,如下图所示:
hi_channel驱动是基于linux4.9内核编写的,要将该驱动应用至linux4.19内核,则需梳理两个内核版本间的改动对wifi驱动的影响,这对于对内核不熟的小伙伴来说可得花一番功夫了,但不管怎么样,海思已经提供了一版驱动作参考了。下面是在移植过程中总结的修改项,供大家参考:
一、移植遇到的问题(移植修改项)
1. net device结构体成员名称destructor 改为 priv_destructor
报错信息为:
hichannel//oal/oal_net.h:38:57: error: 'oal_net_device_stru' {aka 'struct net_device'} has no member named 'destructor'; did you mean 'priv_destructor'?
#define oal_netdevice_destructor(_pst_dev) ((_pst_dev)->destructor)
^~~~~~~~~~
修改方法:
2. 结构体wait_queue_t 需要改用为 wait_queue_entry_t
报错信息为:
hichannel//oal/oal_wait.h:26:9: error: unknown type name 'wait_queue_t'
typedef wait_queue_t oal_wait_queue_stru;
^~~~~~~~~~~~
修改方法:
3. timer用法更改
报错信息为:
/home/disk/fangye/hichannel/oal/oal_timer.h:37:5: error: implicit declaration of function 'init_timer'; did you mean 'init_timers'? [-Werror=implicit-function-declaration]
init_timer(pst_timer);
^~~~~~~~~~
init_timers
/home/disk/fangye/hichannel//oal/oal_timer.h:39:25: error: assignment to 'void (*)(struct timer_list *)' from incompatible pointer type 'oal_timer_func' {aka 'void (*)(long unsigned int)'} [-Werror=incompatible-pointer-types]
pst_timer->function = p_func;
^
/home/disk/fangye/hichannel//oal/oal_timer.h:40:14: error: 'oal_timer_list_stru' {aka 'struct timer_list'} has no member named 'data'
pst_timer->data = ui_arg;
这是因为在linux kernel 4.14版本后,init_timer被移除了,需要换用新的timer_setup接口代替。
参考链接:
https://lwn.net/Articles/735887/
https://stackoverflow.com/a/53842823
修改方法:
hcc_host.c
oal_timer.h
4. 内核调度参数配置
报错信息为:
hichannel//oal/oal_thread.h:59:30: error: storage size of 'st_sched_param' isn't known
struct sched_param st_sched_param;
^~~~~~~~~~~~~~
未知st_sched_param的存储大小,说明该变量类型只有声明没有定义,猜测应该是定义到别的头文件中去了。在sdk的kernel driver中搜索sched_setscheduler函数,对比头文件,添加相关的头文件即可。
修改方法:
5. 发送信号函数
hichannel//oal/oal_thread.h:110:5: error: implicit declaration of function 'send_sig'; did you mean 'send_sigio'? [-Werror=implicit-function-declaration]
send_sig(SIGTERM, pst_thread, 1);
^~~~~~~~
send_sigio
cc1: some warnings being treated as errors
scripts/Makefile.build:333: recipe for target '/home/disk/fangye/projects/rv1109_smart_door/kernel/drivers/hichannel/hcc/hcc_host.o' failed
同样,在kernel/include下搜索send_sig,包含相应的头文件即可。
修改方法:
6.系统时钟
报错信息为:
hichannel/sdio/sdio_host.c:821:38: error: implicit declaration of function 'cpu_clock'; did you mean 'pud_lock'? [-Werror=implicit-function-declaration]
hi_sdio->msg[bit].cpu_time = cpu_clock(UINT_MAX);
^~~~~~~~~
pud_lock
cc1: some warnings being treated as errors
scripts/Makefile.build:333: recipe for target '/home/disk/fangye/projects/rv1109_smart_door/kernel/drivers/hichannel/sdio/sdio_host.o' failed
修改方法:
添加头文件:
#include <linux/sched/clock.h>
按上述修改项修改后,hi_channel驱动编译通过了:
二、平台驱动适配
由于hi_channel目前只适配了hi3518和君正T31平台,仅仅编译通过还不能正常使用,需要针对不通的平台进行适配。hi3861L是通过sdio与主控通讯为host侧主控提供上网能力的,而hi3861L是一款低功耗wifi模块,为了满足低功耗需求,hi3861L是采用一线SDIO方式进行通讯的。
1. 要适配驱动,首先要适配rv1109的dts
我这里是将sdcard 我这里是基于rv1126-evb-ddr3-v13-tb-emmc.dts进行修改的:
dts配置如下:
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitChange-Id: I59016bc57d21e6459b95d39f2e876daa8a0e2157
---
arch/arm/boot/dts/rv1109-evb-ddr3-v13-tb-emmc.dts | 15 +++++++--------
arch/arm/boot/dts/rv1126-evb-v10.dtsi | 26 +++++++++++++-------------
arch/arm/boot/dts/rv1126-pinctrl.dtsi | 7 ++++++-
3 files changed, 26 insertions(+), 22 deletions(-)
mode change 100644 => 100755 arch/arm/boot/dts/rv1126-evb-v10.dtsi
mode change 100644 => 100755 arch/arm/boot/dts/rv1126-pinctrl.dtsidiff --git a/arch/arm/boot/dts/rv1109-evb-ddr3-v13-tb-emmc.dts b/arch/arm/boot/dts/rv1109-evb-ddr3-v13-tb-emmc.dts
index 867b02a..c4da626 100755
--- a/arch/arm/boot/dts/rv1109-evb-ddr3-v13-tb-emmc.dts
+++ b/arch/arm/boot/dts/rv1109-evb-ddr3-v13-tb-emmc.dts
@@ -414,16 +414,15 @@
};
&sdmmc {
- bus-width = <4>;
- cap-mmc-highspeed;
- cap-sd-highspeed;
- card-detect-delay = <200>;
+ max-frequency = <50000000>;
+ bus-width = <1>;
+ cap-sdio-irq;
+ keep-power-in-suspend;
rockchip,default-sample-phase = <90>;
- supports-sd;
- sd-uhs-sdr12;
+ supports-sdio;
sd-uhs-sdr25;
- sd-uhs-sdr104;
- vqmmc-supply = <&vccio_sd>;
+ vqmmc-supply = <&vcc3v3_sd>;
+ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus1>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/rv1126-evb-v10.dtsi b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
old mode 100644
new mode 100755
index 144e9ed..a124f9c
--- a/arch/arm/boot/dts/rv1126-evb-v10.dtsi
+++ b/arch/arm/boot/dts/rv1126-evb-v10.dtsi
@@ -1265,19 +1265,19 @@
vref-supply = <&vcc_1v8>;
};
-&sdmmc {
- bus-width = <4>;
- cap-mmc-highspeed;
- cap-sd-highspeed;
- card-detect-delay = <200>;
- rockchip,default-sample-phase = <90>;
- supports-sd;
- sd-uhs-sdr12;
- sd-uhs-sdr25;
- sd-uhs-sdr104;
- vqmmc-supply = <&vccio_sd>;
- status = "okay";
-};
+//&sdmmc {
+// bus-width = <4>;
+// cap-mmc-highspeed;
+// cap-sd-highspeed;
+// card-detect-delay = <200>;
+// rockchip,default-sample-phase = <90>;
+// supports-sd;
+// sd-uhs-sdr12;
+// sd-uhs-sdr25;
+// sd-uhs-sdr104;
+// vqmmc-supply = <&vccio_sd>;
+// status = "okay";
+//};
&sdio {
max-frequency = <200000000>;
diff --git a/arch/arm/boot/dts/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rv1126-pinctrl.dtsi
old mode 100644
new mode 100755
index dd83d8f..c555d7a
--- a/arch/arm/boot/dts/rv1126-pinctrl.dtsi
+++ b/arch/arm/boot/dts/rv1126-pinctrl.dtsi
@@ -1310,7 +1310,12 @@
};
sdmmc0 {
/omit-if-no-ref/
- sdmmc0_bus4: sdmmc0-bus4 {
+ sdmmc0_bus1: sdmmc0-bus1 {
+ rockchip,pins =
+ /* sdmmc0_d0 */
+ <1 RK_PA4 1 &pcfg_pull_up_drv_level_2>;
+ };
+ sdmmc0_bus4: sdmmc0-bus4 {
rockchip,pins =
/* sdmmc0_d0 */
<1 RK_PA4 1 &pcfg_pull_up_drv_level_2>,
--
2.7.4
配置完成后,重新编译固件烧录,在插入、拔出wifi卡时会有如下打印:
2. GPIO中断配置
首先查看原理图,我们这里是使用的SDMMC_D1来做中断,与hi_3861L的GPIO8相连,确定RV1109的引脚为GPIO1_A5。
将GPIO1_A5换算成GPIO编号为37(GPIOx共32个GPIO,分为A/B/C/D四组,此处为GPIO1,所以前面GPIO0有32个GPIO,A5表示第1组第6个,相加为38,由于序列从0开始,故SDMMC_D1的GPIO编号为37)
sdio_host.h
sdio_host.c
由于定义了宏开关,我们需要添加相应编译宏配置:
env_config.mk
三、驱动加载测试
插入wifi转接卡:
查看wifi打印,确保hi_channel初始化成功。
加载驱动,会有wal_rx_data_proc failed,暂时不用理会。
wifi会有如下打印信息:
在海思提供的hi_channel sdk包中编译出sample_link程序
驱动加载成功后,执行./sample_link & 与hi_3861L建立通讯,获取IP地址,mac地址、网关、dns服务器等信息(自行开发部分代码),运行成功后wal_rx_data_proc failed报错就消失了,具体什么原因没有深入去定位。
测试上网没有问题,就可以开始你的网络应用了(当然这仅仅是个开始,应用到项目中还需要根据应用场景进行调试优化)
上述为个人开发经验总结如果错误还请多多包涵并指出,有疑问可以留言或私信我,一起探讨~