STM32MP157开发板调试实用指南

作者:zzssdd2
E-mail:zzssdd2@foxmail.com

一、前言

​ 最近在ODYSSEY-STM32MP157C板子上移植arm-trusted-firmwareu-boot以及linux(其实这个开发板官方是有提供完整的系统镜像的,重新移植的原因主要是官方镜像没有使用TF-A,而是使用Uboot-SPL替代TF-A作为FSBL启动)。本以为之前在另一块stm32mp157板子上面移植过这些东西所以应该问题不大,但是由于硬件设计的差异仍然是遇到了一些问题。最后还是花费了些时间解决问题,故写这篇笔记用来记录各环节遇到的问题及解决过程。

二、Trusted Firmware A (TF-A)

版本:arm-trusted-firmware-2.2-stm32mp-r2.3

1、问题

ST官方的开发板都是使用芯片的I2C4驱动PMIC,而这块开发板是用的I2C2接口,本以为将设备树中驱动PMIC节点的i2c4部分改为i2c2,然后添加上i2c2的pinctrl信息就可以了。然而并非如此,会报如下错误:

PANIC at PC : 0x2ffeeab3

Exception mode=0x00000016 at: 0x2ffeeab3

2、原因

I2C4或I2C6被定义为安全外设,而I2C2为非安全外设。

在源码drivers/st/pmic/stm32mp_pmic.c中PMIC初始化函数调用如下:

void initialize_pmic(void)
    --> initialize_pmic_i2c()	//从设备树获取pmic的i2c节点信息并初始化
    --> register_non_secure_pmic()
    	--> stm32mp_register_non_secure_periph_iomem(i2c_handle.i2c_base_addr)
    		--> register_periph_iomem(base, SHRES_NON_SECURE)

由于在函数register_periph_iomem中没有定义I2C_BASE导致进入panic()函数。

3、解决方法

在文件plat/st/stm32mp1/stm32mp1_def.h中定义I2C2_BASE:

#define I2C2_BASE			U(0x40013000)

然后修改文件plat/st/stm32mp1/stm32mp1_shared_resources.c中的函数register_periph_iomem如下:

	case UART8_BASE:
	case IWDG2_BASE:
	case I2C2_BASE:	//添加非安全外设I2C2
		/* Allow drivers to register some non-secure resources */
		VERBOSE("IO for non-secure resource 0x%x\n",
			(unsigned int)base);
		if (state != SHRES_NON_SECURE) {
			panic();
		}

		return;

	default:
		panic();
		break;

三、U-Boot

版本:u-boot-2020.01-stm32mp-r2.2

1、问题

移植完成第一次进入u-boot首先出现如下提示:

invalid MAC address in OTP 00:00:00:00:00:00
Net:
Error: ethernet@5800a000 address not set.
No ethernet found.

设置ethaddr环境变量即可:

env set ethaddr 14:16:0B:0B:11:31

上面这个倒是不算问题,重点是接下来遇到的问题。在执行dhcp命令时遇到如下错误:

STM32MP> dhcp
EQOS_DMA_MODE_SWR stuckFAILED: -110STM32MP>

这显然是网卡有问题。

2、原因

查看硬件原理图以太网部分发现和ST官方的DK2开发板有些不同。官方开发板的千兆以太网(RGMII)的125MHZ时钟来自PHY芯片,而我手上这块开发板的设计默认是需要由MPU内部RCC提供125MHZ时钟。除此之外,PHY地址硬件设计上也不相同,需要修改。

在STM32MP157参考手册(RM0436)中的Figure 83对以太网时钟有详细的描述

由上图可知若要使用RCC作为125MHZ时钟来源则需要配置SYSCFG寄存器的ETH_CLK_SEL字段,除此之外还需要选择使用RCC的pll4_p_ck或是pll3_q_ck作为具体时钟来源(我选择的是PLL4P)。既然知道了问题所在,接下来就是修改代码适配硬件。

3、解决方法

