全志系列Tina Linux E907 RISC-V核 開發(fā)指南 多核異域架構(gòu)
1 編寫目的
介紹v85X 上E907 的啟動(dòng)環(huán)境和AMP 的環(huán)境搭建。
2 使用范圍
全志V85X 系列芯片
3 環(huán)境
E907 SDK:melis
4 SDK 快捷命令說明
這里主要介紹幾個(gè)下文會(huì)用到的命令,并不會(huì)介紹全部命令,如果想了解全部命令,可以在lunch 方案后使用hmm打印出所有tina提供的快捷命令。
ckernel, m kernel_menuconfig, mkernel:分別對(duì)應(yīng)進(jìn)入到內(nèi)核目錄,配置內(nèi)核,單獨(dú)編譯內(nèi)核
cboot0, mboot0:進(jìn)入boot0 目錄,單獨(dú)編譯boot0
cmelis, mmelis, mmelis menuconfig:分別對(duì)應(yīng)進(jìn)入melis 根目錄,編譯melis,配置melis
make:編譯整個(gè)tina 除了melis 外的所有東西,如boot0,uboot,內(nèi)核,跟文件系統(tǒng)等
cconfigs:進(jìn)入板級(jí)配置目錄,這里主要存放板級(jí)的設(shè)備樹,分區(qū)等配置文件
p:打包命令,將編譯后的東西打包成固件
5 E907 啟動(dòng)環(huán)境
5.1 預(yù)先工作
選擇方案
cd tina
source build/envsetup.sh
lunch
選擇對(duì)應(yīng)的V85x方案
5.2 配置boot0 啟動(dòng)e907
e907 在boot0 階段啟動(dòng),需要對(duì)boot0 進(jìn)行一些配置
cboot0
vim board/sun8iw21p1/common.mk
# 如下圖取消注釋
保存退出
mboot0 #編譯

圖5-1: 配置1
5.2.1 關(guān)閉RISCV 的IOMMU
本步驟只有需要在boot0 階段啟動(dòng)E907 的需要配置。打開設(shè)備樹,注釋掉下面2 條屬性,因?yàn)?e907 在boot0 階段就啟動(dòng)了,不能打開其IOMMU。
cconfigs
vim ../board.dts

圖5-2: 關(guān)閉IOMMU
5.3 配置打包e907 固件
cconfigs
cd ../../default/
vim boot_package_nor.cfg # 取消melis-elf選項(xiàng)的注釋,如下圖
vim boot_package.cfg # 取消melis-elf選項(xiàng)的注釋,如下圖
保存退出

圖5-3: 打包配置
5.4 Linux 配置
ckernel
m kernel_menuconfig
# 如下圖選中2個(gè)驅(qū)動(dòng)
mkernel -j

圖5-4: 補(bǔ)丁下載mmelis menuconfig # 如下圖選中standby支持

圖5-5: e907-standby 配置
5.5 編譯打包
至此關(guān)于E907 啟動(dòng)的配置完成,進(jìn)行編譯燒錄即可
make -j16 # 編譯tina
mmelis # 編譯melis
p
燒錄
6 AMP 環(huán)境搭建
AMP 環(huán)境用于Linux 和E907 間通信,Linux 依賴于2 個(gè)驅(qū)動(dòng),melis 依賴于openamp 驅(qū) 動(dòng)。
remoteproc 驅(qū)動(dòng):主要用來管理E907 固件的加載器的
rpmsg:在virtio 框架上實(shí)現(xiàn)的消息傳送框架
6.1 Linux 配置
注意:需要前面的啟動(dòng)環(huán)境配置好后,再執(zhí)行以下操作。 需要打開的配置有:
remoteproc 驅(qū)動(dòng)
rpmsg 驅(qū)動(dòng)
6.1.1 remoteproc 驅(qū)動(dòng)
ckernel
m kernel_menuconfig
選中

圖6-1: rproc config
6.1.2 rpmsg 驅(qū)動(dòng)
ckernel
m kernel_menuconfig
# 紅框必選,藍(lán)色框?yàn)閟dk提供的rpmsg demo,視情況而選擇
# 建議選上sunxi rpmsg ctrl driver 方便后面測(cè)試rpmsg通信功能
選中

