当前位置: 代码网 > 服务器>服务器>Linux > Linux驱动之系统移植----uboot移植(有设备树版本),完整移植.

Linux驱动之系统移植----uboot移植(有设备树版本),完整移植.

2024年08月01日 Linux 我要评论
linux驱动uboot移植, 针对网络驱动, phy驱动 设备树的修改

uboot版本:uboot2020.04
开发板:100ask_imx6ull_pro

拿到官方uboot后第一步先编译烧写测试, 查看哪些驱动可用, 哪些不可用.
根据开发板厂商提供的资料:
使用mx6ull_14x14_evk_defconfig配置进行修改
编译完成后将uboot设备树以及uboot.imx烧写到开发板中运行


cpu:   i.mx6ull rev1.1 792 mhz (running at 396 mhz)
cpu:   industrial temperature grade (-40c to 105c) at 40c
reset cause: por
model: i.mx6 ull 14x14 evk board
board: mx6ull 14x14 evk
dram:  512 mib
mmc:   fsl_sdhc: 0, fsl_sdhc: 1
loading environment from mmc... *** warning - bad crc, using default environment

[*]-video link 0 (480 x 272)
        [0] lcdif@21c8000, video
in:    serial
out:   serial
err:   serial
switch to partitions #0, ok
mmc1(part 0) is current device
flash target is mmc:1
net:
error: ethernet@20b4000 address not set.

error: ethernet@20b4000 address not set.

error: ethernet@20b4000 address not set.
fec: can't find phy-handle

error: ethernet@20b4000 address not set.
could not get phy for fec0: addr 2

error: ethernet@20b4000 address not set.
fec: can't find phy-handle

error: ethernet@20b4000 address not set.
could not get phy for fec0: addr 2
no ethernet found.

显然网络不通, phy无法找到, 其次lcd需要关闭(uboot启动阶段非必要驱动lcd)

一, 添加自定义板子

参考文章
备注:
uboot2020的图形界面配置文件在 arch/arm/mach-imx/mx6
全局搜索target_mx6ull_14x14_evk找到的

二, 关闭lcd

在mx6ull_jzy_defconfig文件中

删除 config_dm_video=y

因为在mx6ull_jzy.c文件中有lcd的初始化函数: setup_lcd(void);有个编译选项为config_dm_video, 搜索这个就可以得到是在mx6ull_jzy_defconfig中定义了

三, 在设备树中修改网络驱动


由于开发板更换了官板的phy芯片所以需要修改phy芯片配置
在mx6ull_jzy.c文件中找到网络驱动相关的函数:
static int setup_fec(void)


#ifdef config_fec_mxc
static int setup_fec(void)
{
	struct iomuxc *const iomuxc_regs = (struct iomuxc *)iomuxc_base_addr;
	int ret;

	/*
	 * use 50m anatop loopback ref_clk1 for enet1,
	 * clear gpr1[13], set gpr1[17].
	 */
	clrsetbits_le32(&iomuxc_regs->gpr[1], iomux_gpr1_fec1_mask,
			iomux_gpr1_fec1_clock_mux1_sel_mask);
	/*
	 * use 50m anatop loopback ref_clk2 for enet2,
	 * clear gpr1[14], set gpr1[18].
	 */
	if (!check_module_fused(mx6_module_enet2)) {
		clrsetbits_le32(&iomuxc_regs->gpr[1], iomux_gpr1_fec2_mask,
				iomux_gpr1_fec2_clock_mux1_sel_mask);
	}

	ret = enable_fec_anatop_clock(0, enet_50mhz);
	if (ret)
		return ret;

	if (!check_module_fused(mx6_module_enet2)) {
		ret = enable_fec_anatop_clock(1, enet_50mhz);
		if (ret)
			return ret;
	}

	enable_enet_clk(1);

	return 0;
}

int board_phy_config(struct phy_device *phydev)
{
	phy_write(phydev, mdio_devad_none, 0x1f, 0x8190);

	if (phydev->drv->config)
		phydev->drv->config(phydev);

	return 0;
}
#endif

被config_fec_mxc宏定义包含, 在mx6ull_jzy_defconfig中搜索得到:
config_fec_mxc=y
已经开启.

由于开发板使用了lan8720的phy芯片,
在mx6ull_jzy_defconfig把
config_phy_micrel=y
config_phy_micrel_ksz8xxx=y
这两个删除, 替换成
config_phy_smsc=y

因为在drivers/net/phy/makefile中定义了一系列编译选项

# spdx-license-identifier: gpl-2.0+
#
# (c) copyright 2008
# wolfgang denk, denx software engineering, wd@denx.de.

obj-$(config_bitbangmii) += miiphybb.o
obj-$(config_b53_switch) += b53.o
obj-$(config_mv88e61xx_switch) += mv88e61xx.o
obj-$(config_mv88e6352_switch) += mv88e6352.o

