前言

本文基于正点原子 ATK‑MP257(STM32MP257,2GB DDR、eMMC 启动)完整工程实践,记录整套 BSP 开发三大核心问题:

  1. 自定义 BSP 与 ST 官方层混用,多构建目录之间DL_DIR/SSTATE_DIR缓存互相污染,构建结果不可控;
  2. 固件烧录后 OP‑TEE 安全世界 panic,TF‑A→OP‑TEE 阶段卡死,无法进入 U‑Boot 与 Linux 系统;
  3. 将 repo 检出的 OpenSTLinux 整套构建树转为 Git 快照仓库,遇到 gitlink 空目录、顶层目录改名路径连锁报错。

硬件:ALIENTEK ATK‑MP257 核心板(STM32MP257,2GB DDR eMMC) 软件版本:openstlinux‑6.6‑yocto‑scarthgap‑mpu‑v26.06.10,OpenSTLinux v6.2.1 / Yocto Scarthgap / OE‑core 5.x 启动链:TF‑A (BL2) → OP‑TEE (BL32) → U‑Boot (BL33) → Linux 适配方式:OpenSTLinux external‑dt 外部设备树注入 工程仓库:atk‑mp257,为 repo 环境的快照仓库,克隆即编译,不依赖 repo 工具

原始 repo 检出目录结构:

Distribution‑Package/
├─ .repo/                          # repo元数据目录
├─ layers/
│  ├─ meta‑atk‑mp257/              # 待重构板级BSP层
│  ├─ meta‑st/                     # ST官方BSP集合层
│  ├─ meta‑openembedded/
│  └─ openembedded‑core/
├─ build‑openstlinuxweston‑stm32mp257‑atk/
└─ build‑openstlinuxweston‑stm32mp2/

一、meta‑atk‑mp257 集合层 fork 重构(参考米尔 meta‑myir 方案)

原始方案将板级 dts、bbappend 全部放在单薄的meta‑atk‑mp257薄层,编译依赖外部meta‑st,不同机器共用下载与 sstate 缓存。

设计思路:完整 fork meta‑st下面三套子层封装为独立集合层;保留原有BBFILE_COLLECTIONSLAYERDEPENDS名称不修改,仅修改文件路径;板级 machine、设备树、bbappend 迁移到 fork 后的 BSP 子层,实现编译环境完全隔离。

1.1 备份原有板级资源

mkdir -p /tmp/atk-orig/conf/machine \
         /tmp/atk-orig/recipes-kernel/linux/linux-stm32mp \
         /tmp/atk-orig/recipes-extended/external-dt/external-dt/{optee,tf-a,u-boot}
cd /home/ubuntu/Distribution-Package/layers/meta-atk-mp257
cp conf/machine/stm32mp257-atk.conf            /tmp/atk-orig/conf/machine/
cp recipes-kernel/linux/linux-stm32mp_%.bbappend  /tmp/atk-orig/recipes-kernel/linux/
cp recipes-kernel/linux/linux-stm32mp/stm32mp257d-atk-ddr-2GB*.dts* \
   recipes-kernel/linux/linux-stm32mp/stm32mp25-pinctrl-atk-ddr-2GB.dtsi \
   /tmp/atk-orig/recipes-kernel/linux/linux-stm32mp/
cp recipes-extended/external-dt/external-dt_%.bbappend \
   /tmp/atk-orig/recipes-extended/external-dt/
