• 正点原子嵌入式linux驱动开发——U-boot移植


    uboot的移植并不是说从零开始将uboot移植到所使用的开发板或者开发平台上。这个对于我们开发者来说基本是不可能的,这个工作一般是半导体厂商做的,半导体厂商负责将uboot移植到他们的芯片上,因此半导体厂商都会自己做一个开发板,这个开发板就叫做原厂开发板,比如我们现在学习STM32的时候听说过的discover开发板就是ST自己做的。半导体厂商将uboot移植到自己的原厂开 发板上,测试好以后就会将这个uboot发布出去,这就是大家常说的原厂BSP包。一般做产品的时候就会参考原厂的开发板做硬件,然后在原
    厂提供的BSP包上做修改,将uboot或者linux kernel移植到硬件上。这就是uboot移植的一般流程:

    1. 在uboot中找到参考的开发平台,一般是原厂的开发板。
    2. 参考原厂开发板移植uboot到所使用的开发板。

    正点原子STM32MP157开发板参考的是ST官方的 STM32MP157 EVK开发板做的硬件,因此在移植uboot的时候就可以以ST官方的STM32MP157 EVK开发板为蓝本

    ST官方U-boot编译测试

    ST官方uboot源码打补丁

    获取ST官方uboot源码

    首先肯定要获取到ST官方的 uboot源码,这在之前最开始的uboot学习笔记,也就是uboot使用中已经获取过了,进入到对应的uboot源码目录,命令如下:

    cd /home/zuozhongkai/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0 //进入ST官方uboot源码

    ST官方uboot源码如下图所示:
    ST官方uboot源码
    从上图可以看出, ST官方的uboot源码跟TF-A的源码包文件夹内容格式基本一样,包括了补丁文件.patch、Makefile.sdk和uboot源码压缩包,只是uboot有多个.patch补丁文件,打补丁的时候这些.patch都要用到。

    之后解压上图中u-boot-stm32mp-2020.01-r0.tar.gz这个真正的源码包压缩包,解压命令如下:

    tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz

    解压完成以后就会得到一个名为“u-boot-stm32mp-2020.01”的uboot源码文件夹。

    打补丁

    解压得到uboot的源码文件后,就要对其进行打补丁,进入到上面解压出来的u-boot-stmmp-2020.01目录,然后执行对应的打补丁命令:

    cd u-boot-stm32mp-2020.01/ //进入 uboot源码目录
    for p in `ls -1 ../*.patch`;do patch -p1 < $p;done //打补丁

    打补丁结果如下图所示:
    打补丁结果
    打完补丁以后的u-boot-stm32mp-2020.01目录就是要移植uboot源码,但是上图中的u-boot-stm32mp-2020.01目录路径有点长,不适合阅读和编译。所以可以新建一个名为“my_uboot”的目录来保存要移植的uboot源码,然后将ST官方的 uboot源码拷贝到“my_uboot”目录下,命令如下:

    cd /home/zuozhongkai/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0/u-boot-stm32mp-2020.01
    cp * /home/zuozhongkai/linux/atk-mp1/uboot/my_uboot/ -rf //拷贝到my_uboot目录下

    拷贝完成后的my_uboot目录如下图所示:
    拷贝完成的uboot源码
    最后可以创建一个VSCode工程,方便阅读和移植。

    编译ST官方uboot源码

    修改Makefile

    首先修改一下uboot源码的Makefile文件,也可以不修改,但是在编译的时候需要多输入一些参数,为了偷懒,还是修改一下。修改方法已经在 之前的uboot使用笔记中有过讲解,就是在Makefile文件里面添加ARCH和CROSS_COMPILE这两个变量的值,如下图所示:
    设置ARCH和CROSS_COMPILE变量值
    ST官方uboot肯定适配了官方的STM32MP1 EVK开发板,现在就编译EVK开发板对应的uboot,编译完成以后将得到的uboot可执行文件烧写到正点原子的STM32MP1开发板中,看看能不能运行,不能的话就要修改uboot相应的文件,这就是uboot的移植。编译命令如下:

    make stm32mp15_trusted_defconfig
    make DEVICE_TREE=stm32mp157d-ev1 all -j8

    编译完成后如下图所示:
    uboot编译成功
    编译完成后就会得到uboot可执行文件,如下图所示:
    uboot可执行文件
    从上图可以看出,uboot编译成功,生成了u-boot.bin和u-boot.stm32;u-boot.bin包含了设备树(dtb),也就是将uboot镜像和设备树打包在了一起。 其中u-boot.stm32是在u-boot.bin前面添加了256字节头部信息的可执行文件,是要烧写到开发板里面的

    烧写测试

    上一小节编译出了ST官方EVK开发板对应的u-boot.stm32,本节将其烧写到正点原子的开发板中,看看能不能启动。这里烧写需要注意一下,不能直接用上面编译成功图中的u-boot.stm32文件替换以前images目录下的u-boot.stm32。前面说了STM23CubeProgrammer烧写原理就是先向开发板的DDR里面下载一个完整的uboot进去,然后用这个uboot来烧写系统。所以必须保证这个下载到DDR里面的uboot是工作正常的,但是我们刚刚编译出来的uboot可执行文件肯定是有问题的,所以下载到DDR中的uboot必须用正点原子提供的,烧写到EMMC里面的是我们刚刚编译的,这两个 uboot要区分开

    将上图中的u-boot.stm32重命名为my-u-boot.stm32,一定要重命名!然后将重命名以后的my-u-boot.stm32放到images目录下。还需要修改一下Flashlayouts文件,修改一下烧写到 EMMC里面的uboot名字,如下图所示:
    修改后的FlashLayouts文件
    完成后就可以烧写了,烧写完成后从EMMC启动,此时会发现开发板一直在重启,其中uboot启动过程如下图所示:
    uboot启动过程
    从上图可以看出以下几个重要的信息:

    1. uboot能运行,也就是说ST官方EVK开发板的uboot可以直接在正点原子的开发板
      上运行,但是运行会出错!
    2. uboot版本为2020.01,编译日期为2020年12月1日,10:33:15,说明就是刚刚自行编译的uboot。
    3. 出现了“stpmic1_read: failed to read register”错误,前面讲解TF-A的时候已经说了,ST官方EVK开发板使用了电源管理芯片STPMIC1A,所以uboot运行的时候会初始化这个PMIC芯片,但是正点原子开发板并没有使用这个PMIC芯片,所以就会报STPMIC错误

    接下来就是一步步修改uboot,直至其可以正常工作,也就是所谓的uboot移植。

    在U-boot中添加自己的开发板

    创建默认配置文件

    首先创建自己所使用开发板对应的默认配置文件,在第一次编译uboot的时候先执行:

    make stm32mp15_trusted_defconfig

    上面命令的意思就是先使用默认配置文件配置一下uboot stm32mp15_trusted_defconfig这个文件保存了默认配置选项。默认配置文件创建方法很简单,既然正点原子开发板参考了ST官方的EVK开发板,那么默认配置文件也可以直接参考官方的EVK开发板。在uboot的源码目录下,运行以下命令:

    cd configs //进入uboot的configs目录
    cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig //拷贝

    此时在uboot的configs目录下就存在一个名为“stm32mp15_atk_trusted_defconfig”的默认配置文件,这个默认配置文件就是给我们开发板使用的。

    创建默认配置设备树

    另外还要创建自己所使用开发板对应的设备树,方法也很简单,直接复制ST官方EVK开发板对应的设备树,在uboot的源码目录下,运行以下命令:

    cd arch/arm/dts/ //进入uboot设备树目录
    cp stm32mp157d-ed1.dts stm32mp157d-atk.dts //复制.dts
    cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi //复制.dtsi
    cp stm32mp157a-ed1-u-boot.dtsi stm32mp157d-atk-u-boot.dtsi //复制.dtsi

    打开stm32mp157d-atk.dts文件,要修改一下其中的一个头文件引用,stm32mp157d-atk.dts默认头文件引用如下:
    示例代码13.2.2.1 stm32mp157d-atk.dts文件截图
    注意,第14行引用的是stm32mp15xx-edx.dtsi这个设备树头文件,要将其改为上面创建的stm32mp15d-atk.dtsi,修改以后如下图所示:
    修改后的stm32mp157d-atk.dts

    修改电源管理设置

    打开之前创建的stm32mp157d-atk-u-boot.dtsi文件,前53行内容如下:

    示例代码13.2.3.1 stm32mp157d-atk-u-boot.dtsi文件 
    1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 
    2 /* 
    3  * Copyright : STMicroelectronics 2018 
    4  */ 
    5 
    6 #include <dt-bindings/clock/stm32mp1-clksrc.h> 
    7 #include "stm32mp15-u-boot.dtsi" 
    8 #include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" 
    9 
    10 / { 
    11 aliases { 
    12     i2c3 = &i2c4; 
    13     mmc0 = &sdmmc1; 
    14     mmc1 = &sdmmc2; 
    15 }; 
    16 
    17 config { 
    18     u-boot,boot-led = "heartbeat"; 
    19     u-boot,error-led = "error"; 
    20     u-boot,mmc-env-partition = "ssbl"; 
    21     st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; 
    22     st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>; 
    23 }; 
    24 
    25 led { 
    26     red { 
    27         label = "error"; 
    28         gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; 
    29         default-state = "off"; 
    30         status = "okay"; 
    31         }; 
    32     }; 
    33 };
    34 
    35 #ifndef CONFIG_STM32MP1_TRUSTED 
    36 &clk_hse { 
    37     st,digbypass; 
    38 }; 
    39
    40 &i2c4 { 
    41     u-boot,dm-pre-reloc; 
    42 }; 
    43 
    44 &i2c4_pins_a { 
    45     u-boot,dm-pre-reloc; 
    46     pins { 
    47         u-boot,dm-pre-reloc; 
    48     }; 
    49 }; 
    50 
    51 &pmic { 
    52     u-boot,dm-pre-reloc; 
    53 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    把示例代码13.2.3.1中的的21-22行、26-31行和51~53行都删除,删除以后如下图所示:
    修改后的stm32mp157d-atk-u-boot.dtisi文件
    接着修改stm32mp157d-atk.dtsi文件,找到如下所示代码:

    90 &adc { 
    91 /* ANA0, ANA1 are dedicated pins and don't need pinctrl: only in6. */ 
    92     pinctrl-0 = <&adc1_in6_pins_a>; 
    93     pinctrl-names = "default"; 
    94     vdd-supply = <&vdd>; 
    95     vdda-supply = <&vdda>; 
    96     vref-supply = <&vdda>; 
    97     status = "disabled"; 
    98     adc1: adc@0 { 
    99         st,adc-channels = <0 1 6>; 
    100         /* 16.5 ck_cycles sampling time */ 
    101         st,min-sample-time-nsecs = <400>; 
    102         status = "okay"; 
    103     }; 
    104 }; 
    105 
    106 &cpu0{ 
    107     cpu-supply = <&vddcore>; 
    108 }; 
    109 
    110 &crc1 { 
    111     status = "okay"; 
    112 }; 
    113 
    114 &dac { 
    115     pinctrl-names = "default"; 
    116     pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; 
    117     vref-supply = <&vdda>; 
    118     status = "disabled"; 
    119     dac1: dac@1 { 
    120         status = "okay"; 
    121     }; 
    122     dac2: dac@2 { 
    123         status = "okay"; 
    124     }; 
    125 }; 
    126 
    127 &dma1 { 
    128     sram = <&dma_pool>; 
    129 };
    ...... 
    142 
    143 &i2c4 { 
    144     pinctrl-names = "default", "sleep"; 
    145     pinctrl-0 = <&i2c4_pins_a>; 
    146     pinctrl-1 = <&i2c4_pins_sleep_a>; 
    147     i2c-scl-rising-time-ns = <185>; 
    148     i2c-scl-falling-time-ns = <20>; 
    149     clock-frequency = <400000>; 
    150     status = "okay"; 
    151     /* spare dmas for other usage */ 
    152     /delete-property/dmas; 
    153     /delete-property/dma-names; 
    154 
    155     pmic: stpmic@33 { 
    156         compatible = "st,stpmic1"; 
    157         reg = <0x33>; 
    158         interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; 
    159         interrupt-controller; 
    160         #interrupt-cells = <2>; 
    161         status = "okay"; 
    162 
    163         regulators { 
    164             compatible = "st,stpmic1-regulators"; 
    165             buck1-supply = <&vin>; 
    166             buck2-supply = <&vin>; 
    167             buck3-supply = <&vin>; 
    168             buck4-supply = <&vin>; 
    169             ldo1-supply = <&v3v3>; 
    170             ldo2-supply = <&v3v3>; 
    171             ldo3-supply = <&vdd_ddr>; 
    172             ldo4-supply = <&vin>; 
    173             ldo5-supply = <&v3v3>; 
    174             ldo6-supply = <&v3v3>; 
    175             vref_ddr-supply = <&vin>; 
    176             boost-supply = <&vin>; 
    177             pwr_sw1-supply = <&bst_out>; 
    178             pwr_sw2-supply = <&bst_out>; 
    179 
    180             vddcore: buck1 { 
    181                 regulator-name = "vddcore"; 
    182                 regulator-min-microvolt = <1200000>; 
    183                 regulator-max-microvolt = <1350000>;
    184                 regulator-always-on; 
    185                 regulator-initial-mode = <0>; 
    186                 regulator-over-current-protection; 
    187             }; 
    ...... 
    278             vbus_sw: pwr_sw2 { 
    279                 regulator-name = "vbus_sw"; 
    280                 interrupts = <IT_OCP_SWOUT 0>; 
    281                 regulator-active-discharge = <1>; 
    282             }; 
    283         }; 
    284 
    285         onkey { 
    286             compatible = "st,stpmic1-onkey"; 
    287             interrupts = <IT_PONKEY_F 0>, <IT_PONKEY_R 0>; 
    288             interrupt-names = "onkey-falling", "onkey-rising"; 
    289             power-off-time-sec = <10>; 
    290             status = "okay"; 
    291         }; 
    292 
    293         watchdog { 
    294             compatible = "st,stpmic1-wdt"; 295             status = "disabled"; 
    296         }; 
    297     }; 
    298 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    将示例代码13.2.3.2中90-104行的adc节点、114-125行的dac节点以及143-298行的i2c4节点全部删除掉,删除以后如下图所示:
    修改后的stm32mp157d-atk.dtsi文件
    继续修改stm32mp157d-atk.dtsi文件,找到如下所示代码:

    示例代码13.2.3.3 stm32mp157d-atk.dtsi代码段 
    58 led { 
    59     compatible = "gpio-leds"; 
    60     blue { 
    61         label = "heartbeat"; 
    62         gpios = <&gpiod 9 GPIO_ACTIVE_HIGH>; 
    63         linux,default-trigger = "heartbeat"; 
    64         default-state = "off"; 
    65     }; 
    66 }; 
    67 
    68 sd_switch: regulator-sd_switch { 
    69     compatible = "regulator-gpio"; 
    70     regulator-name = "sd_switch"; 
    71     regulator-min-microvolt = <1800000>; 
    72     regulator-max-microvolt = <2900000>; 
    73     regulator-type = "voltage"; 
    74     regulator-always-on; 
    75 
    76     gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; 
    77     gpios-states = <0>;
    78     states = <1800000 0x1 2900000 0x0>; 
    79 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    上述代码是led和sd_switch节点信息,将这两个节点都删除掉,这两个节点删除以后如下图所示:
    删除后的stm32mp157d-atk.dtsi代码段
    最后需要向stm32mp157d-atk.dtsi文件的根节点‘/’下添加自己的电源管理配置,将下面的代码添加到上图中的58行处:

    示例代码13.2.3.4 要添加的电源管理配置节点 
    1 vddcore: regulator-vddcore { 
    2     compatible = "regulator-fixed"; 
    3     regulator-name = "vddcore"; 
    4     regulator-min-microvolt = <1200000>; 
    5     regulator-max-microvolt = <1350000>; 
    6     regulator-always-on; 
    7     regulator-boot-on; 
    8 }; 
    9 
    10 v3v3: regulator-3p3v { 
    11     compatible = "regulator-fixed"; 
    12     regulator-name = "v3v3"; 
    13     regulator-min-microvolt = <3300000>; 
    14     regulator-max-microvolt = <3300000>; 
    15     regulator-always-on; 
    16     regulator-boot-on; 
    17 }; 
    18 
    19 v1v8_audio: regulator-v1v8-audio { 
    20     compatible = "regulator-fixed"; 
    21     regulator-name = "v1v8_audio"; 
    22     regulator-min-microvolt = <1800000>;
    23     regulator-max-microvolt = <1800000>; 
    24     regulator-always-on; 
    25     regulator-boot-on; 
    26 }; 
    27 
    28 vdd: regulator-vdd { 
    29     compatible = "regulator-fixed"; 
    30     regulator-name = "vdd"; 
    31     regulator-min-microvolt = <3300000>; 
    32     regulator-max-microvolt = <3300000>; 
    33     regulator-always-on; 
    34     regulator-boot-on; 
    35 }; 
    36 
    37 vdd_usb: regulator-vdd-usb { 
    38     compatible = "regulator-fixed"; 
    39     regulator-name = "vdd_usb"; 
    40     regulator-min-microvolt = <3300000>; 
    41     regulator-max-microvolt = <3300000>; 
    42     regulator-always-on; 
    43     regulator-boot-on; 
    44 }; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    上述代码定义了5个电源节点,分别为:vddcore、v3v3、v1v8_audio、vdd和vdd_usb,至此,电源管理相关配置已经设置好了。

    修改TF卡和EMMC配置

    继续修改stm32mp157d-atk.dtsi文件,找到sdmmc1和sdmmc2这两个节点,将这两个节点改为如下所示内容:

    示例代码13.2.4.1 修改后的sdmmc1和sdmmc2节点 
    1 &sdmmc1 { 
    2     pinctrl-names = "default", "opendrain", "sleep"; 
    3     pinctrl-0 = <&sdmmc1_b4_pins_a>; 
    4     pinctrl-1 = <&sdmmc1_b4_od_pins_a>; 
    5     pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; 
    6     st,neg-edge; 
    7     broken-cd; 
    8     bus-width = <4>; 
    9     vmmc-supply = <&v3v3>; 
    10     status = "okay"; 
    11 };
    12 
    13 &sdmmc2 { 
    14     pinctrl-names = "default", "opendrain", "sleep";
    15     pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; 
    16     pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>; 
    17     pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>; 
    18     non-removable; 
    19     st,neg-edge; 
    20     bus-width = <8>; 
    21     vmmc-supply = <&v3v3>; 
    22     keep-power-in-suspend; 
    23     status = "okay"; 
    24 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    编译uboot

    接下来可以先编译一下uboot,在编译之前现在stm32mp157d-atk.dtsi文件中找到usbotg_hs节点,此节点默认内容如下:
    示例代码13.2.5.1 usbotg_hs节点
    此节点定义了USB_OTG的电源配置,ST官方开发板的USB_OTG电源也是通过PMIC配置的,所以USB_OTG电源配置也要修改,但是这里要先测试一下当前修改后的uboot能不能运行,因此先不改USB_OTG电源,所以先将示例代码13.2.5.1中的 usbotg_hs节点屏蔽掉,防止编译报错。

    在编译uboot之前要先让编译器知道我们要编译哪个设备树文件,打开arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_STM32MP15x)”配置项,然后在此配置项中加入“stm32mp157d-atk.dtb”,添加完以后如下图所示:
    添加stm32mp157d-atk.dtb
    上图中第847行里就是告诉“Makefile”把我们刚新建的stm32mp157d-atk.bts编译成对应的dtb文件。以前编译uboot都是自己输入一条一条命令编译,可以创建一个shell脚本,将所有的编译命令都写到这个shell脚本里面,然后每次的时候只需要执行一下这个shell脚本即可。在uboot源码根目录下新建一个名为stm32mp157d_alientek.sh的shell 脚本,在这个shell脚本里面输入如下内容:
    示例代码13.2.5.2 stm32mp157d_alientek.sh文件
    第3行清零uboot。

    第4行使用stm32mp15_atk_trusted_defconfig来配置uboot。

    第5行编译uboot,设备树为stm32mp157d-atk.dts。

    给予stm32mp157d_alientek.sh可执行权限,然后运行脚本来完成编译,命令如下:

    chmod 777 stm32mp157d_alientek.sh //给予可执行权限,一次即可
    ./stm32mp157d_alientek.sh //运行脚本编译 uboot

    编译成功后会出现如下图所示信息:
    uboot编译成功
    从上图可以看出,stm32mp157d-atk.dts已经编译成功,生成了对应的stm32mp157d-atk.dtb文件,u-boot.stm32就是要烧写测试的,要先将其重命名为my-u-boot.stm32,然后再烧写进去。

    烧写完成以后 uboot启动过程如下图所示:
    uboot启动过程
    从上图可以看出,uboot启动成功,并且进入了命令行模式,并且命令行也可以正常操作,那么是不是说明uboot已经移植成功了呢?不一定,uboot有没有移植成功取决于当前uboot能不能满足要求,如果不满足就说明还没移植成功。

    当前uboot的网络、 USB_OTG也不能正常工作,所以还需要接着修改。

    网络驱动修改

    网络设备树修改

    从上图可以看到“Net: No ethernet found.”这一行,这样行的意思就是没有找到网络,说明uboot下的网路驱动有问题 。原因是当前设备树并没有网络相关节点,只需要将网络相关节点加进去就可以了。打开stm32mp157d-atk.dtsi文件,将如下所示的ethernet0节点加添加到最后面:

    示例代码13.2.6.1 ethernet0节点 
    1 &ethernet0 { 
    2     status = "okay"; 
    3     pinctrl-0 = <&ethernet0_rgmii_pins_a>; 
    4     pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>; 
    5     pinctrl-names = "default", "sleep"; 
    6     phy-mode = "rgmii-id"; 
    7     max-speed = <1000>; 
    8     phy-handle = <&phy0>; 
    9 
    10     mdio0 { 
    11         #address-cells = <1>; 
    12         #size-cells = <0>; 
    13         compatible = "snps,dwmac-mdio"; 
    14         phy0: ethernet-phy@0 { 
    15         reg = <0>; 
    16         }; 
    17     }; 
    18 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    添加完成后如下图所示:
    添加进来的ethernet0节点
    至此,网络节点已经添加到设备树中。

    网络驱动修改

    正点原子V1.3及以后版本的核心板开始将网络PHY芯片更换为了国产裕太电子的YT8511,所以需要修改一下驱动。 YT8511驱动源码以及修改方法已经放到了开发板光盘中,就是 phy.c。 phy.c是正点原子修改后支持YT8511芯片的文件,此文件同时支持RTL8211以及YT8511。用修改后的phy.c文件替换掉uboot下的/drivers/net/phy/phy.c文件即可,设备树无需做任何修改,直接编译即可。

    注意,正点原子V1.2版本核心板上使用的RTL8211,其PHY地址为 0X01。V1.3以后的核心板使用YT8511,其PHY地址为0X00,因此在设备树里面需要修改PHY地址为0X00。但是这样修改以后会导致YT8511和RTL8211的设备树不兼容,需要多编写一份设备树,导致出厂设备树过多。因此为了一个设备树兼容YT8511和RTL8211,正点原子修改了phy.c文件中的 phy_connect函数,直接给定YT8511的地址为0X00,也就是不受设备树控制,如下图所示:
    直接读取YT8511
    这种做法虽然不合规则,但是也是为了一个设备树兼容两个地址不同的PHY芯片而不得已采取的方法。

    编译测试

    重新编译uboot并烧写,uboot启动过程如下图所示:
    uboot启动信息
    从上图中可以看到“ethernet@5800a00 address not set.”字样,说明已经找到了网络外设并且网络外设已经启动,但是还是会报“No ethernet found.”错误,这是因为uboot启动的时候获取不到MAC地址,我们只需要设置一些地址相关的环境变量即可,之前笔记中的uboot的网络相关命令已经有学习过了,命令如下:

    setenv ipaddr 192.168.1.250 //开发板IP地址
    setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡MAC地址
    setenv gatewayip 192.168.1.1 //开发板默认网关
    setenv netmask 255.255.255.0 //开发板子网掩码
    setenv serverip 192.168.1.249 //服务器地址,也就是Ubuntu地址
    saveenv

    设置好地址相关环境变量以后就可以在uboot中使用网络了,用网线将开发板上的网络接口与电脑或者路由器连接起来,保证开发板和电脑在同一个网段内,通过ping命令来测试一下网络连接,命令如下:

    ping 192.168.1.249

    结果如下图所示:
    ping命令测试
    从上图中可以看到“host 192.168.1.249 is alive”这句,表明ping主机成功,说明网络工作正常。

    USB OTG设备树修改

    添加usb_phy_tuning子节点

    在这一小节里,给uboot添加USB_OTG功能,操作stm32mp157d-atk.dtsi这个文件,在根节点“/”下添加名为“usb_phy_tuning”的子节点,节点内容如下:

    示例代码13.2.7.1 usb_phy_tuning节点 
    1 usb_phy_tuning: usb-phy-tuning { 
    2     st,hs-dc-level = <2>; 
    3     st,fs-rftime-tuning; 
    4     st,hs-rftime-reduction; 
    5     st,hs-current-trim = <15>; 
    6     st,hs-impedance-trim = <1>; 
    7     st,squelch-level = <3>; 
    8     st,hs-rx-offset = <2>; 
    9     st,no-lsfs-sc; 
    10 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    新添加的usb_phy_tuning子节点

    添加STUSB1600 I2C子节点

    正点原子STM32MP157开发板上的USB OTG接口类型为Type-C,使用STUSB1600芯片来实现此接口功能,STUSB1600有一个I2C接口,此I2C接口用来配置芯片,因此还需要在设备树中添加STUSB1600相关的I2C节点内容。将如下内容添加到stm32mp157d-atk.dtsi的最后面:

    示例代码13.2.7.2 stusb1600芯片i2c节点 
    1 &i2c1 { 
    2     pinctrl-names = "default", "sleep"; 
    3     pinctrl-0 = <&i2c1_pins_a>; 
    4     pinctrl-1 = <&i2c1_pins_sleep_a>; 
    5     i2c-scl-rising-time-ns = <100>; 
    6     i2c-scl-falling-time-ns = <7>; 
    7     status = "okay"; 
    8     /delete-property/dmas; 
    9     /delete-property/dma-names; 
    10 
    11     stusb1600@28 { 
    12         compatible = "st,stusb1600"; 
    13         reg = <0x28>; 
    14         interrupts = <2 IRQ_T    YPE_EDGE_FALLING>; 
    15         interrupt-parent = <&gpiog>; 
    16         pinctrl-names = "default"; 
    17         pinctrl-0 = <&stusb1600_pins_a>; 
    18         status = "okay"; 
    19         vdd-supply = <&vin>;
    20 
    21         connector { 
    22             compatible = "usb-c-connector"; 
    23             label = "USB-C"; 
    24             power-role = "dual"; 
    25             power-opmode = "default"; 
    26 
    27             port { 
    28                 con_usbotg_hs_ep: endpoint { 
    29                     remote-endpoint = <&usbotg_hs_ep>; 
    30                 }; 
    31             }; 
    32         }; 
    33     }; 
    34 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    由于STUSB1600是挂在STM32MP157的I2C1接口下,因此示例代码13.2.7.2是向I2C1节点追加内容,完成以后如下图所示:
    stusb1600节点

    添加usb接口相关节点

    继续向stm32mp157d-atk.dtsi文件添加USB接口相关节点内容,内容如下:

    示例代码13.2.7.3 usb接口节点 
    1 &usbh_ehci { 
    2     phys = <&usbphyc_port0>; 
    3     status = "okay"; 
    4 }; 
    5 
    6 &usbotg_hs { 
    7     phys = <&usbphyc_port1 0>; 
    8     phy-names = "usb2-phy"; 
    9     usb-role-switch; 
    10     status = "okay"; 
    11 
    12     port { 
    13         usbotg_hs_ep: endpoint { 
    14         remote-endpoint = <&con_usbotg_hs_ep>; 
    15         }; 
    16     }; 
    17 }; 
    18 
    19 &usbphyc { 
    20     status = "okay"; 
    21 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    上述代码中有三个节点usbh_ehci、usbotg_hs和usbphyc,其中usbotg_hs默认就有,在前面将其屏蔽掉了,完成以后如下图所示:
    USB接口节点

    在stm32mp157d-atk-u-boot.dtsi文件中添加usbotg_hs节点

    最后,需要在stm32mp157d-atk-u-boot.dtsi文件里面添加usbotg_hs节点,节点内容如下所示:

    示例代码13.2.7.4 usbotg_hs节点 
    1 &usbotg_hs { 
    2     u-boot,force-b-session-valid; 
    3     hnp-srp-disable; 
    4     /* TEMP: force peripheral for USB OTG */ 
    5     dr_mode = "peripheral"; 
    6 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    添加结果如下图所示:
    stm32mp157d-atk-u-boot.dtsi下的usbotg_hs节点
    至此,uboot下的 USB OTG就已经修改完成,重新编译 uboot并烧写,然后使用ums命令测试,看看能不能将EMMC模拟成U盘,挂载到电脑上。把STM32MP157开发板的USB_OTG接口连接到电脑里,重启开发板,接着运行以下命令:

    ums 0 mmc 1

    如果电脑上出现U盘字样的磁盘,那么USB OTG工作成功。

    使能boot和bootd命令

    ST官方uboot默认并没有使能boot和bootd这两个命令,这两个命令的实现源文件为cmd/bootm.c bootm.c下有如下图所示内容:
    boot和bootd命令具体实现
    从上图可以看出,如果要使能boot和bootd这两个命令 ,必须定义宏CONFIG_CMD_BOOT。打开 include/configs/stm32mp1.h,然后在后面添加如下宏定义:

    #define CONFIG_CMD_BOOTD /* 使能boot和bootd命令 */

    添加后如下图所示:
    添加CONFIG_CMD_BOOTD宏
    重新编译uboot并烧写启动,输入命令:

    ?boot

    或是

    ?bootz

    如果boot和bootd使能的话就会打印出相应的命令使用方法,如下图所示:
    boot和bootd帮助信息

    LCD驱动修改

    uboot也是支持LCD显示的,但是要进行相应的设置,主要是设置屏幕背光、屏幕时序参数这些,这些直接在设备树里面修改即可。打开stm32mp157d-atk.dts文件,在里面添加LCD相
    关节点信息,首先在根节点“/”下添加panel_backlight和panel_rgb这两个节点,节点内容如下:

    示例代码13.2.9.1 新添加节点信息 
    1 panel_backlight: panel-backlight { 
    2     compatible = "gpio-backlight"; 
    3     gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>; 
    4     default-on; 
    5     status = "okay"; 
    6 }; 
    7 
    8 panel_rgb: panel-rgb { 
    9     compatible = "simple-panel"; 
    10    pinctrl-names = "default", "sleep"; 
    11    pinctrl-0 = <&ltdc_pins_b>; 
    12    pinctrl-1 = <&ltdc_pins_sleep_b>; 
    13    backlight = <&panel_backlight>; 
    14    status = "okay"; 
    15 
    16    port { 
    17         panel_in_rgb: endpoint { 
    18             remote-endpoint = <&ltdc_ep0_out>; 
    19         }; 
    20    }; 
    21 
    22    display-timings { 
    23        native-mode = <&timing0>; /* 时序信息 */ 
    24        timing0: timing0 { /* 7寸1024*600分辨率 */ 
    25            clock-frequency = <51200000>; /* LCD 像素时钟,单位 Hz */
    26            hactive = <1024>; /* LCD X 轴像素个数 */ 
    27            vactive = <600>; /* LCD Y 轴像素个数 */ 
    28            hfront-porch = <160>; /* LCD hfp 参数 */ 
    29            hback-porch = <140>; /* LCD hbp 参数 */ 
    30            hsync-len = <20>; /* LCD hspw 参数 */ 
    31            vback-porch = <20>; /* LCD vbp 参数 */ 
    32            vfront-porch = <12>; /* LCD vfp 参数 */ 
    33            vsync-len = <3>; /* LCD vspw 参数 */ 
    34            }; 
    35        }; 
    36 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    第1-6行,panel_backlight为LCD的背光控制节点,主要指定LCD背光IO所使用的引脚,正点原子的STM32MP157开发板LCD背光引脚为PD13。

    第8-38行,panel_rgb为RGB LCD节点,指定了LTDC接口所使用的IO、屏幕时序参数等。第11-12行指定LTDC接口的IO,ltdc_pins_b和ltdc_pins_sleep_b定义在stm32mp15-pinctrl.dtsi文件中。第22-35行的display-timings是非常重要的LCD时序参数,不同的屏幕其时序参数不同,这里演示的是正点原子7寸1024*600分辨率的。这款屏幕时序参数如下图所示:
    RGB LCD屏幕时序参数
    添加完成后如下图所示:
    panel_backlight和panel_rgb节点
    最后还需要在stm32mp157d-atk.dts文件里面向ltdc节点追加一些内容,内容如下:

    示例代码13.2.9.3 ltdc节点 
    1 &ltdc { 
    2     status = "okay"; 
    3     pinctrl-names = "default"; 
    4     port { 
    5         #address-cells = <1>; 
    6         #size-cells = <0>; 
    7 
    8         ltdc_ep0_out: endpoint@0 {
    9             reg = <0>; 
    10            remote-endpoint = <&panel_in_rgb>; 
    11        }; 
    12     }; 
    13 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    添加完成后如下图所示:
    ltdc节点
    修改完成以后编译uboot,得到新的uImage和stm32mp157d-atk.dtb设备树,关于uboot下LCD的测试方法稍后会讲解。

    U-boot测试

    自烧写测试

    之前的TF-A和uboot笔记中说了很多次STM32CubeProgrammer是如何烧写系统的,核心就是先向DDR里面下载一个 uboot镜像,然后启动此uboot,使用uboot里面的相关命令进行烧写。本章前面都是使用正点原子出厂u-boot.stm32来烧写我们移植的uboot,本小节就用我们移植好的 u-boot来烧写自身,也就是自烧写测试。这里就再也不需要my-u-boot.stm32了,直接使用我们前面编译得到的u-boot.stm32替换掉images目录下的正点原子出厂u-boot.stm32。然后修改FlashLayout,如下图所示:
    修改后的FlashLayout
    修改完成以后重新烧写测试,此时首先下载到DDR中的u-boot.stm32镜像也是自己编译得到了,也就是用自己编译的uboot来烧写自身。检测方法很简单,就是看能不能正常烧写

    从EMMC启动Linux

    从EMMC启动也就是将编译出来的Linux镜像文件uImage和.dtb设备树文件保存在EMMC中,uboot从EMMC中读取这两个文件并启动,这个是产品最终的启动方式。首先EMMC里面要先存放Linux镜像文件uImage和.dtb设备树,但是我们前面新建的FlashLayout文件并没有烧写uImage和.dtb,所以需要修改一下FlashLayout文件,加入uImage和.dtb烧写命令。由于还没有移植Linux系统,所以uImage和.dtb就先使用正点原子出厂系统提供的, 就是atk-image-bootfs.ext4。 atk-image-bootfs.ext4是ext4格式的打包文件,因为STM32CubeProgrammer软件要求将uImage和.dtb打包在一起,格式为ext4。atk-image-bootfs.ext4里面的文件如下图所示:
    atk-image-bootfs.ext4文件
    从上图可以看出,正点原子出厂的atk-image-bootfs.ext4里面还是有不少文件,其中最重要的就是uImage和.dtb设备树。后面讲解Linux系统移植的时候会讲解如何将uImage和.dtb打包成ext4格式。

    复制一份atk-image-bootfs.ext4到images文件夹,然后打开FlashLayout文件(tf-a.tsv),添加下面一行:

    P 0x21 boot System mmc1 0x00280000 atk-image-bootfs.ext4
    
    • 1

    修改完成以后如下图所示:
    修改后的FlashLayout
    修改完成以后烧写到开发板中并重启,首先使用ext4ls命令查看一下EMMC的分区2里面有没有uImage和.dtb文件,命令如下:

    ext4ls mmc 1:2

    结果如下图所示:
    EMMC分区2文件
    这里只需要用到上图中的uImage和stm32mp157d-atk.dtb这两个文件,设置bootcmd环境变量从EMMC里面读取系统文件,然后再启动,这个在前面讲解BOOT命令的时候已经讲过了如何操作, 命令如下:

    setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
    saveenv
    boot

    设置好以后uboot就会按照bootcmd环境变量的内容加载系统并启动,如下图所示:
    系统启动流程
    注意!只要出现上图中的“Booting Linux on physical CPU 0x0”这一行就说明uboot引导Linux内核成功!

    从网络启动Linux系统

    从网络启动Linux系统的唯一目的就是为了调试!不管是为了调试Linux系统还是Linux下的驱动。每次修改Linux系统文件或者Linux下的某个驱动以后都要将其烧写到EMMC中去测试,这样太麻烦了。可以设置Linux从网络启动,也就是将Linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,这样每次重新编译Linux内核或者某Linux驱动以后只需要使用cp命令将其拷贝到这个指定的文件夹中即可,就不用需要频繁的烧写EMMC,加快了开发速度。可以通过nfs或者tftp从Ubuntu中下载uImage和设备树文件,根文件系统的话也可以通过nfs挂载,不过本小节不讲解如何通过nfs挂载根文件系统,这方面内容会在讲解根文件系统移植的时候再讲解。这里使用tftp从Ubuntu中下载uImage和设备树文件,前提是要将uImage和设备树文件放到Ubuntu下的tftp目录中。

    设置bootcmd环境变量,设置如下:

    setenv bootcmd 'tftp c2000000 uImage;tftp c4000000 stm32mp157d-atk.dtb;bootm c2000000 - (有空格 ) c4000000'
    saveenv
    boot

    设置好以后,uboot先从tftp服务器下载uImage和stm32mp157d-atk.dtb这两个文件,然后启动,如下图所示:
    uboot网络启动Linux成功

    LCD测试

    烧写过程显示测试

    uboot下LCD测试有两种方法,第一种就是用STM32CubeProgrammer烧写系统的时候会在LCD上显示烧写过程,如下图所示:
    uboot烧写过程

    bmp命令显示测试

    第二种就是可以使用uboot下的bmp命令在LCD上显示一张bmp图片,bmp命令如下图所示:
    bmp命令
    从上图中可以看出,有bmp info和bmp display两个命令:

    • bmp info命令

    命令格式如下:

    bmp info
    bmp info命令用于显示BMP图片信息,imageAddr就是BMP图片在RAM中的起始地址。
    • bmp display命令
    bmp display [x, y]

    bmp display命令用于显示bmp图片,imageAddr是要显示的BMP图片在RAM中的起始地址,[x,y]用于指定BMP图片左上角在屏幕上的显示坐标。

    可以准备一个BMP格式的图片,符合如下要求:

    1. 图片的分辨率不能超过当前所使用的LCD分辨率。
    2. 图片的色深应该和LCD驱动格式一致,比如STM32MP1的uboot中LCD驱动默认为16BPP色彩的RGB565格式,因此BMP图片也必须是16位的RGB565格式。一般图片都是32位色深度,需要进行转换。

    16位RGB565格式的BMP图片准备好以后就可以显示了,首先将要显示的BMP图片放到ubuntu的TFTP服务器目录下,通过网络将BMP图片下载到板子的DDR中,然后再用bmp命令显示。命令如下:

    tftp c0000000 test.bmp //下载bmp图片
    bmp info c0000000 //显示图片信息

    图片信息如下:
    图片信息
    从上图可以看出,当前BMP图片分辨率为1024600,每个像素16位,也就是16BPP,当前LCD分辨率为1024600,输入如下命令在LCD上显示图片:

    bmp display c0000000 0 0 //显示bmp图片

    结果如下图所示:
    bmp图片显示

    bootcmd和bootargs环境变量

    bootcmd环境变量

    bootcmd在前面已经说了很多次了,bootcmd保存着uboot默认命令,uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取EMMC或者NAND Flash中的Linux内核镜像文件和设备树文件到DRAM中,然后启动Linux内核。可以在uboot启动以后进入命令行设置bootcmd环境变量的值。如果EMMC或者NAND中没有保存bootcmd的值,那么uboot就会使用默认的值,板子第一次运行uboot的时候都会使用默认值来设置bootcmd环境变量。打开文件include/env_default.h,在此文件中有如下所示内容:

    示例代码13.4.1.1 默认环境变量 
    13 env_t embedded_environment __UBOOT_ENV_SECTION__(environment) = { 
    14     ENV_CRC, /* CRC Sum */ 
    15 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT 
    16     1, /* Flags: valid */ 
    17 #endif 
    18     { 
    19 #elif defined(DEFAULT_ENV_INSTANCE_STATIC) 
    20 static char default_environment[] = { 
    21 #else 
    22 const uchar default_environment[] = {
    23 #endif 
    24 #ifndef CONFIG_USE_DEFAULT_ENV_FILE 
    25 #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT 
    26     ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" 
    27 #endif 
    28 #ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT 
    29     ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" 
    30 #endif 
    31 #ifdef CONFIG_USE_BOOTARGS 
    32     "bootargs=" CONFIG_BOOTARGS "\0" 
    33 #endif 
    34 #ifdef CONFIG_BOOTCOMMAND 
    35     "bootcmd=" CONFIG_BOOTCOMMAND "\0" 
    36 #endif 
    37 #ifdef CONFIG_RAMBOOTCOMMAND 
    38     "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" 
    39 #endif 
    40 #ifdef CONFIG_NFSBOOTCOMMAND 
    41     "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0" 
    42 #endif 
    43 #if defined(CONFIG_BOOTDELAY) 
    44     "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0" 
    45 #endif 
    46 #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0) 
    47     "baudrate=" __stringify(CONFIG_BAUDRATE) "\0" 
    48 #endif 
    49 #ifdef CONFIG_LOADS_ECHO 
    50     "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0" 
    51 #endif 
    52 #ifdef CONFIG_ETHPRIME 
    53     "ethprime=" CONFIG_ETHPRIME "\0" 
    54 #endif 
    55 #ifdef CONFIG_IPADDR 
    56     "ipaddr=" __stringify(CONFIG_IPADDR) "\0" 
    57 #endif 
    58 #ifdef CONFIG_SERVERIP 
    59     "serverip=" __stringify(CONFIG_SERVERIP) "\0" 
    60 #endif 
    61 #ifdef CONFIG_SYS_AUTOLOAD 
    62     "autoload=" CONFIG_SYS_AUTOLOAD "\0" 
    63 #endif 
    64 #ifdef CONFIG_PREBOOT 
    65     "preboot=" CONFIG_PREBOOT "\0"
    66 #endif 
    67 #ifdef CONFIG_ROOTPATH 
    68     "rootpath=" CONFIG_ROOTPATH "\0" 
    69 #endif 
    70 #ifdef CONFIG_GATEWAYIP 
    71     "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0" 
    72 #endif 
    73 #ifdef CONFIG_NETMASK 
    74     "netmask=" __stringify(CONFIG_NETMASK) "\0" 
    75 #endif 
    76 #ifdef CONFIG_HOSTNAME 
    77     "hostname=" CONFIG_HOSTNAME "\0" 
    78 #endif 
    79 #ifdef CONFIG_BOOTFILE 
    80     "bootfile=" CONFIG_BOOTFILE "\0" 
    81 #endif 
    82 #ifdef CONFIG_LOADADDR 
    83     "loadaddr=" __stringify(CONFIG_LOADADDR) "\0" 
    84 #endif 
    85 #ifdef CONFIG_CLOCKS_IN_MHZ 
    86 "clocks_in_mhz=1\0" 
    87 #endif 
    88 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0) 
    89     "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0" 
    90 #endif 
    91 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG 
    92     "arch=" CONFIG_SYS_ARCH "\0" 
    93 #ifdef CONFIG_SYS_CPU 
    94     "cpu=" CONFIG_SYS_CPU "\0" 
    95 #endif 
    96 #ifdef CONFIG_SYS_BOARD 
    97     "board=" CONFIG_SYS_BOARD "\0" 
    98     "board_name=" CONFIG_SYS_BOARD "\0" 
    99 #endif 
    100 #ifdef CONFIG_SYS_VENDOR 
    101    "vendor=" CONFIG_SYS_VENDOR "\0" 
    102 #endif 
    103 #ifdef CONFIG_SYS_SOC 
    104    "soc=" CONFIG_SYS_SOC "\0" 
    105 #endif 
    106 #endif 
    107 #if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
    108    "bootlimit=" __stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0" 
    109 #endif 
    110 #ifdef CONFIG_EXTRA_ENV_SETTINGS 
    111    CONFIG_EXTRA_ENV_SETTINGS 
    112 #endif 
    113    "\0" 
    114 #else /* CONFIG_USE_DEFAULT_ENV_FILE */ 
    115 #include "generated/defaultenv_autogenerated.h" 
    116 #endif 
    117 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED 
    118    } 
    119 #endif 
    120 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    从示例代码13.3.4.1的第13行可以看出,embedded_environment是个env_t类型的变量,保存在environment 段里面,env_t类型如下:
    示例代码13.3.4.2 env_t结构体
    env_t结构体中的crc为CRC值,flags是标志位,data数组就是环境变量值。 示例代码13.3.4.1中指定了很多环境变量的默认值,比如bootcmd的默认值就是CONFIG_BOOTCOMMAND,bootargs的默认值就是CONFIG_BOOTARGS。可以直接在stm32mp1.h文件中通过设置宏CONFIG_BOOTCOMMAND来设置bootcmd的默认值

    bootargs环境变量

    bootargs保存着uboot传递给Linux内核的参数,比如指定Linux内核所使用的console、指定根文件系统所在的分区等,如以下bootargs环境变量值:

    console=ttySTM0,115200 root=/dev/mmcblk2p3 rootwait rw

    console

    console用来设置linux终端(或者叫控制台),也就是通过什么设备来和Linux进行交互,是串口还是LCD屏幕?如果是串口的话应该是串口几等等。一般设置串口作为Linux终端,这样就可以在电脑上通过MobaXterm来和linux交互了。这里设置console为ttySTM0,因为linux启动以后STM32MP1的串口4在linux下的设备文件就是/dev/ttySTM0

    ttySTM0后面有个“,115200”,这是设置串口的波特率,console=ttySTM0,115200综合起来就是设置ttySTM0(就是串口4)作为Linux终端,并且串口波特率设置为115200。

    root

    root用来设置根文件系统的位置,root=/dev/mmcblk2p3用于知名根文件系统存放在mmcblk2设备的分区3中。正点原子的STM32MP1核心板启动 linux以后会存在/dev/mmcblk1、/dev/mmcblk2、/dev/mmcblk1p1、/dev/mmcblk1p2、/dev/mmcblk2p1、/dev/mmcblk2p2和/dev/mmcblk2p3这样的文件,其中/dev/mmcblkx(x=0~n)表示mmc设备,而/dev/mmcblkxpy(x=0-n,y=1-n)表示mmc设备x的分区y在STM32MP1开发板中/dev/mmcblk2表示EMMC,而/dev/mmcblk2p3表示EMMC的分区3。

    root后面有“rootwait rw”,rootwait表示等待mmc设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的。rw表示根文件系统是可以读写的,不加rw的话可能无法在根文件系统中进行写操作,只能进行读操作。

    rootfstype

    此选项一般配合root一起使用,rootfstype用于指定根文件系统类型,如果根文件系统为ext格式的话此选项无所谓。如果根文件系统是yaffs、jffs或ubifs的话就需要设置此选项,指定根文件系统的类型。

    bootargs常设置的选项就这三个,后面遇到其 他选项的话再讲解。

    总结

    uboot移植流程

    首先要先创建自己使用开发板的默认配置文件,这个需要在第一次编译uboot的时候先执行:

    make stm32mp15_trusted_defconfig

    这个文件可以直接参考官方的STM32MP157 EVK开发板,如下命令:

    cd configs //进入uboot的configs目录
    cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig //拷贝

    然后需要创建设备树,可以直接复制ST官方EVK开发板内容:

    cd arch/arm/dts/ //进入uboot设备树目录
    cp stm32mp157d-ed1.dts stm32mp157d-atk.dts //复制.dts
    cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi //复制.dtsi
    cp stm32mp157a-ed1-u-boot.dtsi stm32mp157d-atk-u-boot.dtsi //复制.dtsi

    创建完成后,需要在stm32mp157d-atk.dts中加上对于stm32mp157d-atk.dtsi的引用;之后需要完成如下修改:

    • 修改电源管理设置(这一部分需要删去两个IO定义,led以及pmic定义;之后删除adc、dac以及i2c4节点;再删除led和sd_switch节点;添加正点原子开发板的电源管理配置)
    • 修改TF卡和EMMC配置(修改sdmmc1和sdmmc2)
    • 修改网络驱动(修改网络设备树,添加ethernet0节点;修改网络驱动,针对的是PHY芯片)
    • 修改USB OTG设备树(添加usb_phy_tuning节点;添加STUSB1600 I2C节点;最后添加usb接口的相关节点)
    • 使能boot和bootd命令(在include/configs/stm32mp1.h中定义宏CONFIG_CMD_BOOTD)
    • 有LCD,则需要添加LCD驱动(添加panel_backlight和panel_rgb节点;追加ltdc节点内容)

    总结之总结

    这一篇笔记就是针对STM32MP157开发板完成uboot的移植,从ST官方的源代码出发,经过对于正点原子开发板的适配,修改设备树内容完成uboot移植。

  • 相关阅读:
    React 组件中无法清除定时器问题记录
    回文串 rust解法
    存储数据的介质销毁时怎么处置
    VUE3与Uniapp 三 (属性绑定)
    设计模式——职责链模式
    Git--分布式版本控制工具
    基于flink与groovy实现全实时动态规则智能营销与风控系统
    MySQL-数据目录
    83 # 静态服务中间件 koa-static 的使用以及实现
    前端技术栈学习:Vue2、Vue cli脚手架、ElementUI组件库、Axios
  • 原文地址:https://blog.csdn.net/xhj12138/article/details/133611586