圖6-2: rpmsg config
6.2 melis 配置
主要進(jìn)行2 個(gè)配置:
msgbox 配置
openamp 配置
6.2.1 msgbox 配置
mmelis menuconfig #選擇下面2項(xiàng)
選中

圖6-3: msgbox-melis config
6.2.2 openamp 配置
mmelis menuconfig
# 紅框是必選,藍(lán)框是可選的rpmsg demo
剛剛Linux 端選擇了rpmsg hearbeat demo 和ctrl driver,我們這里也選上對(duì)應(yīng)的驅(qū)動(dòng)hearbeatdriver 和client driver。 選中

圖6-4: openamp config
為了方便在控制臺(tái)測(cè)試rpmsg 通信,rpmsg client driver 還需開啟下面2 個(gè)選項(xiàng)

圖6-5: rpmsg client config
6.3 打包
make -j16 # 編譯tina
mmelis # 編譯melis
p
燒錄
6.4 測(cè)試
本章節(jié)介紹一些AMP 提供的控制臺(tái)命令,用于測(cè)試AMP 環(huán)境
6.4.1 E907 控制
1.在linux 控制臺(tái)執(zhí)行:echo stop > /sys/kernel/debug/remoteproc/remoteproc0/state (停止e907)
2.在linux 控制臺(tái)執(zhí)行:echo start > /sys/kernel/debug/remoteproc/remoteproc0/state (啟動(dòng)e907)
若控制臺(tái)出現(xiàn)remoteproc0: remote processor e907_rproc is now up,表明啟動(dòng)e907 成功。 如果使能了rpmsg_heartbeat 和rpmsg_ctrl 驅(qū)動(dòng),可以在Linux 控制臺(tái)start 之后會(huì)看到如下輸出:

圖6-6: rproc test
紅框里面表示有2 個(gè)設(shè)備成功創(chuàng)建,代表rpmsg 正常。
6.4.2 rpmsg 通信測(cè)試
借助rpmsg_ctrl 驅(qū)動(dòng)幫助我們進(jìn)行測(cè)試
6.4.2.1 名字監(jiān)聽.
平臺(tái):melis 控制臺(tái) 輸入如下圖命令: eptdev_bind 命令:監(jiān)聽name=test 的鏈接,最大連接數(shù)5 個(gè)

圖6-7: rproc test
6.4.2.2 節(jié)點(diǎn)創(chuàng)建
平臺(tái):Linux 控制臺(tái) 輸入如下圖的命令,進(jìn)行節(jié)點(diǎn)創(chuàng)建

圖6-8: rpmsg test

圖6-9: rpmsg test
根據(jù)log 可以看出,創(chuàng)建了一個(gè)rpmsg0-4 5 個(gè)設(shè)備,因?yàn)閙elis 只監(jiān)聽的5 個(gè),故最多只能創(chuàng)建5 個(gè)。
6.4.2.3 節(jié)點(diǎn)通信
rpmsg 節(jié)點(diǎn)支持標(biāo)準(zhǔn)的文件操作,直接讀寫即可。 Linux 向e907 發(fā)數(shù)據(jù):

圖6-10: rpmsg test

圖6-11: rpmsg test
e907 向Linux 發(fā)數(shù)據(jù):

圖6-12: rpmsg test

圖6-13: test
6.4.2.4 節(jié)點(diǎn)關(guān)閉
Linux 主動(dòng)釋放:

圖6-14: rpmsg test