首先是时钟部分的改动。因为使用了TF-A所以U-Boot配置为trusted模式,修改u-boot源码中的时钟配置是无效的,需要修改TF-A中的时钟配置。主要就是配置PLL4P输出125MHZ时钟,关于PLL的详细信息需要查阅参考手册(RM0436)的 第10章RCC(Reset and clock control) 的PLL章节。

在TF-A源码设备树的rcc节点中添加如下代码配置PLL4时钟频率:

&rcc {
    ......
    /* VCO = 750.0 MHz => P = 125, Q = 62.5, R = 62.5 */
	pll4: st,pll@3 {
		compatible = "st,stm32mp1-pll";
		reg = <3>;
		cfg = < 3 124 5 11 11 PQR(1,1,1) >;
	};
    ......
};

cfg中参数含义如下:

cfg = <DIVM DIVN DIVP DIVQ DIVR Output(DIVPEN DIVQEN DIVREN)>

因此按照上述参数计算各部分时钟频率结果如下:

F(ref_ck) = HSE / (DIVM + 1)

Using the PLLs in integer mode

For the PLL3 and PLL4, the VCO frequency (FVCO) is given by the following expression:

F(VCO) = F(ref_ck) x (DIVN + 1)

And the frequency at the output of the post-dividers is given by with y = P, Q or R:

F(pll_y_ck) = F(VCO) / (DIVy + 1)

VCO = HSE / (DIVM + 1) * (DIVN + 1) = 24MHZ / (3 + 1) * (124 + 1) = 750MHZ
PLL4P = P = VCO / (DIVP + 1) = 750MHZ / (5 + 1) = 125MHZ
PLL4Q = VCO / (DIVQ + 1) = 750MHZ / (11 + 1) = 62.5MHZ
PLL4R = VCO / (DIVR + 1) = 750MHZ / (11 + 1) = 62.5MHZ 

这样就得到了期望的125MHZ时钟。接着还需要将Ethernet的时钟选为PLL4P,在rcc节点修改如下内容:

&rcc {
    ......
    	st,pkcs = <
		......
-       CLK_ETH_DISABLED	//删除这个
+		CLK_ETH_PLL4P		//添加这个
		......
	>;
    ......
};

至此,千兆以太网125MHZ时钟频率就配置好了。接下来需要修改的就是u-boot源码的设备树中ethernet0节点内容,主要是修改时钟选择部分的内容。根据手册可知选择RCC作为千兆以太网125 MHz时钟需要将寄存器SYSCFG_PMCSETRETH_CLK_SEL位配置为1:

在源码drivers/net/dwc_eth_qos.c文件中eqos_probe_resources_stm32函数会调用board_interface_eth_init函数(文件路径board/st/stm32mp1/stm32mp1.c)根据设备树内容配置该寄存器该位,如下:

/* eth init function : weak called in eqos driver */
int board_interface_eth_init(struct udevice *dev,
			     phy_interface_t interface_type)
{
	u8 *syscfg;
	u32 value;
	bool eth_clk_sel_reg = false;
	......
	/* Gigabit Ethernet 125MHz clock selection. */
	eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
	......
	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
	......
	switch (interface_type) {
	......
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
	case PHY_INTERFACE_MODE_RGMII_TXID:
		if (eth_clk_sel_reg)
			value = SYSCFG_PMCSETR_ETH_SEL_RGMII |
				SYSCFG_PMCSETR_ETH_CLK_SEL;
		else
			value = SYSCFG_PMCSETR_ETH_SEL_RGMII;
		debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__);
		break;
	......
	}

	/* clear and set ETH configuration bits */
	writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII |
	       SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL,
	       syscfg + SYSCFG_PMCCLRR);
	writel(value, syscfg + SYSCFG_PMCSETR);

	return 0;
}

因此需要在设备树ethernet0节点下添加st,eth_clk_sel(文件路径arch/arm/dts/stm32mp151.dtsi)如下:

ethernet0: ethernet@5800a000 {
	......
    st,eth_clk_sel;
	......
};

