zynmp系统调试踩的坑

zynqmp 系统调试记录

调试环境

系统环境

  • Ubuntu 20.04

软件环境

  • Vivado 2021.1
  • Petalinux 2021.1

构建系统

生成 Vivado 工程

  根据原理图选择对应的 part 创建 vivado 工程,添加新的 block design,添加 zynqmp ip 核。

IP 核配置

  连接方式参考原理图,因为是公司的项目就不放图了。

  这里需要注意的一个坑是 dp 的 lane 连接,对于仅用了一个 lane 的 dp,根据原理图选择对应的 MIO 即可,但是如果使用了两个 lane,需要注意DP Lane0DP Lane1GT Lane1GT Lane0的对应关系,这是选择Dual Lower的情况,如果是Dual Higher,应该是GT Lane3GT Lane2,同时需要留意原理图上是不是一样的对应关系,一定要按照 Xilinx 的参考设计。

  个人分析原因应该是在 zynqmp 配置的时候连接是反的,所以原理图上连接到转换芯片上时也需要反过来,总之是一个很容易忽略的细节。这里附上我在 Xilinx 论坛的提问链接

生成 Petalinux 系统

  生成系统没什么好说的,根据 petalinux 文档操作即可,注意选择正确的template,zynqmp 自然是选择zynqMP。导入 vivado 编译生成的xsa文件,然后编译一次,petalinux 自己生成设备树,方便后续修改。

提示

  因为 Petalinux 每次编译会从服务器下载xlnx的源码,所以建议自己配置一个本地服务器或者公司内网使用的服务器,推荐后者。
编辑 Petalinux 的Yocto设置,启用YOCTO_NETWORK_SSTATE_FEEDS,并设置YOCTO_NETWORK_SSTATE_FEEDS_URL为配置好的服务器地址,这样可以大幅减少第一次编译的时间,配置服务器之后会写另外一篇博客,更新后回附上链接。 project-spec/configs/config部分内容如下

1
2
3
4
5
6
CONFIG_YOCTO_NETWORK_SSTATE_FEEDS=y

#
# Network sstate feeds URL
#
CONFIG_YOCTO_NETWORK_SSTATE_FEEDS_URL="http://petamirror.com:12333/sswreleases/rel-v2021/aarch64/sstate-cache"

接口调试

网口调试

  网口调试更依赖与选择的芯片以及连接方式,这次使用的芯片配置比较简单,并且直接连在了 PS 端,所以仅声明一下phy-handle以及寄存器地址即可。

1
2
3
4
5
6
7
8
9
&gem0 {
	status = "okay";
	phy-mode = "rgmii-id";
	phy-handle = <&ethernet_phy0>;
	ethernet_phy0: ethernet-phy@0 {
		reg = <0>;
        led-reg-value = <0x0088>;
	};
};

  配置完成后网口10Mbps100Mbps1000Mbps都可以正常工作,但是网口的指示灯不符合常用习惯,所以我在驱动中添加了led-reg-value的代码,根据手册设置指示灯的颜色。

 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
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 5aec673a0120..024c4a5d4dcc 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -664,6 +664,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev)

 static void marvell_config_led(struct phy_device *phydev)
 {
+	u16 led_reg_value;
+	int ret;
+	struct device_node *np = phydev->mdio.dev.of_node;
+
 	u16 def_config;
 	int err;

@@ -688,6 +692,14 @@ static void marvell_config_led(struct phy_device *phydev)
 		return;
 	}

+	ret = of_property_read_u16(np, "led-reg-value", &led_reg_value);
+	if (ret) {
+		phydev_info(phydev, "No custom led reg value, set default value\n");
+	} else {
+		def_config = led_reg_value;
+		phydev_info(phydev, "Set custom led reg value%d\n", led_reg_value);
+	}
+
 	err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, MII_PHY_LED_CTRL,
 			      def_config);
 	if (err < 0)

USB 调试

  Petalinux2021.1 中 USB 的配置已经很简单了,zynqmp ip 核按照原理图正确配置后,一般可以直接自动生成正确的设备树。但是由于都使用了 dwc3 的驱动,usb2.0 存在问题,Petalinux2021.2 修复了这个问题,我摘取了其中有关 usb 的代码,直接添加到当前工程的 patch 中。

 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
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 7231c5a3eece..85bb308959fb 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -374,14 +374,6 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
 	u32			reg;
 	struct gpio_desc	*reset_gpio = NULL;

-	usb3_phy = devm_phy_get(dev, "usb3-phy");
-	if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) {
-		ret = -EPROBE_DEFER;
-		goto err;
-	} else if (IS_ERR(usb3_phy)) {
-		usb3_phy = NULL;
-	}
-
 	crst = devm_reset_control_get_exclusive(dev, "usb_crst");
 	if (IS_ERR(crst)) {
 		ret = PTR_ERR(crst);
@@ -407,6 +399,15 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
 		goto err;
 	}

+	usb3_phy = devm_phy_get(dev, "usb3-phy");
+	if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	} else if (IS_ERR(usb3_phy)) {
+		ret = 0;
+		goto skip_usb3_phy;
+	}
+
 	ret = reset_control_assert(crst);
 	if (ret < 0) {
 		dev_err(dev, "Failed to assert core reset\n");
@@ -461,17 +462,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
 		goto err;
 	}

-	/*
-	 * This routes the USB DMA traffic to go through FPD path instead
-	 * of reaching DDR directly. This traffic routing is needed to
-	 * make SMMU and CCI work with USB DMA.
-	 */
-	if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) {
-		reg = readl(priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG);
-		reg |= XLNX_USB_TRAFFIC_ROUTE_FPD;
-		writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG);
-	}
-
+skip_usb3_phy:
 	/* ulpi reset via gpio-modepin or gpio-framework driver */
 	reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 	if (IS_ERR(reset_gpio)) {
@@ -488,6 +479,17 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
 		usleep_range(5000, 10000); /* delay */
 	}