obj-$(config_phylib) += phy.o
obj-$(config_phylib_10g) += generic_10g.o
obj-$(config_phy_aquantia) += aquantia.o
obj-$(config_phy_atheros) += atheros.o
obj-$(config_phy_broadcom) += broadcom.o
obj-$(config_phy_cortina) += cortina.o
obj-$(config_phy_davicom) += davicom.o
obj-$(config_phy_et1011c) += et1011c.o
obj-$(config_phy_lxt) += lxt.o
obj-$(config_phy_marvell) += marvell.o
obj-$(config_phy_micrel_ksz8xxx) += micrel_ksz8xxx.o
obj-$(config_phy_micrel_ksz90x1) += micrel_ksz90x1.o
obj-$(config_phy_meson_gxl) += meson-gxl.o
obj-$(config_phy_natsemi) += natsemi.o
obj-$(config_phy_realtek) += realtek.o
obj-$(config_phy_smsc) += smsc.o
obj-$(config_phy_teranetics) += teranetics.o
obj-$(config_phy_ti) += dp83867.o
obj-$(config_phy_xilinx) += xilinx_phy.o
obj-$(config_phy_xilinx_gmii2rgmii) += xilinx_gmii2rgmii.o
obj-$(config_phy_vitesse) += vitesse.o
obj-$(config_phy_mscc) += mscc.o
obj-$(config_phy_fixed) += fixed.o
obj-$(config_phy_ncsi) += ncsi.o

跳转到smsc.c中发现开发板所用的芯片的定义:

static struct phy_driver lan8710_driver = {
	.name = "smsc lan8710/lan8720",
	.uid = 0x0007c0f0,
	.mask = 0xffff0,
	.features = phy_basic_features,
	.config = &genphy_config_aneg,
	.startup = &genphy_startup,
	.shutdown = &genphy_shutdown,
};

修改设备树

第一步确定phy芯片地址
mx6ull_jzy_defconfig中定义了
config_default_device_tree=“imx6ull-14x14-evk”
使用设备树imx6ull-14x14-evk
打开imx6ull-14x14-evk.dts

#include "imx6ull.dtsi"
#include "imx6ul-14x14-evk.dtsi"
#include "imx6ul-14x14-evk-u-boot.dtsi"

包含了三个dtsi, 全部打开, 并搜索phy关键字
在imx6ul-14x14-evk.dtsi中找到fec1和fec2的描述

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1>;
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@2 {
			reg = <2>;
			micrel,led-mode = <1>;
			clocks = <&clks imx6ul_clk_enet_ref>;
			clock-names = "rmii-ref";
		};

		ethphy1: ethernet-phy@1 {
			reg = <1>;
			micrel,led-mode = <1>;
			clocks = <&clks imx6ul_clk_enet2_ref>;
			clock-names = "rmii-ref";
		};
	};
};

然而其标签是&fec2说明这并不是最初的源头, 我们需要找到对饮的节点的驱动程序, 最好的办法就是fec2的compatible属性的定义
通过追溯所有imx6ull-14x14-evk.dts包含的设备树, 找到imx6ul.dtsi中描述了fec2


			fec2: ethernet@20b4000 {
				compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
				reg = <0x020b4000 0x4000>;
				interrupt-names = "int0", "pps";
				interrupts = <gic_spi 120 irq_type_level_high>,
					     <gic_spi 121 irq_type_level_high>;
				clocks = <&clks imx6ul_clk_enet>,
					 <&clks imx6ul_clk_enet_ahb>,
					 <&clks imx6ul_clk_enet_ptp>,
					 <&clks imx6ul_clk_enet2_ref_125m>,
					 <&clks imx6ul_clk_enet2_ref_125m>;
				clock-names = "ipg", "ahb", "ptp",
					      "enet_clk_ref", "enet_out";
				fsl,num-tx-queues=<1>;
				fsl,num-rx-queues=<1>;
				status = "disabled";
			};

通过搜索 fsl,imx6ul-fec 这个关键字可以找到驱动程序

找到了drivers/net/fec_mxc.c中

static const struct udevice_id fecmxc_ids[] = {
	{ .compatible = "fsl,imx28-fec" },
	{ .compatible = "fsl,imx6q-fec" },
	{ .compatible = "fsl,imx6sl-fec" },
	{ .compatible = "fsl,imx6sx-fec" },
	{ .compatible = "fsl,imx6ul-fec" },
	{ .compatible = "fsl,imx53-fec" },
	{ .compatible = "fsl,imx7d-fec" },
	{ .compatible = "fsl,mvf600-fec" },
	{ .compatible = "fsl,imx8qm-fec" },
	{ }
};

u_boot_driver(fecmxc_gem) = {
	.name	= "fecmxc",
	.id	= uclass_eth,
	.of_match = fecmxc_ids,
	.ofdata_to_platdata = fecmxc_ofdata_to_platdata,
	.probe	= fecmxc_probe,
	.remove	= fecmxc_remove,
	.ops	= &fecmxc_ops,
	.priv_auto_alloc_size = sizeof(struct fec_priv),
	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};

在device_get_phy_addr函数中发现获取phy地址, 读取的是phy-handle属性中的reg的第0个描述