圖6-15: rpmsg test
e907 主動(dòng)釋放:
圖6-16: rpmsg test
圖6-17: rpmsg test
e907 端接觸監(jiān)聽,會(huì)釋放所有的鏈接:
圖6-18: rpmsg test
圖6-19: rpmsg test
7 開發(fā)使用
7.1 rpmsg 內(nèi)核開發(fā)
linux 端請(qǐng)參考driver/rpmsg/rpmsg_client_e907.c 。
melis 端請(qǐng)參考ekernel/subsys/thirdparty/openamp/rpmsg_demo/ 目錄下的文件。
7.2 rpmsg 用戶層接口
控制臺(tái)調(diào)試命令參考測(cè)試章節(jié),這里列舉代碼使用示例。
Linux 端:
#include <linux/rpmsg.h>
# 創(chuàng)建端點(diǎn)
int fd;
struct rpmsg_ept_info info;
char ept_dev_name[32];
strcpy(info.name, "test");
info.id = 0xfffff; # id由itctl進(jìn)行更新
fd = open(ctrl_dev, O_RDWR);
ret = ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &info);
# 當(dāng)ioctl返回值==0時(shí),端點(diǎn)已經(jīng)創(chuàng)建成功,設(shè)備節(jié)點(diǎn)會(huì)出現(xiàn)在/dev/rpmsg%d(=info.id)下
close(fd);
#讀寫設(shè)備節(jié)點(diǎn)
snprintf(ept_dev_name, 32, "/dev/rpmsg%d", info.id);
fd = open(ept_dev_name, O_RDWR);
write,read,poll...
close(fd);
# 關(guān)閉節(jié)點(diǎn)
fd = open(ctrl_dev, O_RDWR);
ret = ioctl(fd, RPMSG_DESTROY_EPT_IOCTL, &info);
close(fd);
melis 端:
方法1:基于rpmsg_ctrl 驅(qū)動(dòng),等待主機(jī)建立連接
// 頭文件
#include <openamp/sunxi_helper/openamp.h>
static int ept_cb(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
// 收到數(shù)據(jù)
}
int bind_cb(struct rpmsg_ept_client *client)
{
// client綁定,每個(gè)client代表一個(gè)連接
// client->priv和client->ept->priv 可供用戶使用
}
int unbind_cb(struct rpmsg_ept_client *client)
{
// 連接關(guān)閉
}
int main()
{
// cnt: 監(jiān)聽的數(shù)量,即最多對(duì)test創(chuàng)建cnt個(gè)連接
// 最后一個(gè)參數(shù)priv,其實(shí)里面設(shè)置的是client->priv
rpmsg_client_bind("test", ept_cb, bind_cb, unbind_cb,
cnt, NULL);
// do some things
// 取消綁定會(huì)unbind所有與其相關(guān)的client
rpmsg_client_unbind("test");
}
具體代碼參考ekernel/subsys/thirdparty/openamp/rpmsg_demo/rpmsg_ctrl/test.c;
方法2:基于rpmsg 原生框架,melis 端主動(dòng)創(chuàng)建連接,觸發(fā)主機(jī)端的rpmsg driver 的probe。
melis 端代碼參考:
1.ekernel/subsys/thirdparty/openamp/rpmsg_demo/demo.c
2.ekernel/subsys/thirdparty/openamp/rpmsg_demo/hearbeat.c
Linux 端參考代碼:
1.drivers/rpmsg/rpmsg_client_e907.c
2.drivers/rpmsg/rpmsg_client_heart.c
7.3 amp 控制臺(tái)
SDK 在Linux 端提供了進(jìn)入E907 控制臺(tái)的功能,配置步驟如下:
內(nèi)核配置
ckernel
m kernel_menuconfig # 選擇下圖配置
圖7-1: rpmsg config
Tina 配置
croot
m menuconfig # 選擇下圖配置
圖7-2: amp_shell config
melis 配置
圖7-3: amp_shell config
編譯& 打包& 下載
mmelis -j32
make -j32
p
使用
在echo start > /sys/kernel/debug/remoteproc/remoteproc0/state 后檢查有無rpmsg_ctrl 成功創(chuàng)建的log 或者是否存在/dev/rpmsg_ctrl0 節(jié)點(diǎn)。如果正常,直
接在Linux 控制臺(tái)啊輸入amp_shell 即可進(jìn)入e907 控制臺(tái),amp_exit退出控制臺(tái)。支持執(zhí)行多次amp_shell,開啟多個(gè)控制臺(tái)。
圖7-4: amp_shell test
圖7-5: amp_shell test
7.4 大數(shù)據(jù)傳輸
由于rpmsg 特性,不適合傳輸大數(shù)據(jù)量;如需使用大數(shù)據(jù)傳輸,請(qǐng)參考本章節(jié)。
7.4.1 配置
內(nèi)核打開rpbuf 驅(qū)動(dòng):
m kernel_menuconfig
Device Drivers --->
RPBuf drivers --->
-*- RPBuf device interface
<*> RPMsg-based RPBuf service driver
<*> Allwinner RPBuf controller driver
<*> Allwinner RPBuf sample driver
Note:Allwinner RPBuf sample driver 是一個(gè)簡(jiǎn)單的rpbuf 內(nèi)核層使用demo,可以不使能。
e907 配置:
Kernel Setup
Subsystem support
Allwinner Components Support
RPBuf framework
? ? ? ? ? ? ? ?[*] RPMsg-based RPBuf service component
? ? ? ? ? ? ? ?[*] RPBuf controller component
? ? ? ? ? ? ? ?[*] RPMsg-based RPBuf service component demo
? ? ? ? ? ?OpenAMP Support
? ? ? ? ? ? ?[*] ?RPBuf demo
Tina 打開rpbuf_demo 軟件包:
m menuconfig
Allwinner --->
? ?RPBuf --->
? ? ? ?<*> rpbuf_demo
? ? ? ?<*> rpbuf_test
7.4.2 測(cè)試
rpmsg_test:會(huì)自動(dòng)生成隨機(jī)數(shù)據(jù)并附帶MD5 校驗(yàn)值,另一端收到會(huì)重新計(jì)算MD5 并與收到的進(jìn)行對(duì)比。
(e907) rpbuf_test -c -N "rpbuf_demo" -L 0x100000 # 創(chuàng)建size=0x100000的buffer
(Linux) rpbuf_test -d 1000 -s -L 0x100000 -N "rpbuf_demo" # 發(fā)送測(cè)試數(shù)據(jù)
(Linux) rpbuf_test -r -t 1000 -L 0x100000 -N "rpbuf_demo" # 接收數(shù)據(jù)
(e907) rpbuf_test -s -L 0x100000 -N "rpbuf_demo" #發(fā)送測(cè)試數(shù)據(jù)
(e907) rpbuf_test -N "rpbuf_demo" -d # 刪除buffer
出現(xiàn)success 表明校驗(yàn)成功。
過程log 如下:
圖7-6: Linux 端log
圖7-7: e907 端log
rpbuf_demo:用于在控制臺(tái)簡(jiǎn)單傳輸數(shù)據(jù)
(e907) rpbuf_demo -c -N "rpbuf_demo" -L 0x1000 # 創(chuàng)建size=4k的buffer
(Linux) rpbuf_demo -d 1000 -L 0x1000 -N "rpbuf_demo" -s "hello" # 發(fā)送數(shù)據(jù),并在1000ms后釋放
buffer
(Linux) rpbuf_demo -r -t 1000 -L 0x1000 -N "rpbuf_demo" # 接收數(shù)據(jù)
(e907) rpbuf_demo -s "hello" -N "rpbuf_demo" # 發(fā)送數(shù)據(jù)
(e907) rpbuf_demo -N "rpbuf_demo" -d # 刪除buffer
圖7-8: Linux 端log
圖7-9: e907 端log
7.4.3 使用
內(nèi)核層接口,參考drivers/rpbuf/rpbuf_sample_sunxi.c: Linux 端使用流程:
在需要用到rpbuf 接口的驅(qū)動(dòng)的設(shè)備樹節(jié)點(diǎn)種添加一條屬性:rpbuf = <&rpbuf_controller0>;, 可以創(chuàng)建多個(gè)controller,當(dāng)面默認(rèn)只有一個(gè)rpbuf_controller0;
獲取controller:調(diào)用controller = rpbuf_get_controller_by_of_node(np, 0);
創(chuàng)建buffer:調(diào)用rpbuf_alloc_buffer(controller, name, len, ops, cbs, priv);
接收數(shù)據(jù):收到數(shù)據(jù)時(shí)候會(huì)調(diào)用cbd->rx_cb 回調(diào)
判斷狀態(tài):創(chuàng)建出的buffer 不一樣馬上可用,需要用判斷狀態(tài),調(diào)用rpbuf_buffer_is_available(buffer)
發(fā)送數(shù)據(jù):
buf_va = rpbuf_buffer_va(buffer);
buf_len = rpbuf_buffer_len(buffer);
直接對(duì)buf_va 地址進(jìn)行寫入即可
rpbuf_transmit_buffer(buffer, offset, data_len);
釋放buffer:rpbuf_free_buffer(buffer);
應(yīng)用層端口,具體細(xì)節(jié)可以參考package/allwinner/rpbuf/
創(chuàng)建buffer
fd = open(0, O_RDWR);
ioctl(fd, RPBUF_CTRL_DEV_IOCTL_CREATE_BUF, &buffer->info);
buf_fd = open(buf_dev_path, O_RDWR);
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, buf_fd, 0);
接收數(shù)據(jù):
rpbuf_receive_buffer_block(buffer, &offset, &data_len) 阻塞接收
rpbuf_receive_buffer_nonblock(buffer, &offset, &data_len) 非阻塞接收
發(fā)送數(shù)據(jù):
buf_va = rpbuf_buffer_va(buffer);
直接對(duì)buf_va 地址進(jìn)行寫入即可
rpbuf_transmit_buffer(buffer, offset, data_len);
釋放buffer:
close(buf_fd);
ioctl(fd, RPBUF_CTRL_DEV_IOCTL_DESTROY_BUF, &buffer->info);
close(fd);
e907 端接口,可以參考ekernel/subsys/aw/rpbuf/rpbuf_demo/rpbuf_demo.c e907 端使用流程:
獲取controller:調(diào)用controller = rpbuf_get_controller_by_id(0); 代碼默認(rèn)提供一個(gè)controller, 這里直接使用
創(chuàng)建buffer:調(diào)用rpbuf_alloc_buffer(controller, name, len, ops, cbs, priv);
接收數(shù)據(jù):收到數(shù)據(jù)時(shí)候會(huì)調(diào)用cbd->rx_cb 回調(diào)
判斷狀態(tài):創(chuàng)建出的buffer 不一樣馬上可用,需要用判斷狀態(tài),調(diào)用rpbuf_buffer_is_available (buffer)
發(fā)送數(shù)據(jù):
buf_va = rpbuf_buffer_va(buffer);
buf_len = rpbuf_buffer_len(buffer);
直接對(duì)buf_va 地址進(jìn)行寫入即可
rpbuf_transmit_buffer(buffer, offset, data_len);
釋放buffer:rpbuf_free_buffer(buffer);
7.4.4 Note
關(guān)于controller:代碼默認(rèn)已經(jīng)提供了一個(gè)基于rpmsg 實(shí)現(xiàn)的controller0 了,正常情況下 直接使用改controller 即可
關(guān)于rpbuf_alloc_buffer 的ops 參數(shù):controller0 已經(jīng)基于ion 實(shí)現(xiàn)了內(nèi)存分配函數(shù)。如 無必要,使用controller 的內(nèi)存分配函數(shù)即可,即創(chuàng)建buffer 時(shí),ops 參數(shù)置NULL。
關(guān)于互斥:由于通信雙方都能拿到的buffer 的地址,難以在驅(qū)動(dòng)實(shí)現(xiàn)互斥,所以需要在具體 應(yīng)用上自行保證互斥。
8 其他
8.1 rpmsg 需知
端點(diǎn)是rpmsg 通信的基礎(chǔ);每個(gè)端點(diǎn)都有自己的src 和dst 地址,范圍(1 - 1023,除了0x35)
rpmsg 每次發(fā)送數(shù)據(jù)最大為512 -16 字節(jié);(數(shù)據(jù)塊大小為512,頭部占用16 字節(jié))
rpmsg 使用name server 機(jī)制,當(dāng)E907 創(chuàng)建的端點(diǎn)名,和linux 注冊(cè)的rpmsg 驅(qū)動(dòng)名一樣的時(shí)候,rpmsg bus 總線會(huì)調(diào)用其probe 接口。所以如果需要
?Linux 端主動(dòng)發(fā)起創(chuàng)建端點(diǎn)并通知e907,則需要借助上面提到的rpmsg_ctrl 驅(qū)動(dòng)。
rpmsg 是串行調(diào)用回調(diào)的,故建議rpmsg_driver 的回調(diào)中不要調(diào)用耗時(shí)長(zhǎng)的函數(shù),避免影響其他rpmsg 驅(qū)動(dòng)的運(yùn)行
8.2 rpbuf 簡(jiǎn)介
rpbuf 全志基于rpmsg 開發(fā)的一套通信機(jī)制,它主要解決rpmsg 不適合傳輸大數(shù)據(jù)量的問題。 其實(shí)現(xiàn)原理是使用rpmsg 傳輸數(shù)據(jù)的地址,而不是數(shù)據(jù)的本身,避免了數(shù)據(jù)的多次拷貝以及每次 傳輸不能大于496 字節(jié)的限制。 rpbuf 中使用名字和長(zhǎng)度來唯一標(biāo)識(shí)一個(gè)buffer,故不能創(chuàng)建相同名字的buffer。 rpbuf 中的buffer 有3 個(gè)狀態(tài):
remote_dummy_buffers:該buffer 遠(yuǎn)端已創(chuàng)建,本地未創(chuàng)建
local_dummy_buffers:該buffer 本地已創(chuàng)建,遠(yuǎn)端未創(chuàng)建
buffers:遠(yuǎn)端、本地已創(chuàng)建,此時(shí)buffer 才可用
8.3 修改e907 地址
目前在perf1 板子上,給e907 預(yù)留的內(nèi)存為:0x48000000 開始的4M 空間
如果需要修改E907 固件的運(yùn)行地址和大小,可按如下步驟進(jìn)行修改:
8.3.1 修改設(shè)備樹(Linux)
cconfigs
vim ../board.dts
# 找到e907_dram項(xiàng),修改成想要的地址,例如這里向修改成0x49000000
e907_dram: riscv_memserve {
reg = <0x0 0x49000000 0x0 0x00400000>;
no-map;
};
# 重新編譯內(nèi)核
mkernel
8.3.2 修改配置項(xiàng)(melis)
mmelis menuconfig
# 如下圖進(jìn)行修改;e907沒有mmu,故第一項(xiàng)和第二項(xiàng)相等
# 將第一項(xiàng)和第二項(xiàng)改成0x49000000
# 第三項(xiàng)為大小,可按需修改
圖8-1: e907 dram config
8.3.3 修改鏈接腳本(melis)
cmelis
vim source/projects/v853-e907-ver1-board/kernel.lds
# 如下圖所示,按照所需修改DRAM_SEG_KRN 項(xiàng)目
mmelis -j16

