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)
一, 添加自定义板子
参考文章官方uboot添加自定义板子
备注:
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 = <ðphy0>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
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 = <ðphy1>;
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芯片的通用驱动
参考文章对drivers/net/phy/phy.c 的修改文章来源:https://www.toymoban.com/news/detail-824837.html
烧录测试网卡文章来源地址https://www.toymoban.com/news/detail-824837.html
=> 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
到了这里,关于Linux驱动之系统移植----uboot移植(有设备树版本),完整移植.的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!