+	/*
+	 * This routes the USB DMA traffic to go through FPD path instead
+	 * of reaching DDR directly. This traffic routing is needed to
+	 * make SMMU and CCI work with USB DMA.
+	 */
+	if (of_dma_is_coherent(dev->of_node) || device_iommu_mapped(dev)) {
+		reg = readl(priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG);
+		reg |= XLNX_USB_TRAFFIC_ROUTE_FPD;
+		writel(reg, priv_data->regs + XLNX_USB_TRAFFIC_ROUTE_CONFIG);
+	}
+
 err:
 	return ret;
 }

  除了自动生成的设备树,需要指定 usb phy 的工作模式以及最大速度,对于 usb3,需要启用lpm(不启用也可以,只不过内核会报warning,强迫症难受)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
&dwc3_0 {
    dr_mode = "host";
	maximum-speed = "high-speed"; /* usb 2.0 */
    snps,usb3_lpm_capable;
};

&dwc3_1 {
    dr_mode = "host";
	maximum-speed = "super-speed"; /* usb 3.0 */
    snps,usb3_lpm_capable;
};

SD 卡调试

  SD 卡主要出现了两个问题。

  第一,SD 卡识别报错Buffer I/O error on dev mmcblk0, logical block 0, async page read,根据论坛的描述,这是一个在 2019.2 就存在的问题,需要在设备树中声明no-1-8-v;,声明后注意 sd 的供电电压。

  第一,SD 卡无法写入,这是因为 zynqmp 中似乎默认设置了 SD 的写保护模式,需要在设备树中声明不启用。

1
2
3
4
&sdhci0 {
    no-1-8-v;
    disable-wp;
};

DP 调试

  DP 一开始报错Invalid reference clock number,在设备树中修改psgtr,指定 video_clk 以及 dp_aclk 的参考钟,具体需要参考自动生成的设备树以及 IP 核配置。

1
2
3
4
&psgtr {
    clocks = <&video_clk>, <&dp_aclk>;
    clock-names = "ref0", "ref3";
};

  解决上述问题后,内核报错时钟和速率不匹配,并且驱动报错More than allowed devices are using the vpll_int, which is forbidden,参考 zynqmp IP 核的样例工程,修改了 DP 使用的输出时钟,解决了后者报错。通过modetest -M xlnx发现EncodersConnectorsCRTCsPlanes的对应关系错误,并且Connectors的状态是disconnected,示波器查看 dp 的 aux 输出是反的,原因在于 MIO 数量不足,所以 dp 连在了 PL 端,通过 EMIO 连接到 arm,而文档中提到了dp_aux_data_oe连接到 EMIO 的极性会反转,这是我一开始忽略的地方,手动取反之后,modetest的测试结果正常。但是此时显示器依旧没有输出。这里就是上文提到的DP LaneGT Lane的对应关系的问题了。

  在调试的过程中,参考其他人的设备树,修改了zynqmp_dpsubdmas,分为vid-layergfx-layer,后续没有测试对显示有没有影响,感兴趣可以删除试试看。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
&zynqmp_dpsub {
    vid-layer {
        dma-names = "vid0", "vid1", "vid2";
        dmas = <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO0>,
            <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO1>,
            <&zynqmp_dpdma ZYNQMP_DPDMA_VIDEO2>;
    };
    gfx-layer {
        dma-names = "gfx0";
        dmas = <&zynqmp_dpdma ZYNQMP_DPDMA_GRAPHICS>;
    };
};

  在解决了硬件电路上接反的问题后,连接显示器后可以正确显示出来。

警告

目前的版本挑显示器,测试的显示器中仅有一台不能正确显示,dp 转 VGA 也可以正常工作。

 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
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index be63b0e19b60..4a2363c66caf 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -958,18 +958,24 @@ static int zynqmp_dp_train(struct zynqmp_dp *dp)
 	zynqmp_dp_write(dp->iomem, ZYNQMP_DP_TX_PHY_CLOCK_FEEDBACK_SETTING,
 			reg);
 	ret = zynqmp_dp_phy_ready(dp);
-	if (ret < 0)
+	if (ret < 0) {
+		dev_err(dp->dev, "DP Phy is not ready\n");
 		return ret;
+	}

 	zynqmp_dp_write(dp->iomem, ZYNQMP_DP_TX_SCRAMBLING_DISABLE, 1);
 	memset(dp->train_set, 0, ARRAY_SIZE(dp->train_set));
 	ret = zynqmp_dp_link_train_cr(dp);
-	if (ret)
+	if (ret) {
+		dev_err(dp->dev, "clock recovery train is done unsuccessfull\n");
 		return ret;
+	}

 	ret = zynqmp_dp_link_train_ce(dp);
-	if (ret)
+	if (ret) {
+		dev_err(dp->dev, "channel equalization train is done unsuccessfull\n");
 		return ret;
+	}

 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET,
 				 DP_TRAINING_PATTERN_DISABLE);

在驱动中添加了上述调试输出后发现,无法工作的显示器会报channel equalization train is done unsuccessfull,目前原因不明,这里具体的报错源头是 aux 通道协商时,返回的信道均衡值不对。

eMMC 调试

eMMC 很顺利,具体调试过程参考

文章有帮到您的话,请我喝杯奶茶吧ヾ(●´∀`●)
支付宝
微信
0%