cp recipes-extended/external-dt/external-dt/optee/* \
   recipes-extended/external-dt/external-dt/tf-a/* \
   recipes-extended/external-dt/external-dt/u-boot/* \
   /tmp/atk-orig/recipes-extended/external-dt/external-dt/

1.2 fork ST 官方层

复制脚本与 BSP 三层,过滤.git.repo版本控制文件

cd /home/ubuntu/Distribution-Package/layers
rm -rf meta-atk-mp257
mkdir -p meta-atk-mp257
rsync -a --exclude='.git' --exclude='.repo' \
    meta-st/scripts/                      meta-atk-mp257/scripts/
rsync -a --exclude='.git' --exclude='.repo' \
    meta-st/meta-st-stm32mp/              meta-atk-mp257/meta-atk-mp257-stm32mp/
rsync -a --exclude='.git' --exclude='.repo' \
    meta-st/meta-st-stm32mp-addons/       meta-atk-mp257/meta-atk-mp257-stm32mp-addons/
rsync -a --exclude='.git' --exclude='.repo' \
    meta-st/meta-st-openstlinux/          meta-atk-mp257/meta-atk-mp257-openstlinux/
find meta-atk-mp257 -name '.git*' -exec rm -rf {} + 2>/dev/null

1.3 迁移板级配置、设备树到 fork 后的 BSP 子层

cd /home/ubuntu/Distribution-Package/layers/meta-atk-mp257
BSP=meta-atk-mp257-stm32mp
cp /tmp/atk-orig/conf/machine/stm32mp257-atk.conf $BSP/conf/machine/
ln -sf ST_EULA_SLA $BSP/conf/eula/stm32mp257-atk

mkdir -p $BSP/recipes-kernel/linux/linux-stm32mp
cp /tmp/atk-orig/recipes-kernel/linux/linux-stm32mp_%.bbappend $BSP/recipes-kernel/linux/
cp /tmp/atk-orig/recipes-kernel/linux/linux-stm32mp/* $BSP/recipes-kernel/linux/linux-stm32mp/

mkdir -p $BSP/recipes-extended/external-dt/external-dt/{optee,tf-a,u-boot}
cp /tmp/atk-orig/recipes-extended/external-dt/external-dt_%.bbappend \
   $BSP/recipes-extended/external-dt/
cp /tmp/atk-orig/recipes-extended/external-dt/external-dt/optee/* \
   $BSP/recipes-extended/external-dt/external-dt/optee/
cp /tmp/atk-orig/recipes-extended/external-dt/external-dt/tf-a/* \
   $BSP/recipes-extended/external-dt/external-dt/tf-a/
cp /tmp/atk-orig/recipes-extended/external-dt/external-dt/u-boot/* \
   $BSP/recipes-extended/external-dt/external-dt/u-boot/

1.4 修改 envsetup.sh(关键)

修改集合层根路径:

sed -i 's|_META_LAYER_ROOT=layers/meta-st|_META_LAYER_ROOT=layers/meta-atk-mp257|' \
    layers/meta-atk-mp257/scripts/envsetup.sh

1.5 修改 bblayers.conf.sample 模板

路径:layers/meta‑atk‑mp257/meta‑atk‑mp257‑openstlinux/conf/templates/default/bblayers.conf.sample

BSPLAYER ?= " \
    ${@'${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-stm32mp' if os.path.isfile('${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-stm32mp/conf/layer.conf') else ''} \
    "
ADDONSLAYERS += "${@'${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-stm32mp-addons' if os.path.isfile('${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-stm32mp-addons/conf/layer.conf') else ''}"
FRAMEWORKLAYERS += "${@'${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-openstlinux' if os.path.isfile('${OEROOT}/layers/meta-atk-mp257/meta-atk-mp257-openstlinux/conf/layer.conf') else ''}"

重要:fork 子层内部layer.confBBFILE_COLLECTIONSLAYERDEPENDS保持 ST 原版,不要修改,否则 Yocto 层依赖校验直接失败。

1.6 重构后目录结构(layers 阶段)

layers/meta-atk-mp257/
├─ scripts/
├─ meta-atk-mp257-stm32mp/                     # BSP主层,存放atk板级machine、dts、bbappend
│   ├─ conf/machine/stm32mp257-atk.conf
│   ├─ conf/eula/stm32mp257-atk  -> ST_EULA_SLA
│   ├─ recipes-kernel/linux/linux-stm32mp/
│   └─ recipes-extended/external-dt/
├─ meta-atk-mp257-stm32mp-addons/
└─ meta-atk-mp257-openstlinux/

关键点:meta‑atk‑mp257此时是集合容器目录,本身没有 layer.conf,真正 BSP 层是内部子目录。旧 build 配置中如果直接引用容器目录会报找不到 layer.conf 错误。

1.7 生成独立编译构建目录,隔离缓存

cd /home/ubuntu/Distribution-Package
DISTRO=openstlinux-weston \
MACHINE=stm32mp257-atk \
BUILD_DIR=build-openstlinuxweston-stm32mp257-atk \
EULA_stm32mp257atk=1 \
source layers/meta-atk-mp257/scripts/envsetup.sh --no-ui

build‑openstlinuxweston‑stm32mp257‑atk/conf/site.conf配置本地缓存,和其他构建完全隔离:

DL_DIR = "/home/ubuntu/Distribution-Package/build-openstlinuxweston-stm32mp257-atk/downloads"
SSTATE_DIR = "/home/ubuntu/Distribution-Package/build-openstlinuxweston-stm32mp257-atk/sstate-cache"

1.8 解析验证(不编译,快速校验)

source layers/openembedded-core/oe-init-build-env build-openstlinuxweston-stm32mp257-atk
bitbake -p
bitbake -e | grep -E '^MACHINE=|^DISTRO=|^ACCEPT_EULA_stm32mp257-atk='

首次完整编译提示:无共享 sstate 缓存,需要下载约 10GB 源码,编译耗时较长,产物、缓存全部存放在当前 build 目录。


二、OP‑TEE 启动阶段 panic 两大踩坑实录

注意:OP‑TEE 设备树与 Linux 内核设备树是两套完全独立 DTS;使用external‑dt注入 boot 链设备树,修改后必须优先编译 external‑dt

错误一:PMIC stpmic2 探测失败 panic

报错日志:

E/TC:0 0 probe_driver_node:565 Failed to probe stm32_pmic2 on node stpmic2@33: 0xffff0008
E/TC:0 0 print_probe_list:518 |- Driver stm32_pmic2 on node stpmic2@33 failed
E/TC:0 0 Panic at ... core/kernel/dt_driver.c:904 <probe_dt_drivers>

0xffff0008 = TEE_ERROR_ITEM_NOT_FOUND

根因

  1. OP‑TEE 开启CFG_STM32_PWR_IRQ=y,PMIC 驱动需要读取中断属性;
  2. 移植沿用 STM32MP1 旧属性st,wakeup‑pin-number / wakeup‑parent,STM32MP2 不再支持;
  3. EXTI1 line52 的 RIF 权限配置为RIF_NSEC,OP‑TEE 安全域无权访问该中断资源。

修改文件路径: layers/meta‑atk‑mp257/meta‑atk‑mp257‑stm32mp/recipes‑extended/external‑dt/external‑dt/optee/stm32mp257d‑atk‑ddr‑2GB.dts

#include <dt-bindings/clock/stm32mp25-clksrc.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/mfd/st,stpmic2.h>

pmic2: stpmic2@33 {
	compatible = "st,stpmic2";
	reg = <0x33>;
	interrupts-extended = <&exti1 52 IRQ_TYPE_EDGE_FALLING>;
	wakeup-source;
	st,pmic-it-id = <IT_PKEY_FA IT_PKEY_RI>;
	st,notif-it-id = <0 1>;
	status = "okay";
};

RIF 权限修改文件:stm32mp257d‑atk‑ddr‑2GB‑ca35tdcid‑rif.dtsi

RIFPROT(RIF_EXTI1_RESOURCE(52), RIF_UNUSED, RIF_UNLOCK, RIF_SEC, RIF_PRIV, RIF_CID1, RIF_SEM_DIS, RIF_CFEN)

错误二:GPU OPP 初始化 panic(修复 PMIC 之后复现)

报错日志:

E/TC:0 0 clk_stm32_pll3_set_rate:2877 OPP for 800000000 rate not found
E/TC:0 0 set_opp:70 set rate failed
E/TC:0 0 Panic at .../core/drivers/stm32_gpu_opp.c:339 <stm32_gpu_init>

根因:OP‑TEE GPU 驱动初始化读取&rcc {st,clk_opp}st,ck_gpu时钟 OPP 配置;板级 dts 缺失该节点,查找 OPP 失败直接 panic。

dts 修改片段:

 &rcc {
 	st,c1msrd = <2>;
 	st,clk_opp {
 		st,ck_cpu1 {
 			cfg_1 { hz = <1500000000>; st,pll = <&pll1_cfg_1500Mhz>; };
 			cfg_2 { hz = <1200000000>; st,pll = <&pll1_cfg_1200Mhz>; };
 		};
		st,ck_gpu {
			cfg_1 {
				hz = <800000000>;
				st,pll = <&pll3_cfg_800Mhz>;
			};
			cfg_2 {
				hz = <900000000>;
				st,pll = <&pll3_cfg_900Mhz>;
			};
		};
 	};
 };

OP‑TEE 内嵌 DTB 提取验证技巧

不要只看源码 dts,直接从编译输出 bin 镜像提取内嵌 dtb,确认真正编译进固件的设备树。

python3 -c "
import struct
data=open('tee-pager_v2-stm32mp257d-atk-ddr-2GB-optee.bin','rb').read()
i=data.find(b'\xd0\x0d\xfe\xed')
sz=struct.unpack('>I',data[i+4:i+8])[0]
open('/tmp/atk-optee.dtb','wb').write(data[i:i+sz])
"
dtc -I dtb -O dts /tmp/atk-optee.dtb -o /tmp/atk-optee.dts
grep -n -A5 "stpmic2@33" /tmp/atk-optee.dts
grep -n -A10 "st,ck_gpu" /tmp/atk-optee.dts

修改 dts 后快速重编 boot 链

编译顺序硬性约束:external‑dt → optee‑os‑stm32mp → fip‑stm32mp

source layers/openembedded-core/oe-init-build-env build-openstlinuxweston-stm32mp257-atk
bitbake external-dt -c cleansstate
bitbake external-dt
bitbake optee-os-stm32mp
bitbake fip-stm32mp

产物路径:build‑openstlinuxweston‑stm32mp257‑atk/tmp‑glibc/deploy/images/stm32mp257‑atk/fip/,使用 DFU 烧录分区 0x03。


三、整套 OpenSTLinux 转为 Git 快照仓库(atk‑mp257)

重构完成后,将layers整套构建树转为 Git 快照仓库,脱离 repo 工具,实现克隆即编译

仓库克隆后顶层目录固定为atk‑mp257,envsetup 脚本对顶层目录名存在硬依赖,请勿随意改名。

快照仓库目录总览:

atk-mp257/
├─ README.md
├─ meta-atk-mp257/                   # 项目定制层集合
│  ├─ scripts/
│  ├─ meta-atk-mp257-stm32mp/
│  ├─ meta-atk-mp257-stm32mp-addons/
│  └─ meta-atk-mp257-openstlinux/
├─ meta-st/                          # ST官方层,纳入git快照
├─ meta-openembedded/                # meta‑oe / meta‑python
└─ openembedded-core/                # OE‑core,无poky

坑 1:git push 远端目录为空(gitlink 子模块指针)

现象:git push 提交成功,GitHub 上除自己开发的meta‑atk‑mp257之外,meta‑stmeta‑openembeddedopenembedded‑core目录显示灰色无法点开。

根因:repo 检出工程每个子目录内部存在.git符号链接,指向.repo/projects真实仓库。Git 识别嵌套 git 仓库,生成权限位160000gitlink(子模块指针),仓库只保存 commit hash,不会上传实际源码文件。

快照展平操作(适合本项目一次性快照):

cd layers
# 删除所有嵌套的.git符号链接,保留顶层git仓库
find . -mindepth 2 -name .git -type l -delete
# 清除git索引中的gitlink引用
git rm -r --cached meta-openembedded meta-st openembedded-core
# 以普通文件重新跟踪所有代码
git add -A
# 校验:输出0代表无gitlink残留
git ls-files -s | grep 160000 | wc -l
git commit -m "track layer contents as regular files"

代价:快照仓库脱离 repo 上游;后续如需同步 ST 上游版本,需要手动替换对应层目录;如需保留上游更新能力,使用 gitmodules 配置正式子模块方案。

坑 2:顶层 layers 重命名为 atk‑mp257,批量路径替换

仓库希望 clone 后顶层目录为atk‑mp257,仅执行mv layers atk‑mp257会大量路径报错,Yocto 多处硬编码layers/字符串。

需要修改的点位清单

表格

分类文件位置影响
运行编译build 目录bblayers.conftemplateconf.cfg不改直接编译失败
配置模板bblayers.conf.sampleenvsetup --reset 重新生成配置会沿用旧路径
INIT 初始化machine conf 中#@NEEDED_BSPLAYERSmeta‑oe、meta‑python 自动追加路径错误
环境脚本envsetup.sh(atk fork 版本 + meta‑st 原版)source 后无法定位 meta 层根目录

注意:openembedded‑core内部 SDK 相关layers字符串不要修改,属于 SDK 安装之后的内部布局,和源码顶层目录无关。

执行改名与批量替换:

mv layers atk-mp257

# 替换OEROOT变量引用路径
git grep -l '\${OEROOT}/layers/' | xargs sed -i 's|${OEROOT}/layers/|${OEROOT}/atk-mp257/|g'
# 替换NEEDED_BSPLAYERS路径
git grep -l 'NEEDED_BSPLAYERS: layers/' | xargs sed -i 's|NEEDED_BSPLAYERS: layers/|NEEDED_BSPLAYERS: atk-mp257/|g'

# 更新两份envsetup脚本内部META_LAYER_ROOT
sed -i 's|_META_LAYER_ROOT=layers/meta-st|_META_LAYER_ROOT=atk-mp257/meta-st|' atk-mp257/meta-st/scripts/envsetup.sh
sed -i 's|layers/openembedded-core|atk-mp257/openembedded-core|g' atk-mp257/meta-st/scripts/envsetup.sh
sed -i 's|_META_LAYER_ROOT=layers/meta-atk-mp257|_META_LAYER_ROOT=atk-mp257/meta-atk-mp257|' atk-mp257/meta-atk-mp257/scripts/envsetup.sh
sed -i 's|layers/openembedded-core|atk-mp257/openembedded-core|g' atk-mp257/meta-atk-mp257/scripts/envsetup.sh

# build目录不在git仓库,单独替换路径
sed -i 's|${OEROOT}/layers/|${OEROOT}/atk-mp257/|g' \
    build-openstlinuxweston-stm32mp257-atk/conf/bblayers.conf \
    build-openstlinuxweston-stm32mp2/conf/bblayers.conf
sed -i 's|../../layers/|../../atk-mp257/|g' build-*/conf/templateconf.cfg
改名暴露的历史遗留 bug(层重构遗留)