但是只是这么做还不够,进入u-boot会提示如下:

Net:   No phy clock provided -61eth0: ethernet@5800a000

根据提示可以定位到代码位置在drivers/net/dwc_eth_qos.ceqos_probe_resources_stm32函数中:

/*  Get ETH_CLK clocks (optional) */
ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
if (ret)
    pr_warn("No phy clock provided %d", ret);

因此在设备树ethernet0添加eth-ck如下:

ethernet0: ethernet@5800a000 {
	......
    clock-names = "stmmaceth",
        "mac-clk-tx",
        "mac-clk-rx",
+       "eth-ck", //添加这行
        "ethstp";
    ......
    st,eth_clk_sel;
	......
};

但是但是,这么做依旧不够,修改后u-boot执行dhcp命令报错如下:

STM32MP> dhcp
stm32mp1_clk_get_id: clk id 112 not found
clk_enable(clk_ck) failed: -22eqos_start_clks() failed: -22FAILED: -22STM32MP>

因为添加了时钟名后还需要添加对应的时钟节点,因此在设备树ethernet0节点添加ETHCK_K如下:

ethernet0: ethernet@5800a000 {
	......
    clock-names = "stmmaceth",
        "mac-clk-tx",
        "mac-clk-rx",
        "eth-ck",
        "ethstp";
    clocks = <&rcc ETHMAC>,
        <&rcc ETHTX>,
        <&rcc ETHRX>,
+       <&rcc ETHCK_K>, //添加这行
        <&rcc ETHSTP>;
    st,eth_clk_sel;
	......
};

最后还得修改phy地址以及添加phy复位引脚(需和硬件设计一致),否则会有如下报错提示:

地址错误:

STM32MP> dhcp
Could not get PHY for ethernet@5800a000: addr 0
phy_connect() failedFAILED: 0

复位引脚缺失错误

Net:   gpio_request_by_name(phy reset) not provided -2eth0: ethernet@5800a000

修改如下:

&ethernet0 {
	......
	mdio0 {
		......
		phy0: ethernet-phy@7 {
			reg = <7>; //phy地址
            reset-gpios = <&gpiog 0 GPIO_ACTIVE_LOW>; //phy复位引脚
		};
	};
};

复位操作在源码drivers/net/dwc_eth_qos.c函数eqos_probe_resources_stm32匹配设备树,函数eqos_start_resets_stm32执行。

以上修改完成后重新编译u-boot启动后执行网络操作命令就正常了:

STM32MP> dhcp
ethernet@5800a000 Waiting for PHY auto negotiation to complete........... done
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
DHCP client bound to address 192.168.10.85 (2875 ms)
STM32MP>

四、Linux Kernel

版本:linux-5.4-stm32mp-r2.4

1、问题

既然U-Boot部分网络有问题,那么在Linux中也会有同样的问题。但是在linux中只做u-boot中的改动网络仍然无法正常工作,会报如下错误:

root@arm:~# [  316.042400] stm32-dwmac 5800a000.ethernet eth0: no phy at addr -1
[  316.047061] stm32-dwmac 5800a000.ethernet eth0: stmmac_open: Cannot attach to PHY (error: -19)
[  316.124044] stm32-dwmac 5800a000.ethernet eth0: no phy at addr -1
[  316.128703] stm32-dwmac 5800a000.ethernet eth0: stmmac_open: Cannot attach to PHY (error: -19)
[  316.186944] stm32-dwmac 5800a000.ethernet eth0: no phy at addr -1
[  316.191693] stm32-dwmac 5800a000.ethernet eth0: stmmac_open: Cannot attach to PHY (error: -19)
[  316.242397] stm32-dwmac 5800a000.ethernet eth0: no phy at addr -1
[  316.247066] stm32-dwmac 5800a000.ethernet eth0: stmmac_open: Cannot attach to PHY (error: -19)

2、原因

在Linux设备树的ethernet0节点还需要添加一些phy芯片信息(这个板子是KSZ9031)并且要配置相关的驱动。

