【米尔STM32MP135】TF-A编译与设备启动
[复制链接]
STM32MP135这款MPU的性能非常的好,很适合工业使用,而且ST公司比较大方,除了数据手册以外寄存器定义和编程手册都对普通用户开放,不像国产的某*志之类的厂家有用的资料对普通用户捂得严严实实的,甚至威胁谁要是公开其资料就会被起诉,这点我是十分的不理解,所以国内的ARM MPU芯片一直没有兴趣。这次测评米尔STM32MP135的芯片就有计划做些移植实验。本次的测试就是STM32MP135的移植实验。
STM32MP135的启动流程大致分三个阶段。大致为:
1、内置ROM启动,这个过程是使用MPU的内存工作的,就和单片机差不多,所以除了脚本的设置功能没有更高级的了,设置DDR初始化都没有,只是负责把FSBL代码读到CPU内部RAM中,这部分过程差不多MPU都是相似的。就是高级的手机的CPU也一样。这段ROM code为厂家内置,不可更改。
2、FSBL启动,这个是移植工程师需要编写的,这段代码也分两部分,First Stage为在内部RAM中执行的程序和后续的加载程序SSBL,第一阶段程序需要根据具体的硬件配置初始化,例如:串口、MMC内存、SD卡、等,最重要的DDR内存。本次实验就是测试的这段代码。最要的外设和DDR初始化以后,就是将Uboot等程序加载到内存,进行第三阶段启动。
3、SSBL阶段就是工作的程序了,通常这一阶段工作在DDR内存当中,例如:我们熟知的UBOOT程序,这其实整个系统就算进入到工作状态了,你其实都可以将UBOOT改成类似单片机的方式,或者写个什么简单的操作系统之类的。
4、uboot启动后通常都会加载linux内核,linux内核完全的推翻了UBOOT的内存布局和外设初始化,linux完全的接管整个系统。
从上述描述当中可以知道,不同阶段都外设有着不同的要求,每个阶段都有自己独立的系统要求,也就是互相没有什么关联,自己干自己的事,这就涉及到不同的阶段设备树也是不一样的,彼此可以独立。
我的测试主要参考了:Trusted Firmware-A (BL2)的内容,ST公司服务真是太赞了。
先去STMicroelectronics github上下载TF-A的代码,这里注意不要使用SDK包里的代码太旧,轻易出问题。理论上也可以去trustedfirmware官网上也是可以地,但是象我这样的水平就免了。
进入arm-trusted-firmware目录,查看一下fdts下的dts文件,找到stm32mp135f-dk.dts文件,复制一份。编辑文件
- // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
- /*
- * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
- */
-
- /dts-v1/;
-
-
-
-
-
-
-
- / {
- model = "STMicroelectronics STM32MP135F-DK Discovery Board";
- compatible = "st,stm32mp135f-dk", "st,stm32mp135";
-
- aliases {
- serial0 = &uart4;
- serial1 = &usart1;
- serial2 = &uart8;
- serial3 = &usart2;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
- memory@c0000000 {
- device_type = "memory";
- reg = <0xc0000000 0x20000000>;
- };
-
- vin: vin {
- compatible = "regulator-fixed";
- regulator-name = "vin";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-always-on;
- };
-
- v3v3_ao: v3v3_ao {
- compatible = "regulator-fixed";
- regulator-name = "v3v3_ao";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- };
- };
-
- &bsec {
- board_id: board_id@f0 {
- reg = <0xf0 0x4>;
- st,non-secure-otp;
- };
- };
-
- &cpu0 {
- cpu-supply = <&vddcpu>;
- };
-
- &hash {
- status = "okay";
- };
-
- &i2c4 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c4_pins_a>;
- i2c-scl-rising-time-ns = <185>;
- i2c-scl-falling-time-ns = <20>;
- clock-frequency = <400000>;
- status = "okay";
-
- pmic: stpmic@33 {
- compatible = "st,stpmic1";
- reg = <0x33>;
-
- status = "okay";
-
- regulators {
- compatible = "st,stpmic1-regulators";
- buck1-supply = <&vin>;
- buck2-supply = <&vin>;
- buck3-supply = <&vin>;
- buck4-supply = <&vin>;
- ldo1-supply = <&vin>;
- ldo4-supply = <&vin>;
- ldo5-supply = <&vin>;
- ldo6-supply = <&vin>;
- vref_ddr-supply = <&vin>;
- pwr_sw1-supply = <&bst_out>;
- pwr_sw2-supply = <&v3v3_ao>;
-
- vddcpu: buck1 {
- regulator-name = "vddcpu";
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <1250000>;
- regulator-always-on;
- regulator-over-current-protection;
- };
-
- vdd_ddr: buck2 {
- regulator-name = "vdd_ddr";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-over-current-protection;
- };
-
- vdd: buck3 {
- regulator-name = "vdd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- st,mask-reset;
- regulator-over-current-protection;
- };
-
- vddcore: buck4 {
- regulator-name = "vddcore";
- regulator-min-microvolt = <1250000>;
- regulator-max-microvolt = <1250000>;
- regulator-always-on;
- regulator-over-current-protection;
- };
-
- vdd_adc: ldo1 {
- regulator-name = "vdd_adc";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- vdd_usb: ldo4 {
- regulator-name = "vdd_usb";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- vdd_sd: ldo5 {
- regulator-name = "vdd_sd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- v1v8_periph: ldo6 {
- regulator-name = "v1v8_periph";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vref_ddr: vref_ddr {
- regulator-name = "vref_ddr";
- regulator-always-on;
- };
-
- bst_out: boost {
- regulator-name = "bst_out";
- };
-
- v3v3_sw: pwr_sw2 {
- regulator-name = "v3v3_sw";
- regulator-active-discharge = <1>;
- regulator-always-on;
- };
- };
- };
- };
-
- &iwdg1 {
- timeout-sec = <32>;
- status = "okay";
- };
-
- &pka {
- status = "okay";
- };
-
- &pwr_regulators {
- vdd-supply = <&vdd>;
- vdd_3v3_usbfs-supply = <&vdd_usb>;
- };
-
- &rcc {
- st,clksrc = <
- CLK_MPU_PLL1P
- CLK_AXI_PLL2P
- CLK_MLAHBS_PLL3
- CLK_CKPER_HSE
- CLK_RTC_LSE
- CLK_SDMMC1_PLL4P
- CLK_SDMMC2_PLL4P
- CLK_STGEN_HSE
- CLK_USBPHY_HSE
- CLK_I2C4_HSI
- CLK_USBO_USBPHY
- CLK_I2C12_HSI
- CLK_UART2_HSI
- CLK_UART4_HSI
- CLK_SAES_AXI
- >;
-
- st,clkdiv = <
- DIV(DIV_AXI, 0)
- DIV(DIV_MLAHB, 0)
- DIV(DIV_APB1, 1)
- DIV(DIV_APB2, 1)
- DIV(DIV_APB3, 1)
- DIV(DIV_APB4, 1)
- DIV(DIV_APB5, 2)
- DIV(DIV_APB6, 1)
- DIV(DIV_RTC, 0)
- >;
-
- st,pll_vco {
- pll2_vco_1066Mhz: pll2-vco-1066Mhz {
- src = <CLK_PLL12_HSE>;
- divmn = <2 65>;
- frac = <0x1400>;
- };
-
- pll3_vco_417Mhz: pll3-vco-417Mhz {
- src = <CLK_PLL3_HSE>;
- divmn = <1 33>;
- frac = <0x1a04>;
- };
-
- pll4_vco_600Mhz: pll4-vco-600Mhz {
- src = <CLK_PLL4_HSE>;
- divmn = <1 49>;
- };
- };
-
- /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 266, R = 533 (DDR) */
- pll2:st,pll[url=home.php?mod=space&uid=490]@1[/url] {
- compatible = "st,stm32mp1-pll";
- reg = <1>;
-
- st,pll = <&pll2_cfg1>;
-
- pll2_cfg1: pll2_cfg1 {
- st,pll_vco = <&pll2_vco_1066Mhz>;
- st,pll_div_pqr = <1 1 0>;
- };
- };
-
- /* VCO = 417.8 MHz => P = 209, Q = 24, R = 209 */
- pll3:st,pll@2 {
- compatible = "st,stm32mp1-pll";
- reg = <2>;
-
- st,pll = <&pll3_cfg1>;
-
- pll3_cfg1: pll3_cfg1 {
- st,pll_vco = <&pll3_vco_417Mhz>;
- st,pll_div_pqr = <1 16 1>;
- };
- };
-
- /* VCO = 600.0 MHz => P = 50, Q = 10, R = 100 */
- pll4:st,pll@3 {
- compatible = "st,stm32mp1-pll";
- reg = <3>;
-
- st,pll = <&pll4_cfg1>;
-
- pll4_cfg1: pll4_cfg1 {
- st,pll_vco = <&pll4_vco_600Mhz>;
- st,pll_div_pqr = <11 59 5>;
- };
- };
- };
-
- &rng {
- status = "okay";
- };
-
- &saes {
- status = "okay";
- };
-
- &sdmmc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_clk_pins_a>;
- disable-wp;
- st,neg-edge;
- bus-width = <4>;
- vmmc-supply = <&vdd_sd>;
- status = "okay";
- };
-
- &uart4 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_a>;
- status = "okay";
- };
-
- &uart8 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart8_pins_a>;
- status = "disabled";
- };
-
- &usart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&usart1_pins_a>;
- uart-has-rtscts;
- status = "disabled";
- };
-
这其中对于米尔的板子有个坑,就是i2c4设置,这个设置的引脚和板子的定义有冲突,如果直接使用,就会是这样地
所以必须修改自己的设备树文件,
这里我使用了STM32CubMX工具生成设备树,
主要是系统时钟,和DDR3设置
DDR3的设置
生成代码,好像很轻松是吧,但是别高兴的太早,这个工具生成的代码是编译不过去地,编译不过去地!
那有什么用呢?用处就是可以给你参考地。
其实主要是引脚设置,
- /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
- /*
- * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
- * Author: STM32CubeMX code generation for STMicroelectronics.
- */
-
- /* For more information on Device Tree configuration, please refer to
- * https://wiki.st.com/stm32mpu/wiki/Category:Device_tree_configuration
- */
-
- /dts-v1/;
-
-
-
-
-
-
-
-
-
- /* USER CODE BEGIN includes */
- /* USER CODE END includes */
-
- / {
- model = "STMicroelectronics custom STM32CubeMX board - openstlinux-5.15-yocto-kirkstone-mp1-v22.11.23";
- compatible = "st,stm32mp135d-mydts-mx", "st,stm32mp135";
-
- memory@c0000000 {
- device_type = "memory";
- reg = <0xc0000000 0x10000000>;
-
- /* USER CODE BEGIN memory */
- /* USER CODE END memory */
- };
-
- /* USER CODE BEGIN root */
- /* USER CODE END root */
-
- clocks {
- /* USER CODE BEGIN clocks */
- /* USER CODE END clocks */
-
- clk_hsi: clk-hsi {
- clock-frequency = <64000000>;
-
- /* USER CODE BEGIN clk_hsi */
- /* USER CODE END clk_hsi */
- };
- clk_lse: clk-lse {
- status = "disabled";
-
- /* USER CODE BEGIN clk_lse */
- /* USER CODE END clk_lse */
- };
- clk_hse: clk-hse {
- clock-frequency = <24000000>;
-
- /* USER CODE BEGIN clk_hse */
- /* USER CODE END clk_hse */
- };
- clk_i2sin: clk-i2sin {
- status = "disabled";
-
- /* USER CODE BEGIN clk_i2sin */
- /* USER CODE END clk_i2sin */
- };
- };
-
- }; /*root*/
-
- &pinctrl {
- uart4_pins_mx: uart4_mx-0 {
- pins1 {
- pinmux = <STM32_PINMUX('A', 15, AF8)>; /* UART4_RX */
- bias-disable;
- };
- pins2 {
- pinmux = <STM32_PINMUX('A', 9, AF8)>; /* UART4_TX */
- bias-disable;
- drive-push-pull;
- slew-rate = <2>;
- };
- };
-
- /* USER CODE BEGIN pinctrl */
- /* USER CODE END pinctrl */
- };
-
- &bsec{
- status = "okay";
-
- /* USER CODE BEGIN bsec */
- /* USER CODE END bsec */
- };
-
- &rcc{
- status = "okay";
-
- /* USER CODE BEGIN rcc */
- /* USER CODE END rcc */
-
- st,clksrc = <
- CLK_MPU_HSI
- CLK_AXI_HSI
- CLK_MLAHBS_HSI
- CLK_CKPER_DISABLED
- CLK_STGEN_HSI
- CLK_UART4_PCLK1
- >;
- st,clkdiv = <
- DIV(DIV_MPU, 1)
- DIV(DIV_AXI, 0)
- DIV(DIV_MLAHB, 0)
- DIV(DIV_APB1, 0)
- DIV(DIV_APB2, 0)
- DIV(DIV_APB3, 0)
- DIV(DIV_APB4, 0)
- DIV(DIV_APB5, 0)
- DIV(DIV_APB6, 0)
- >;
- st,pll_vco {
-
- /* USER CODE BEGIN rcc_st-pll_vco */
- /* USER CODE END rcc_st-pll_vco */
- };
-
- };
-
- &uart4{
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_mx>;
- status = "okay";
-
- /* USER CODE BEGIN uart4 */
- /* USER CODE END uart4 */
- };
-
- /* USER CODE BEGIN addons */
- /* USER CODE END addons */
-
-
主要是#include "stm32mp13-mydts-pinctrl.dtsi"这个文件,这个文件的内容是根据板子的硬件设置地。这个文件我参考的是stm32mp13-pinctrl.dtsi文件
将里面的内容根据板子的情况修改地。就是冲突的引脚都去除了。这个文件我感觉很是不严谨。最后编译代码。
- make ARM_ARCH_MAJOR=7 ARCH=aarch32 PLAT=stm32mp1 STM32MP_SDMMC=1 STM32MP13=1 DTB_FILE_NAME=stm32mp135d-mydts-mx.dtb
这里也有个坑:如果你使用的是ST的编译SDK toolkit,使用unset LDFLAGS 关掉编译设置。就可以编译通过了,
编译完成,build/stm32mp1/release目录下生成文件:tf-a-stm32mp135d-dk.stm32
使用scp tf-a-stm32mp135d-dk.stm32 root@192.168.1.105:~ 拷贝到开发板当中,
- dd if=<tf-a file>.stm32 of=/dev/<device partition> bs=1M conv=fdatasync
用DD命令工具,烧写到TF卡。
重启开发板
系统顺利进入到linux状态。
后记:这个测试我搞了好久,主要是设备树的设置,不断地出错。祝各位顺利。
|