stm32mp2 的bblayers.conf残留无效配置行:

BBLAYERS =+ ".../meta‑atk‑mp257"

重构之后meta‑atk‑mp257只是容器目录,没有 layer.conf,bitbake 解析直接报FileNotFoundError

重要:fork 集合层的BBFILE_COLLECTIONS集合名与原版 meta‑st 重名,两套 BSP 集合不能共用同一个 build 目录。 解决办法:直接删除 stm32mp2 build 的 bblayers.conf 中这一行,恢复 ST 原版纯净构建。

改名后完整验证流程

# 验证atk‑mp257工程
source atk-mp257/meta-atk-mp257/scripts/envsetup.sh build-openstlinuxweston-stm32mp257-atk
bitbake -p
bitbake st-image-weston

# 验证原生stm32mp2编译不受破坏
source atk-mp257/meta-st/scripts/envsetup.sh build-openstlinuxweston-stm32mp2
bitbake -p

atk‑mp257 快照仓库构建命令(README 摘录)

主机环境 Ubuntu20.04/22.04/24.04,禁止 root 用户操作。

# 交互式初始化
source atk-mp257/meta-atk-mp257/scripts/envsetup.sh build-openstlinuxweston-stm32mp257-atk

# 非交互式首次初始化(预接受EULA)
DISTRO=openstlinux-weston \
MACHINE=stm32mp257-atk \
BUILD_DIR=build-openstlinuxweston-stm32mp257-atk \
EULA_stm32mp257atk=1 \
source atk-mp257/meta-atk-mp257/scripts/envsetup.sh --no-ui

