[ARM Linux系统移植] U-Boot LCD 和网络驱动移植
我们在文章 [ARM Linux系统移植] U-Boot 中添加自己的开发板 中,已经介绍了移植自己开发板前的准备工作:“抽离”和组织相关的目录和文件。
本篇文章在此基础上继续修改 LCD 驱动和网络驱动。需要修改 LCD 驱动的原因是 LCD 屏幕的参数会不一致;而修改网络驱动的原因是更换了网络相关芯片,并且引脚也发生了变化。
1. 修改 LCD 驱动
修改 LCD 的驱动,针对当前开发板,因为引脚和官方的 i.Mx 开发板一致,所以只要修改 LCD 的接口参数。LCD 相关的裸机实验已经在文章 [ARM裸机开发] LCD 显示 中介绍过了,在此基础上进行理解没有什么难度。
修改的参数对应 mx6ullevk.c(之前移植的文件叫做 mx6ull_my_emmc.c)文件中的 displays 变量。根据 [ARM裸机开发] LCD 显示 中的参数进行修改,修改内容已经用粗体标出。额外需要注意的地方是,此处像素时钟(即 pixclock 成员)的计算方式为:1 / clock(Hz) * 10^12。
- struct display_info_t const displays[] = { {
- .bus = MX6UL_LCDIF1_BASE_ADDR,
- .addr = 0,
- .pixfmt = 24,
- .detect = NULL,
- .enable = do_enable_parallel_lcd,
- .mode = {
- .name = "TFT43AB",
- .xres = 800,
- .yres = 480,
- .pixclock = 32258,
- .left_margin = 88, //HBPD
- .right_margin = 40, //HFPD
- .upper_margin = 32, //VBPD
- .lower_margin = 13, //VFBD
- .hsync_len = 48, //HSPW
- .vsync_len = 3, //VSPW
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED
- } } };
修改好后,重新编译并烧写。如果屏幕出现了 NXP 的 log 图样,就代表移植成功了。自己这边移植顺利,也没有特别的“坑”需要记录。
2. 修改网络驱动
网络驱动的修改步骤相对 LCD 驱动的修改要繁琐。因为使用的网络芯片和官方开发板不一样,且连接的复位引脚也不一样。我们需要修改的内容包括以下 3 个部分:
1. 芯片对应的器件 ID
2. 新复位引脚的初始化
3. 新芯片驱动
器件 ID 这边按照 I2C 接口的器件 ID 进行理解,并没有深究。
关于新芯片驱动,照理说通用的网络驱动需要是“通用”的:因为这块有标准组织规定,基本功能的寄存器定义需要一致。此处驱动不一致,也就直接按照文档进行修改了,也没有深究。
2.1 修改器件 ID
开发板上有两个网口,对应的物理地址(器件 ID)分为为 0x0 和 0x1。器件 ID 对应的修改在 mx6ull_alientek_emmc.h(之前移植的文件叫做 mx6ull_my_emmc.h) 文件中第 335 和 339 行。同时,因为更换了网络芯片,也把第 345 行跟芯片公司相关的宏进行修改。
- #ifdef CONFIG_CMD_NET
- #define CONFIG_CMD_PING
- #define CONFIG_CMD_DHCP
- #define CONFIG_CMD_MII
- #define CONFIG_FEC_MXC
- #define CONFIG_MII
- #define CONFIG_FEC_ENET_DEV 1
- #if (CONFIG_FEC_ENET_DEV == 0)
- #define IMX_FEC_BASE ENET_BASE_ADDR
- #define CONFIG_FEC_MXC_PHYADDR 0x0
- #define CONFIG_FEC_XCV_TYPE RMII
- #elif (CONFIG_FEC_ENET_DEV == 1)
- #define IMX_FEC_BASE ENET2_BASE_ADDR
- #define CONFIG_FEC_MXC_PHYADDR 0x1
- #define CONFIG_FEC_XCV_TYPE RMII
- #endif
- #define CONFIG_ETHPRIME "FEC"
- #define CONFIG_PHYLIB
- #define CONFIG_PHY_SMSC
- #endif
2.2 新复位引脚的初始化
首先我们删除之前定义的复位引脚,并定义新的复位引脚。
- //#define IOX_SDI IMX_GPIO_NR(5, 10)
- //#define IOX_STCP IMX_GPIO_NR(5, 7)
- //#define IOX_SHCP IMX_GPIO_NR(5, 11)
- //#define IOX_OE IMX_GPIO_NR(5, 8)
- #define ENET1_RESET IMX_GPIO_NR(5, 7)
- #define ENET2_RESET IMX_GPIO_NR(5, 8)
删除了之前的复位引脚定义之后,还会影响到其他使用到它的地方,不一起删除的话就会导致编译错误。还需要删除的地方为:iox_pads 数组、iox74lv_init() 函数、iox74lv_set() 函数以及 board_init() 函数里面对 iox74lv_init() 和 imx_iomux_v3_setup_multiple_pads(iox_pads) 函数的调用。
删除之后,如果编译出错,根据错误提示修改即可。
接着在 fec1_pads 和 fec2_pads 数组中,添加对两个新复位引脚的复用参数。
- static iomux_v3_cfg_t const fec1_pads[] = {
- MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
- MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- ……,
- MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
- };
- static iomux_v3_cfg_t const fec2_pads[] = {
- MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
- MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
- ……,
- MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
- MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
- };
fec1_pads 和 fec2_pads 数组在 setup_iomux_fec() 函数中使用,其中完成了管脚的复用操作。还需要做的是操作复位引脚使硬件复位,相关代码已用粗体标出。
- static void setup_iomux_fec(int fec_id)
- {
- if (fec_id == 0)
- {
- imx_iomux_v3_setup_multiple_pads(fec1_pads,
- ARRAY_SIZE(fec1_pads));
- gpio_direction_output(ENET1_RESET, 1);
- gpio_set_value(ENET1_RESET, 0);
- mdelay(20);
- gpio_set_value(ENET1_RESET, 1);
- }
- else
- {
- imx_iomux_v3_setup_multiple_pads(fec2_pads,
- ARRAY_SIZE(fec2_pads));
- gpio_direction_output(ENET2_RESET, 1);
- gpio_set_value(ENET2_RESET, 0);
- mdelay(20);
- gpio_set_value(ENET2_RESET, 1);
- }
- }
2.3 新芯片驱动
新芯片增加的驱动功能是软件复位,需要修改 phy.c 下的 genphy_update_link() 函数,对应第 225 至 239 行。
- int genphy_update_link(struct phy_device* phydev)
- {
- unsigned int mii_reg;
- #ifdef CONFIG_PHY_SMSC
- static int lan8720_flag = 0;
- int bmcr_reg = 0;
- if (lan8720_flag == 0)
- {
- bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
- phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
- while (phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0x8000)
- {
- udelay(100);
- }
- phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
- lan8720_flag = 1;
- }
- #endif
至此,网络驱动就全部修改完毕。重新编译烧写后,可以发现 u-boot 原先打印的初始化网络失败的 log 消失了。
第一次烧写会遇到 Error: FEC1 address not set. 的错误,原因是 ipaddr 等环境变量没有设置。网络相关的环境变量设置在 [ARM Linux系统移植] U-Boot 网络命令 中有详细说明。在设置 ipaddr 等环境变量之后,之前的错误 log 也消失了。后续还可以使用 ping 命令进行验证,ping 通了就代表网络驱动修改正确。