概要
上一篇文章,介紹了多核異構(gòu)的方案,RPmsg-lite多核通信框架的內(nèi)容。--《多核異構(gòu)通信框架(RPMsg-Lite)》
本篇文章我們主要來(lái)講講RK3568上的多核加載流程,實(shí)驗(yàn)的板子:風(fēng)火輪科技的YY3568開(kāi)發(fā)板。
YY3568主板基于 Rockchip RK3568 芯片平臺(tái),四核 64位 Cortex-A55 核,主頻最高達(dá) 2GHz,集成雙核心架構(gòu)GPU以及高效能NPU,芯片性能優(yōu)異。開(kāi)發(fā)板功能接口豐富,多媒體性能強(qiáng)悍、可在物聯(lián)網(wǎng)、工業(yè)控制、智慧交通、輕量級(jí)人工智能等領(lǐng)域發(fā)揮獨(dú)特優(yōu)勢(shì)。
板載有 2路DSI、1路HDMI 和 1路edp顯示接口。支持雙屏異顯輸出和4K分辨率。強(qiáng)大的顯示性能,并且適配了自研的7寸mipi屏和edp屏。在多屏廣告機(jī)、電子站牌、自助服務(wù)機(jī)、工業(yè)HMI等領(lǐng)域可發(fā)揮強(qiáng)大優(yōu)勢(shì)以及更低的成本。
板載 2 路千兆 以太網(wǎng),可通過(guò)雙網(wǎng)口訪問(wèn)和傳輸內(nèi)外網(wǎng)的數(shù)據(jù)。擁有WIFI/BT,PCIE 3.0接口及 SIM 座,可接 4G 通信模塊,提高網(wǎng)絡(luò)傳輸效率。滿足NVR、工業(yè)網(wǎng)關(guān)等多網(wǎng)口產(chǎn)品需求。
板載 5路 串口,能夠大大降低通信成本。2 路IIC,可接多個(gè)IIC設(shè)備。1路CAN,能夠滿足汽車電子領(lǐng)域需求。
板載PCIE3.0和SATA接口,支持固態(tài)硬盤(pán)M.2,SATA硬盤(pán),可擴(kuò)展大容量硬盤(pán)。
YY3568多核啟動(dòng)方案
瑞芯微官方提供了4種多核軟件方案。但是啟動(dòng)流程的大致方案是一致的。其方案為:
方案 | 說(shuō)明 |
---|---|
3kernel + 1hal | 0~2核心:Linux(SMP),3核心:裸機(jī) |
3kernel + 1RT-Thread | 0~2核心:Linux(SMP),3核心:RT-Thread(RTOS) |
1kernel + 3hal | 0核心:Linux,1~3核心:裸機(jī)(每一個(gè)核心跑一個(gè)裸機(jī)) |
2kernel + 3RT-Thread | 0核心:Linux,1~3核心:RT-Thread(每一個(gè)核心跑一個(gè)RTOS) |
YY3568多核啟動(dòng)分析
我們?cè)陲L(fēng)火輪科技的YY3568開(kāi)發(fā)板上驗(yàn)證的方案:3kernel(SMP) + 1RT-Thread。
啟動(dòng)配置
多核啟動(dòng)配置文件路徑:device/rockchip/rk3568/rk3568_amp_linux.its。
rk3568_amp_linux.its配置文件格式,其以設(shè)備樹(shù)的格式存在。所以操作其內(nèi)容的方法可以通過(guò)操作設(shè)備樹(shù)一樣。
多核啟動(dòng)主要分為兩個(gè)核心節(jié)點(diǎn):
①conf節(jié)點(diǎn)描述:描述需要啟動(dòng)那些子核心(節(jié)點(diǎn):loadables),linux內(nèi)核啟動(dòng)參數(shù)(節(jié)點(diǎn):linux)。
②images節(jié)點(diǎn)描述:描述需要啟動(dòng)子核心的參數(shù),如:架構(gòu),指令集,分區(qū)首地址,核啟動(dòng)延遲等。
/{ description="FITsourcefileforrockchipAMP"; #address-cells=<1>; images{ amp3{ description="bare-mental-core3"; data=/incbin/("cpu3.bin");//打包前的固件位置,一般不需要 type="firmware"; compression="none"; arch="arm";//固件的指令架構(gòu),當(dāng)前只支持arm cpu=<0x300>;//mpidr thumb=<0>;//0:armorthumb2;1:thumb hyp=<0>;//0:el1/svc;1:el2/hyp load=<0x02800000>;//內(nèi)存分區(qū)起始地址 udelay=<10000>;//啟動(dòng)下一個(gè)核心的延遲時(shí)間 hash{ algo="sha256"; }; }; }; configurations{ default="conf"; conf{ description="RockchipAMPimages"; rollback-index=<0x0>; loadables="amp3"; signature{ algo="sha256,rsa2048"; padding="pss"; key-name-hint="dev"; sign-images="loadables"; }; /*-runlinuxoncpu0 *-itisbroughtupbyamp(thatrunonU-Boot) *-itisbootentrydependsonU-Boot */ linux{ description="linux-os"; arch="arm64"; cpu=<0x000>; thumb=<0>; hyp=<0>; udelay=<0>; }; }; }; };
內(nèi)存分區(qū)
描述了每個(gè)核心的內(nèi)存起始地址以及內(nèi)存分區(qū)大小。
我們采用的方案:3kernel(SMP) + 1RT-Thread,所以RT-Thread的內(nèi)存位置為:CPU3_MEM_BASE=0x02800000。
# Linux + HAL/RTT形式的內(nèi)存資源分區(qū)示例: CPU0_MEM_BASE=0x03000000 CPU1_MEM_BASE=0x01800000 CPU2_MEM_BASE=0x02000000 CPU3_MEM_BASE=0x02800000 CPU0_MEM_SIZE=0x00800000 CPU1_MEM_SIZE=0x00800000 CPU2_MEM_SIZE=0x00800000 CPU3_MEM_SIZE=0x00800000
amp固件打包
RK3568的amp固件,其包含的內(nèi)容:?jiǎn)?dòng)配置信息(rk3568_amp_linux.its) + 從核的代碼。
它是通過(guò)mkimage將兩者打包一起的,工具路徑:device/rockchip/common/mkimage。
打包命令:mkimage -f amp.its -E -p 0xe00 amp.img,其中:
0xe00:它是its在固件的大小,如果its文件大小不足對(duì)應(yīng)大小,則補(bǔ)0。
從核的代碼追加在其后面。
源碼分析
內(nèi)核啟動(dòng)流程--準(zhǔn)備工作
RK3568的多核啟動(dòng)是由uboot來(lái)管理的,所以我們主要剖析uboot的源碼。
多核啟動(dòng)流程的代碼路徑:uboot/drivers/cpu/rockchip_amp.c。
多核啟動(dòng)的函數(shù)入口:int amp_cpus_on(void)。
啟動(dòng)核心的程序,需要提前準(zhǔn)備4個(gè)動(dòng)作:
獲取設(shè)備的啟動(dòng)設(shè)備,我們YY3568目前采用的是EMMC,所以這里描述的就是EMMC設(shè)備;然后從啟動(dòng)設(shè)備獲取AMP分區(qū)。
申請(qǐng)存放頭信息的空間,從AMP分區(qū)中獲取頭信息(即多核啟動(dòng)配置信息:rk3568_amp_linux.its);檢測(cè)its的合法性,并獲取其大小。
申請(qǐng)固件的內(nèi)存,從AMP分區(qū)獲取從核心的內(nèi)容。
通過(guò)頭部信息,解析可加載項(xiàng)。然后調(diào)用brought_up_all_amp()啟動(dòng)所有核心。
intamp_cpus_on(void) { ....省略 dev_desc=rockchip_get_bootdev(); ....省略 if(part_get_info_by_name(dev_desc,AMP_PART,&part)0)???????//?① ?....省略 ?hdr?=?memalign(ARCH_DMA_MINALIGN,?FIT_HEADER_SIZE); ?....省略 ?/*?get?totalsize?*/ ?offset?=?part.start; ?cnt?=?DIV_ROUND_UP(FIT_HEADER_SIZE,?part.blksz); ?if?(blk_dread(dev_desc,?offset,?cnt,?hdr)?!=?cnt)?{ ?....省略 ?if?(fdt_check_header(hdr))?{ ?....省略 ?if?(fit_get_totalsize(hdr,?&totalsize))?{???????????//?② ?....省略 ?/*?load?image?*/ ?fit?=?memalign(ARCH_DMA_MINALIGN,?ALIGN(totalsize,?part.blksz)); ?....省略 ?offset?+=?cnt; ?cnt?=?DIV_ROUND_UP(totalsize,?part.blksz)?-?cnt; ?if?(blk_dread(dev_desc,?offset,?cnt,?fit?+?FIT_HEADER_SIZE)?!=?cnt)?{???//?③ ?....省略 ?ret?=?parse_os_amp_dispatcher(); ?....省略 ?/*?Load?loadables?*/ ?memset(&images,?0,?sizeof(images)); ?images.fit_uname_cfg?=?"conf"; ?images.fit_hdr_os?=?fit; ?images.verify?=?1; ?ret?=?boot_get_loadable(0,?NULL,?&images,?IH_ARCH_DEFAULT,?NULL,?NULL);?????//?④ ?....省略 ?/*?Wakeup?*/ ?ret?=?brought_up_all_amp(images.fit_hdr_os,?images.fit_uname_cfg);?//⑤ ?....省略 }
內(nèi)核啟動(dòng)流程--加載項(xiàng)獲取
核心啟動(dòng)分為兩部分:Linux內(nèi)核啟動(dòng)部分 + 非Linux內(nèi)核(RT-Thread)啟動(dòng)部分。
Linux內(nèi)核啟動(dòng)部分:從rk3568_amp_linux.its配置中獲取Linux節(jié)點(diǎn)。然后調(diào)用brought_up_amp()啟動(dòng)內(nèi)核。
非Linux內(nèi)核(RT-Thread)啟動(dòng)部分:從rk3568_amp_linux.its配置中獲取loadables節(jié)點(diǎn),遍歷節(jié)點(diǎn)成員,獲取對(duì)應(yīng)的加載項(xiàng)的配置信息,然后調(diào)用調(diào)用brought_up_amp()啟動(dòng)內(nèi)核。
staticintbrought_up_all_amp(void*fit,constchar*fit_uname_cfg) { ....省略 g_bootcpu.boot_on=1; linux_noffset=fdt_subnode_offset(fit,conf_noffset,"linux");//① if(linux_noffset>0){ ret=brought_up_amp(fit,linux_noffset,&g_bootcpu,1); if(ret) returnret; } for(loadables_index=0;//② uname=fdt_stringlist_get(fit,conf_noffset, FIT_LOADABLE_PROP,loadables_index,NULL),uname; loadables_index++){ cpu_noffset=fit_image_get_node(fit,uname); if(cpu_noffset0) ???return?cpu_noffset; ??ret?=?brought_up_amp(fit,?cpu_noffset,?&g_bootcpu,?0); ??if?(ret) ???return?ret; ?} ????....省略 ?return?0; }
內(nèi)核啟動(dòng)流程--核心配置參數(shù)獲取
我們獲取了加載項(xiàng)節(jié)點(diǎn)之后,從節(jié)點(diǎn)中獲取其加載參數(shù),獲取方式跟設(shè)備樹(shù)樹(shù)獲取一致。
通過(guò)smc_cpu_on()啟動(dòng)核心
staticintbrought_up_amp(void*fit,intnoffset, boot_cpu_t*bootcpu,intis_linux) { ....省略 desc=fdt_getprop(fit,noffset,"description",NULL); cpu=fit_get_u32_default(fit,noffset,"cpu",-ENODATA); hyp=fit_get_u32_default(fit,noffset,"hyp",0); thumb=fit_get_u32_default(fit,noffset,"thumb",0); entry=load=fit_get_u32_default(fit,noffset,"load",-ENODATA); us=fit_get_u32_default(fit,noffset,"udelay",0); boot_on=fit_get_u32_default(fit,noffset,"boot-on",1); fit_image_get_arch(fit,noffset,&arch); fit_image_get_type(fit,noffset,&type); fit_image_get_data_size(fit,noffset,&data_size); memset(&args,0,sizeof(args)); ....省略 /*bootnow*/ ret=smc_cpu_on(cpu,pe_state,entry,&args,is_linux); if(ret) returnret; exit: if(us) udelay(us); return0; }
內(nèi)核啟動(dòng)流程--內(nèi)核啟動(dòng)
檢測(cè)pe狀態(tài),如果目標(biāo)pe狀態(tài)是默認(rèn)的arch狀態(tài),則直接給cpu通電
如果非Linux系統(tǒng)則跳轉(zhuǎn)到finish下,直接啟動(dòng)啟動(dòng)內(nèi)核。
如果是Linux系統(tǒng)需要設(shè)置啟動(dòng)參數(shù),然后再啟動(dòng)內(nèi)核。
staticintsmc_cpu_on(u32cpu,u32pe_state,u32entry, boot_args_t*args,boolis_linux) { ....省略 /*iftargetpestateisdefaultarchstate,powerupcpudirectly*/ if(is_default_pe_state(pe_state)) gotofinish; ret=sip_smc_amp_cfg(AMP_PE_STATE,cpu,pe_state,0); if(ret){ AMP_E("smcpe-state,ret=%dn",ret); returnret; } /*onlylinuxneedsbootargs*/ if(!is_linux) gotofinish; ret=sip_smc_amp_cfg(AMP_BOOT_ARG01,cpu,args->arg0,args->arg1); if(ret){ AMP_E("smcbootarg01,ret=%dn",ret); returnret; } ret=sip_smc_amp_cfg(AMP_BOOT_ARG23,cpu,args->arg2,args->arg3); if(ret){ AMP_E("smcbootarg23,ret=%dn",ret); returnret; } finish: ret=psci_cpu_on(cpu,entry); if(ret){ printf("cpuupfailed,ret=%dn",ret); returnret; } printf("OKn"); return0; }
多核啟動(dòng)效果
我們多核的方案:3kernel(SMP) + 1RT-Thread,
我們需要準(zhǔn)備兩個(gè)串口,一個(gè)為L(zhǎng)inux端的終端信息打印(UART2),一個(gè)為RT-Thread端的終端信息打印(UART4)
YY3568已經(jīng)將所有的串口引出,所以我們調(diào)試很方便,接線圖如下:
運(yùn)行效果:
5. 視頻演示
審核編輯 黃宇
-
Linux
+關(guān)注
關(guān)注
87文章
11304瀏覽量
209483 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1289瀏覽量
40124
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論