# 完整编译镜像
bitbake st-image-weston

# 仅重编译boot链
source atk-mp257/openembedded-core/oe-init-build-env build-openstlinuxweston-stm32mp257-atk
bitbake external-dt -c cleansstate
bitbake external-dt
bitbake optee-os-stm32mp
bitbake fip-stm32mp

编译产物:build‑openstlinuxweston‑stm32mp257‑atk/tmp‑glibc/deploy/images/stm32mp257‑atk/


四、工程踩坑经验总结

  1. meta 集合 fork 重构要点:完整复制 ST 子层,layer.conf 中 BBFILE_COLLECTIONS 集合名称严禁修改,仅改动文件路径;配置独立DL_DIRSSTATE_DIR实现编译环境隔离;重构后顶层meta‑atk‑mp257是容器目录,BSP 实际在子目录,旧配置不要直接引用容器目录。
  2. STM32MP2 OP‑TEE 高频踩坑:STM32MP1 的 PMIC 中断设备树写法不能直接复用至 MP2;RIF 安全权限、GPU OPP 时钟配置极易引发 panic;OP‑TEE DTS 独立于 Linux 内核 DTS;修改 external‑dt 之后编译顺序必须严格遵守:external‑dt → optee‑os‑stm32mp → fip‑stm32mp;可以从 bin 镜像提取 dtb 反编译确认固件内真实设备树。
  3. repo 工程转 Git 快照:repo 检出目录下.git是软链接,直接 git add 会生成 gitlink 子模块指针,远端仓库只有 hash 没有实际源码;快照托管需要清除嵌套.git 符号链接。
  4. Yocto 顶层目录改名不是简单 mvbblayers.confbblayers.conf.sample、machine 的#@NEEDED_BSPLAYERSenvsetup.sh、build 目录templateconf.cfg全部同步替换路径;优先执行bitbake -p解析校验,不需要完整编译即可定位绝大多数路径错误。
  5. 区分改动引入 bug 和历史遗留 bug,本次目录改名暴露了 meta 层重构阶段遗留的无效配置行;排查问题建议对照版本修改时间线定位。
  6. atk‑mp257 快照仓库约束:克隆后顶层目录名必须为atk‑mp257,envsetup 脚本对目录名硬依赖;仓库已经脱离 repo,上游更新需要手动替换层目录;GPU 多媒体 EULA 受限特性需要ACCEPT_EULA_stm32mp257‑atk = "1"

五、相关资源

- 本工程仓库:<https://github.com/2022102437/atk-mp257>

- OpenSTLinux 官方文档:<https://wiki.st.com/stm32mpu>

标签:#STM32MP257 #OpenSTLinux #Yocto #OP‑TEE #external‑dt #meta层重构

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