3、解决方法

make menuconfig

				Linux/arm 5.4.192 Kernel Configuration
Device Drivers  ---> 
	[*] Network device support  ---> 
		 -*-   PHY Device support and infrastructure  --->
		 	   <*>   Micrel PHYs

完整的ethernet0设备树内容如下:

ethernet0: ethernet@5800a000 {
    compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
    reg = <0x5800a000 0x2000>;
    reg-names = "stmmaceth";
    interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
    					<&exti 70 IRQ_TYPE_LEVEL_HIGH>;
    interrupt-names = "macirq",
    				"eth_wake_irq";
    clock-names = "stmmaceth",
                "mac-clk-tx",
                "mac-clk-rx",
+               "eth-ck", //添加这行
                "ethstp";
    clocks = <&rcc ETHMAC>,
            <&rcc ETHTX>,
            <&rcc ETHRX>,
+           <&rcc ETHCK_K>, //添加这行
            <&rcc ETHSTP>;
+   st,eth-clk-sel; //添加这行
    st,syscon = <&syscfg 0x4>;
    snps,mixed-burst;
    snps,pbl = <2>;
    snps,en-tx-lpi-clockgating;
    snps,axi-config = <&stmmac_axi_config_0>;
    snps,tso;
    power-domains = <&pd_core>;
    status = "disabled";

    stmmac_axi_config_0: stmmac-axi-config {
        snps,wr_osr_lmt = <0x7>;
        snps,rd_osr_lmt = <0x7>;
        snps,blen = <0 0 0 0 16 8 4>;
    };
};

&ethernet0 {
	status = "okay";
	pinctrl-0 = <&ethernet0_rgmii_pins_a>;
	pinctrl-1 = <&ethernet0_rgmii_pins_sleep_a>;
	pinctrl-names = "default", "sleep";
	phy-mode = "rgmii";
	max-speed = <1000>;
	phy-handle = <&phy0>;

	mdio0 {
		#address-cells = <1>;
		#size-cells = <0>;
		compatible = "snps,dwmac-mdio";

		phy0: ethernet-phy@7 {
			/* PHY_ID_KSZ9031		0x00221620 */
+    		compatible = "ethernet-phy-id0022.1620"; //添加这行
			reset-gpios = <&gpiog 0 GPIO_ACTIVE_LOW>; //phy复位引脚
			reset-assert-us = <1000>;
			reset-deassert-us = <2000>;
			reg = <7>; //phy地址
		};
	};
};

重新编译linux镜像和设备树,启动后有如下提示信息说明网络正常了

[   15.235404] stm32-dwmac 5800a000.ethernet eth0: PHY [stmmac-0:07] driver [Micrel KSZ9031 Gigabit PHY]
[   15.275230] dwmac4: Master AXI performs any burst length
[   15.281043] stm32-dwmac 5800a000.ethernet eth0: No Safety Features support found
[   15.287068] stm32-dwmac 5800a000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
[   15.287593] stm32-dwmac 5800a000.ethernet eth0: registered PTP clock
[   15.287621] stm32-dwmac 5800a000.ethernet eth0: configuring for phy/rgmii link mode
[   18.391932] stm32-dwmac 5800a000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off

五、Root File System

debian-11.5-minimal-armhf-2022-10-06

1、问题

会自动报如下错误:

EXT4-fs (mmcblk0p4): error count since last fsck: 1
EXT4-fs (mmcblk0p4): initial error at time 1667385179: ext4_get_journal_inode:5149: inode 8

执行apt update命令时报如下错误:

E: List directory /var/lib/apt/lists/partial is missing. - Acquire (30: Read-only file system)

2、原因

文件系统损坏

3、解决方法

重新制作文件系统烧录SD卡启动后问题解决

至此,在ODYSSEY-STM32MP157C开发板系统移植过程中遇到的这些困扰两年半的问题就都解决了

物联沃分享整理
物联沃-IOTWORD物联网 » STM32MP157开发板调试实用指南

发表评论