static int device_get_phy_addr(struct udevice *dev)
{
	struct ofnode_phandle_args phandle_args;
	int reg;

	if (dev_read_phandle_with_args(dev, "phy-handle", null, 0, 0,
				       &phandle_args)) {
		debug("failed to find phy-handle");
		return -enodev;
	}

	reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);

	return reg;
}

fec2的reg第0个描述是0x1.无需修改

第二步对phy芯片进行硬复位, 即对复位引脚进行操作
在drivers/net/fec_mxc.c中的fecmxc_probe函数中是有复位函数调用的:

static int fecmxc_probe(struct udevice *dev)
{
...
#if config_is_enabled(dm_gpio)
	fec_gpio_reset(priv);
#endif
...
}

config_is_enabled(dm_gpio)这个宏表示
config_dm_gpio是否使能了

查看fec_gpio_reset(priv);函数

/* fec gpio reset */
static void fec_gpio_reset(struct fec_priv *priv)
{
	debug("fec_gpio_reset: fec_gpio_reset(dev)\n");
	if (dm_gpio_is_valid(&priv->phy_reset_gpio)) {
		dm_gpio_set_value(&priv->phy_reset_gpio, 1);
		mdelay(priv->reset_delay);
		dm_gpio_set_value(&priv->phy_reset_gpio, 0);
		if (priv->reset_post_delay)
			mdelay(priv->reset_post_delay);
	}
}

dm_gpio_is_valid(&priv->phy_reset_gpio)知道 如果phy_reset_gpio是有效的才会进入初始化.
搜索phy_reset_gpio找到:

	ret = gpio_request_by_name(dev, "phy-reset-gpios", 0,
				   &priv->phy_reset_gpio, gpiod_is_out);

原来是通过读取设备树中的phy-reset-gpios这个属性, 因此,需要加这个属性.
回到imx6ul-14x14-evk.dtsi文件,
在&fec2中添加属性phy-reset-gpios = <&gpio5 6 gpio_active_low>;
模仿spi4节点中的pinctrl-assert-gpios = <&gpio5 8 gpio_active_low>;来写的;
初始化的过程还有用到reset_delay这个变量, 搜索得到
priv->reset_delay = dev_read_u32_default(dev, “phy-reset-duration”, 1);
是这么来, 所以要添加phy-reset-duration属性, 值在lan8720芯片手册中说明, 初始化引脚要保持25以上, 因此设置phy-reset-duration = <26>;

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-reset-gpios = <&gpio5 6 gpio_active_low>;
	phy-reset-duration = <26>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@2 {
			reg = <2>;
			micrel,led-mode = <1>;
			clocks = <&clks imx6ul_clk_enet_ref>;
			clock-names = "rmii-ref";
		};

		ethphy1: ethernet-phy@1 {
			reg = <1>;
			micrel,led-mode = <1>;
			clocks = <&clks imx6ul_clk_enet2_ref>;
			clock-names = "rmii-ref";
		};
	};
};

在设备树中加上 gpio5-6的初始化.
找到合适的位置添加:
mx6ull_pad_snvs_tamper6__gpio5_io06 0x79
只要会被调用的地方都可以
pinctrl_enet2是要使用的,必然会被调用.

	pinctrl_enet2: enet2grp {
		fsl,pins = <
			mx6ul_pad_gpio1_io07__enet2_mdc		0x1b0b0
			mx6ul_pad_gpio1_io06__enet2_mdio	0x1b0b0
			mx6ul_pad_enet2_rx_en__enet2_rx_en	0x1b0b0
			mx6ul_pad_enet2_rx_er__enet2_rx_er	0x1b0b0
			mx6ul_pad_enet2_rx_data0__enet2_rdata00	0x1b0b0
			mx6ul_pad_enet2_rx_data1__enet2_rdata01	0x1b0b0
			mx6ul_pad_enet2_tx_en__enet2_tx_en	0x1b0b0
			mx6ul_pad_enet2_tx_data0__enet2_tdata00	0x1b0b0
			mx6ul_pad_enet2_tx_data1__enet2_tdata01	0x1b0b0
			mx6ul_pad_enet2_tx_clk__enet2_ref_clk2	0x4001b031
			mx6ull_pad_snvs_tamper6__gpio5_io06 0x79
		>;
	};

第三步添加phy芯片的软复位驱动代码
软复位就是将lan8720芯片中的复位寄存器设置
打开drivers/net/phy/phy.c b/drivers/net/phy/phy.c
这个是phy芯片的通用驱动

烧录测试网卡

=> setenv eth1addr 00:01:3f:2d:3e:4d
=> setenv ipaddr 192.168.31.178
=> setenv gatewayip 192.168.31.1
=> setenv netmask 255.255.255.0
=> setenv serverip 192.168.31.158
=> saveenv
=> ping 192.168.31.158
ethernet@20b4000 waiting for phy auto negotiation to complete.... done
using ethernet@20b4000 device
host 192.168.31.158 is alive

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com