1. 공식 소스 확보 및 빌드 환경 구축
STM32MP1 플랫폼에서 U-Boot 을移植하기 위해서는 먼저 스타크레디미컬(STMicroelectronics) 에서 제공하는 공식 소스 코드를 기반으로 작업해야 합니다. 일반적으로 OpenSTLinux 프레임워크 내에서 호스트된 U-Boot 소스를 활용하며, 구체적인 버전은 프로젝트 요구사항에 맞춰 선택합니다.
1.1 소스 추출 및 패치 처리
압축된 U-Boot 아카이브를 배포하여 작업 디렉토리 로 이동한 후, 필요한 수정 사항을 반영하기 위해 패치 파일을 순차적으로 적용하는 과정이 필요합니다. 이는 보드 특유의 하드웨어 제약을 우회하거나 추가 기능을 통합하기 위한 전제 조건입니다.
cd $WORKSPACE/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0/
tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz
# 패치 자동 적용 스크립트
cd u-boot-stm32mp-2020.01/
for p_file in ../\*.patch; do
patch -p1 < "$p_file" || { echo "Error applying $p_file"; exit 1; }
done
위 명령어는 상위 디렉토리에 위치한 모든 패치 파일을 순환하며 `-p1` 옵션을 사용하여 경로를 정리하고 소스에 병합합니다. 수정된 소스는 별도의 백업 폴더로 옮겨 관리하는 것이 좋습니다.
1.2 빌드 스크립트 최적화
수동으로 여러 단계를 실행하는 대신, 빌드 과정을 자동화하는 셸 스크립트를 생성하여 일관성을 유지합니다. 아래 예시는 기존 빌드 절차를 함수화하고 변수를 활용한 개선된 형태입니다.
#!/bin/bash
# build_custom_uboot.sh
UBOOT_ROOT=$(pwd)
ARCH_CONFIG="stm32mp15_atk_trusted_defconfig"
DTB_NAME="stm32mp157d-custom"
JOBS_COUNT=${1:-12}
clean_build() {
echo "[Cleanup] Removing old build artifacts..."
make distclean
}
configure_env() {
echo "[Config] Generating default configuration..."
make "$ARCH_CONFIG"
}
compile_binaries() {
echo "[Build] Compiling U-Boot with target Device Tree..."
make DEVICE_TREE="$DTB_NAME" all -j"$JOBS_COUNT"
}
main() {
cd "$UBOOT_ROOT"
clean_build
configure_env
compile_binaries
if [ $? -eq 0 ]; then
echo "[Success] u-boot.stm32 generated successfully."
cp arch/arm/imx-u-boot.bin ./output/uboot-final.img
else
echo "[Failed] Build process encountered errors."
exit 1
fi
}
main "$@"
2. 커스텀 보드 정의 및 장치트리 설계
기존 평가보드 (EVK) 의 설정을 그대로 사용할 경우, 실제 타겟 보드의 회로 차이 (예: 전원 관리 칩 부재, 메모리 인터페이스 등) 로 인해 부팅이 실패할 수 있습니다. 따라서 보드 별 고유 설정을 갖는 새 파일들을 생성해야 합니다.
2.1 기본 설정 파일 생성
U-Boot 내부의 configs 디렉토리로 이동하여 참조용 파일 복사본을 만듭니다.
cd configs
cp stm32mp15_trusted_defconfig stm32mp15_custom_defconfig
또한 장치트리 소스 (DTS) 는 arch/arm/dts 경로에서 관련 모델을 기반으로 복제합니다.
cd ../arch/arm/dts/
cp stm32mp157d-ed1.dts stm32mp157d-custom.dts
cp stm32mp15xx-edx.dtsi stm32mp157d-custom.dtsi
2.2 전원 공급망 (Regulator) 재정의
공식 EVK 는 STPMIC1A 와 같은 전용 PMIC 칩을 사용하지만, 일부 커스텀 보드는 고정형 레귤레이터를 직접 사용합니다. 이에 따라 DTS 파일 내의 PMIC 노드를 제거하고 고정 전압원을 정의해야 합니다.
stm32mp157d-custom-u-boot.dtsi 파일에서 PMIC 관련 주석을 해지하거나 삭제 작업을 수행하며, 필요한 경우 다음 형태의 고정 레귤레이터 정의를 추가합니다.
/ {
// 기존 PMIC 의존성 제거 및 고정 전압원 추가
vddcore: regulator-vddcore {
compatible = "regulator-fixed";
regulator-name = "vddcore";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
};
...
};
아날로그 컨버터 (ADC/DAC) 나 사용하지 않는 주변 기기 노드 또한 status = "disabled" 로 명시하여 리소스 충돌을 방지해야 합니다.
3. 주변 장치 드라이버 활성화
U-Boot 가 안정적으로 구동되도록 네트워크, USB, 스토리지 인터페이스 등의 설정을 보드 핀아웃에 맞게 조정합니다.
3.1 MMC/SD 인터페이스 구성
TF 카드 슬롯과 내부 eMMC 를 구분하여 설정합니다. 버너폭과 전압 공급 소스를 정확히 매핑해야 정상 인식됩니다.
&sdmmc1 {
/* TF Slot Configuration */
bus-width = <4>;
vmmc-supply = <&v3v3>;
status = "okay";
};
&sdmmc2 {
/* eMMC Internal Storage */
non-removable;
bus-width = <8>;
vmmc-supply = <&v3v3>;
status = "okay";
};
3.2 네트워킹 지원 확장
이더넷 제어기가 활성화되지 않은 경우 네트워크 부팅이나 펌웨어 업데이트가 불가능합니다. ðernet0 노드를 통해 MDIO 주소와 PHY 연결 정보를 명시합니다.
ðernet0 {
status = "okay";
phy-mode = "rgmii-id";
mdio0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "snps,dwmac-mdio";
phy0: ethernet-phy@0 {
reg = <0>;
};
};
};
필요시 PHY 드라이버 소스 (drivers/net/phy/phy.c) 를 커스텀 버전으로 교체하여 호환성을 높일 수 있습니다.
3.3 USB OTG 기능 구현
Type-C 연결을 지원하는 경우 STUSB1600 컨트롤러 설정이 필요합니다. I2C 버스를 통한 초기화 파라미터를 등록하고, USB 역할 전환 (Host/Peripheral) 을 위한 플래그를 설정합니다.
&i2c1 {
stusb1600@28 {
compatible = "st,stusb1600";
reg = <0x28>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpiog>;
status = "okay";
};
};
&usbotg_hs {
usb-role-switch;
phys = <&usbphyc_port1 0>;
dr_mode = "peripheral";
status = "okay";
};
4. 부팅 프로세스 검증 및 테스트
수정한 U-Boot 이미지를 개발기에 프로그래밍하고 다양한 시나리오에서 작동 여부를 확인합니다.
4.1 자체 이미지 재프로그래밍
컴파일된 u-boot.stm32 파일을 Flash 에 다시 기록하여 부트로더 자체가 올바르게 동작하는지 확인합니다. 이는 외부 미디어 없이도 펌웨어 업데이트가 가능한지를 검증합니다.
4.2 eMMC 를 통한 OS 부팅
최종 목표인 리눅스 커널을 eMMC 저장공간에 로드하여 실행시키는 방식입니다. U-Boot 명령어로 파티션으로부터 이미지와 장치트리를 RAM 으로 전송한 후 부팅합니다.
# 환경 변수 설정 예시
setenv bootcmd 'ext4load mmc 1:2 0xc2000000 zImage; ext4load mmc 1:2 0xc4000000 dtb_file.dtb; bootz 0xc2000000 - 0xc4000000'
saveenv
boot
여기서 ext4load 명령은 특정 파티션의 파일 시스템을 읽어들이며, bootz 또는 bootm 는 해당 메모리 주소의 커널을 실행시킵니다.
4.3 네트워크 부팅 (TFTP/NFS)
개발 과정에서 eMMC 재기록 없이 빠르게 테스트하기 위해 네트워크를 경유하여 이미지를 다운로드하는 환경을 구성합니다. 호스트 서버 (Ubuntu 등) 에 TFTP 서비스를 실행하고 U-Boot 에서 원격 인출을 지시합니다.
setenv bootcmd 'tftpboot 0xc2000000 uImage; tftpboot 0xc4000000 dtb_file.dtb; bootz 0xc2000000 - 0xc4000000'
5. 핵심 환경 변수 이해
U-Boot 의 동작을 제어하는 주요 두 가지 환경 변수인 bootcmd 과 bootargs 의 역할은 다음과 같습니다.
5.1 부팅 명령열 (bootcmd)
시스템 시작 시 카운트다운 종료 후 자동으로 실행되는 명령어 조합입니다. 기본적으로 저장장치에서 커널을 로드하는 일련의 스크립트가 포함됩니다. 컴파일 단계에서 CONFIG_BOOTCOMMAND 매크로를 통해 초기값을 할당할 수 있습니다.
5.2 커널 인자 (bootargs)
리눅스 커널에게 전달될 설정 파라미터입니다. 콘솔 포트 지정, 루트 파일 시스템 위치, 파일 시스템 타입 등을 정의합니다.
console=ttySTM0,115200 root=/dev/mmcblk2p3 rw rootwait
- console: 커널 출력 로그가 가는 터미널 경로 및 바이트 전송 속도를 설정합니다.
- root: 커널이 마운트할 루트 파일 시스템의 블록 장치 위치를 지시합니다.
- rw: 파일 시스템을 읽기/쓰기 모드로 마운트하도록 허용합니다.
- rootwait: 저장 장치 드라이버 초기화가 완료될 때까지 마운트 과정을 지연시킵니다.