风火轮科技YY3568开发板上的多核方案:3kernel(SMP) + 1RT-Thread。
/ {
description = "FIT source file for rockchip AMP";
#address-cells = <1>;
images {
amp3 {
description = "bare-mental-core3";
data = /incbin/("cpu3.bin"); // 打包前的固件位置,一般不需要
type = "firmware";
compression = "none";
arch = "arm"; // 固件的指令架构,当前只支持arm
cpu = <0x300>; // mpidr
thumb = <0>; // 0: arm or thumb2; 1: thumb
hyp = <0>; // 0: el1/svc; 1: el2/hyp
load = <0x02800000>; // 内存分区起始地址
udelay = <10000>; // 启动下一个核心的延迟时间
hash {
algo = "sha256";
};
};
};
configurations {
default = "conf";
conf {
description = "Rockchip AMP images";
rollback-index = <0x0>;
loadables = "amp3";
signature {
algo = "sha256,rsa2048";
padding = "pss";
key-name-hint = "dev";
sign-images = "loadables";
};
/* - run linux on cpu0
* - it is brought up by amp(that run on U-Boot)
* - it is boot entry depends on U-Boot
*/
linux {
description = "linux-os";
arch = "arm64";
cpu = <0x000>;
thumb = <0>;
hyp = <0>;
udelay = <0>;
};
};
};
};
int amp_cpus_on(void)
{
....省略
dev_desc = rockchip_get_bootdev();
....省略
if (part_get_info_by_name(dev_desc, AMP_PART, &part) < 0) // ① 获取设备的启动设备,我们YY3568目前采用的是EMMC,所以这里描述的就是EMMC设备;然后从启动设备获取AMP分区
....省略
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)) { // ② 申请存放头信息的空间,从AMP分区中获取头信息(即多核启动配置信息:rk3568_amp_linux.its);检测its的合法性,并获取其大小
....省略
/* 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) { // ③ 申请固件的内存,从AMP分区获取从核心的内容
....省略
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); // ④ 通过头部信息,解析可加载项。然后调用brought_up_all_amp()启动所有核心
....省略
/* Wakeup */
ret = brought_up_all_amp(images.fit_hdr_os, images.fit_uname_cfg); //⑤
....省略
}
static int brought_up_all_amp(void *fit, const char *fit_uname_cfg)
{
....省略
g_bootcpu.boot_on = 1;
linux_noffset = fdt_subnode_offset(fit, conf_noffset, "linux"); // ① Linux核心
if (linux_noffset > 0) {
ret = brought_up_amp(fit, linux_noffset, &g_bootcpu, 1);
if (ret)
return ret;
}
for (loadables_index = 0; // ② RT-Thread核心
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_noffset < 0)
return cpu_noffset;
ret = brought_up_amp(fit, cpu_noffset, &g_bootcpu, 0);
if (ret)
return ret;
}
....省略
return 0;
}
static int brought_up_amp(void *fit, int noffset,
boot_cpu_t *bootcpu, int is_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));
....省略
/* boot now */
ret = smc_cpu_on(cpu, pe_state, entry, &args, is_linux);
if (ret)
return ret;
exit:
if (us)
udelay(us);
return 0;
}
static int smc_cpu_on(u32 cpu, u32 pe_state, u32 entry,
boot_args_t *args, bool is_linux)
{
....省略
/* if target pe state is default arch state, power up cpu directly */
if (is_default_pe_state(pe_state))
goto finish;
ret = sip_smc_amp_cfg(AMP_PE_STATE, cpu, pe_state, 0);
if (ret) {
AMP_E("smc pe-state, ret=%d\n", ret);
return ret;
}
/* only linux needs boot args */
if (!is_linux)
goto finish;
ret = sip_smc_amp_cfg(AMP_BOOT_ARG01, cpu, args->arg0, args->arg1);
if (ret) {
AMP_E("smc boot arg01, ret=%d\n", ret);
return ret;
}
ret = sip_smc_amp_cfg(AMP_BOOT_ARG23, cpu, args->arg2, args->arg3);
if (ret) {
AMP_E("smc boot arg23, ret=%d\n", ret);
return ret;
}
finish:
ret = psci_cpu_on(cpu, entry);
if (ret) {
printf("cpu up failed, ret=%d\n", ret);
return ret;
}
printf("OK\n");
return 0;
}