圖8-2: e907 lds config
8.4 添加新板級(jí)注意事項(xiàng)
當(dāng)用戶需要添加新的板子時(shí),需要注意修改build/expand_melis.sh 來支持mmelis, cmelis命令。例如,用戶在添加了新的板級(jí)v853_user,在melis 添加了新的板
級(jí)e907_user,則需要對(duì)build/expand_melis.sh文件進(jìn)行如下修改:

圖8-3: 新板級(jí)配置
8.5 melis 系統(tǒng)
8.5.1 常用命令
help:列出當(dāng)前系統(tǒng)支持的所有命令
p addr [len]:打印內(nèi)存數(shù)據(jù)
m addr value:修改內(nèi)存數(shù)據(jù)
top:顯示當(dāng)前系統(tǒng)各個(gè)線程CPU 占用率
ps:顯示當(dāng)前系統(tǒng)各個(gè)線程狀態(tài)
free:查看當(dāng)前系統(tǒng)內(nèi)存信息
8.5.2 自定義命令
當(dāng)用戶想要在e907 控制臺(tái)上執(zhí)行自定義的命令時(shí)候,可以用FINSH_FUNCTION_EXPORT_ALIAS導(dǎo)出自定義的函數(shù)。例如:

圖8-4: 添加自定義命令

圖8-5: 執(zhí)行自定義命令