3 添加开发板对应的板级文件夹
uboot 中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。 NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 board/freescale 目录下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。复制 mx6ullevk,将其重命名为 mx6ull_alientek_emmc,命令如下:
cd board/freescale/ cp mx6ullevk/ -r mx6ull_alientek_emmc
进 入 mx6ull_alientek_emmc 目 录 中 , 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ull_alientek_emmc.c,命令如下:
cd mx6ull_alientek_emmc mv mx6ullevk.c mx6ull_alientek_emmc.c
我们还需要对 mx6ull_alientek_emmc 目录下的文件做一些修改:
1、修改 mx6ull_alientek_emmc 目录下的 Makefile 文件
将 mx6ull_alientek_emmc 下的 Makefile 文件内容改为如下所示:
vi Makefile
1 # (C) Copyright 2015 Freescale Semiconductor, Inc. 2 # 3 # SPDX-License-Identifier: GPL-2.0+ 4 # 5 6 obj-y := mx6ull_alientek_emmc.o 7 8 extra-$(CONFIG_USE_PLUGIN) := plugin.bin 9 $(obj)/plugin.bin: $(obj)/plugin.o 10 $(OBJCOPY) -O binary --gap-fill 0xff $< $@
重点是第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c这个文件。
2、修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件
将 imximage.cfg 中的下面一句:
PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
改为:
PLUGIN board/freescale/mx6ull_alientek_emmc/plugin.bin 0x00907000
3、修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件
修改 Kconfig 文件,修改后的内容如下:
if TARGET_MX6ULL_ALIENTEK_EMMC config SYS_BOARD default "mx6ull_alientek_emmc" config SYS_VENDOR default "freescale" config SYS_SOC ` default "mx6" config SYS_CONFIG_NAME default "mx6ull_alientek_emmc" endif
4、修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件
修改 MAINTAINERS 文件,修改后的内容如下:
1 MX6ULL_ALIENTEK_EMMC BOARD 2 M: Peng Fan <peng.fan@nxp.com> 3 S: Maintained 4 F: board/freescale/mx6ull_alientek_emmc/ 5 F: include/configs/alientek_mx6ull_emmc.h
4 修改 U-Boot 图形界面配置文件
uboot 是支持图形界面配置,关于 uboot 的图形界面配置下一章会详细的讲解。修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),在 207 行加入如下内容:
vim arch/arm/cpu/armv7/mx6/Kconfig
config TARGET_MX6ULL_ALIENTEK_EMMC bool "Support mx6ull_alientek_emmc" select MX6ULL select DM select DM_THERMAL
在最后一行的 endif 的前一行添加如下内容:
source "board/freescale/mx6ull_alientek_emmc/Kconfig"
到此为止, I.MX6U-ALPHA 开发板就已经添加到 uboot 中了,接下来就是编译这个新添加的开发板。
5 使用新添加的板子配置编译 uboot
在 uboot 根目录下新建一个名为 nxp_uboot_make.sh 的 shell 脚本,在这个 shell 脚本里面输入如下内容:
#!/bin/bash make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
第 3 行我们使用的默认配置文件就是前面新建的 mx6ull_alientek_emmc_defconfig 这个配置文件。给予 mx6ll_alientek_emmc.sh 可执行权限,然后运行脚本来完成编译,命令如下:
chmod 777 mx6ull_alientek_emmc.sh //给予可执行权限,一次即可 ./mx6ull_alientek_emmc.sh //运行脚本编译uboot
等待编译完成, 编译完成以后输入如下命令, 查看一下 添加的mx6ull_alientek_emmc.h 这个头文件有没有被引用。
grep -nR "mx6ull_alientek_emmc.h"
如果有很多文件都引用了mx6ull_alientek_emmc.h 这个头文件,那就说明新板子添加成功
编译完成以后就使用 imxdownload 将新编译出来的 u-boot.bin 烧写到 SD 卡中测试,SecureCRT 输出结果如图 所示:
此时的 Board 还是“MX6ULL 14x14 EVK”,因为我们参考的 NXP官方的 I.MX6ULL 开发板来添加自己的开发板。如果接了 LCD 屏幕的话会发现 LCD 屏幕并没有显示 NXP 的 logo(或显示重叠的logo),而且从图 可以看出此时的网络同样也没识别出来。前面已经说了,默认 uboot 中的 LCD 驱动和网络驱动在正点原子的 I.MX6U-ALPHA 开发板上是有问题的,需要修改。
6 LCD 驱动修改
一般 uboot 中修改驱动基本都是在 xxx.h 和 xxx.c 这两个文件中进行的, xxx 为板子名称,比如 mx6ull_alientek_emmc.h 和 mx6ull_alientek_emmc.c 这两个文件。一般修改 LCD 驱动重点注意以下几点:
①、 LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
②、 LCD 背光引脚 GPIO 的配置。
③、 LCD 配置参数是否正确。正点原子的 I.MX6U-ALPHA 开发板 LCD 原理图和 NXP 官方 I.MX6ULL 开发板一致,也就是 LCD 的 IO 和背光 IO 都一样的,所以 IO 部分就不用修改了。需要修改的之后 LCD 参数,打开文件 mx6ull_alientek_emmc.c,找到如下所示内容:
board/freescale/mx6ull_alientek_emmc/mx6ull_alientek_emmc.c
780 struct display_info_t const displays[] = {{ 781 .bus = MX6UL_LCDIF1_BASE_ADDR, 782 .addr = 0, 783 .pixfmt = 24, 784 .detect = NULL, 785 .enable = do_enable_parallel_lcd, 786 .mode = { 787 .name = "TFT43AB", 788 .xres = 480, 789 .yres = 272, 790 .pixclock = 108695, 791 .left_margin = 8, 792 .right_margin = 4, 793 .upper_margin = 2, 794 .lower_margin = 4, 795 .hsync_len = 41, 796 .vsync_len = 10, 797 .sync = 0, 798 .vmode = FB_VMODE_NONINTERLAC
ED
799 } } };
定义了一个变量 displays,类型为 display_info_t,这个结构体是 LCD信息结构体,其中包括了 LCD 的分辨率,像素格式, LCD 的各个参数等。 display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,定义如下:
struct display_info_t { int bus; int addr; int pixfmt; int (*detect)(struct display_info_t const *dev); void (*enable)(struct display_info_t const *dev); struct fb_videomode mode; };
ixfmt 是像素格式,也就是一个像素点是多少位,如果是 RGB565 的话就是 16 位,如果是 888 的话就是 24 位,一般使用 RGB888。结构体 display_info_t 还有个 mode 成员变量,此成员变量也是个结构体,为 fb_videomode,定义在文件 include/linux/fb.h 中,定义如下:
struct fb_videomode { const char *name; /* optional */ u32 refresh; /* optional */ u32 xres;5 u32 yres; u32 pixclock; u32 left_margin; u32 right_margin; u32 upper_margin; u32 lower_margin; u32 hsync_len; u32 vsync_len; u32 sync; u32 vmode; u32 flag; };
结构体 fb_videomode 里面的成员变量为LCD 的参数,这些成员变量函数如下:
name:LCD 名字,要和环境变量中的 panel 相等。
xres、yres:LCD X 轴和 Y 轴像素数量。
pixclock:像素时钟,每个像素时钟周期的长度,单位为皮秒。
left_margin:HBP,水平同步后肩。
right_margin:HFP,水平同步前肩。
upper_margin:VBP,垂直同步后肩。
lower_margin:VFP,垂直同步前肩。
hsync_len:HSPW,行同步脉宽。
vsync_len:VSPW,垂直同步脉宽。
vmode:大多数使用FB_VMODE_NONINTERLACED,也就是不使用隔行扫描。
可以看出,这些参数和我们第二十四章讲解RGB LCD 的时候参数基本一样,唯一不同的像素时钟 pixclock 的含义不同,
pixclock 像素时钟需要根据自己的LCD屏幕时间参数进行计算,计算公式如下:
pxclk = {[(VSPW+VBP+LINE+VFP) * (HSPW+HBP+HOZVAL+HFP)] * 60} **** (1)
以上参数都在LCD数据手册能找到。
pixclock = (1 / pxclk) * 10^12 (2)
由1,2式即可计算出pixclock的值32285。
780 struct display_info_t const displays[] = {{ 781 .bus = MX6UL_LCDIF1_BASE_ADDR, 782 .addr = 0, 783 .pixfmt = 24, 784 .detect = NULL, 785 .enable = do_enable_parallel_lcd, 786 .mode = { 787 .name = "ATK4384", 788 .xres = 800, 789 .yres = 480, 790 .pixclock = 32285, 791 .left_margin = 88, 792 .right_margin = 40, 793 .upper_margin = 32, 794 .lower_margin = 13, 795 .hsync_len = 48, 796 .vsync_len = 3, 797 .sync = 0, 798 .vmode = FB_VMODE_NONINTERLACED 799 } } };
打开 mx6ull_alientek_emmc.h,找到所有如下语句:
include/configs/mx6ull_alientek_emmc.h
panel=TFT43AB
将其改为
panel=ATK4384
也就是设置 panel 为 ATK4384, panel 的值要与示例代码中的.name 成员变量的值一致。修改完成以后重新编译一遍 uboot 并烧写到 SD 中启动。
重启以后 LCD 驱动一般就会工作正常了, LCD 上回显示 NXP 的 logo。但是有可能会遇到LCD 并没有工作,还是黑屏,这是什么原因呢?在 uboot 命令模式输入“print”来查看环境变量 panel 的值,会发现 panel 的值要是 TFT43AB(或其他的,反正不是 ATK4384),如图 33.2.6.1所示:
print
这是因为之前有将环境变量保存到 EMMC 中, uboot 启动以后会先从 EMMC 中读取环境变量,如果 EMMC 中没有环境变量的话才会使用 mx6ull_alientek_emmc.h 中的默认环境变量。如果 EMMC 中的环境变量 panel 不等于 ATK4384,那么 LCD 显示肯定不正常,我们只需要在uboot 中修改 panel 的值为 ATK4384 即可,在 uboot 的命令模式下输入如下命令:
setenv panel ATK4384 saveenv
上述命令修改环境变量 panel 为 ATK4384,然后保存,重启 uboot,此时 LCD 驱动就工作正常了。如果 LCD 还是没有正常工作的,那就要检查自己哪里有没有改错,或者还有哪里没有修改。
7.网络驱动修改
1、 I.MX6U-ALPHA 开发板网络简介
I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。大家可能听过 DM9000 这个网络芯片,在一些没有内部 MAC 的 CPU 中,比如三星的 2440, 4412 等,就会采用 DM9000 来实现联网功能。 DM9000 提供了一个类似 SRAM 的访问接口,主控 CPU 通过这个接口即可与DM9000 进行通信, DM9000 就是一个 MAC+PHY 芯片。这个方案就相当于外部 MAC+外部PHY,那么 I.MX6U 这样的内部 MAC+PHY 芯片与 DM9000 方案比有什么优势吗?那优势大了去了!首先就是通信效率和速度,一般 SOC 内部的 MAC 是带有一个专用 DMA 的,专门用于处理网络数据包,采用 SRAM 来读写 DM9000 的速度是压根就没法和内部 MAC+外部 PHY 芯片的速度比。采用外部 DM9000 完全是无奈之举,谁让 2440, 4412 这些芯片内部没有以太网外设呢,现在又想用有线网络,没有办法只能找个 DM9000 的方案。从这里也可以看出,三星的 2440、 4412 这些芯片设计之初就不是给工业产品用的,他们是给消费类电子使用的,比如手机、平板等,手机或平板要上网,可以通过 WIFI 或者 4G,我是没有见过哪个手机或者平板上网是要接根网线的。正点原子的 I.MX6U-ALPHA 开发板也可以通过 WIFI 或者 4G 上网,这个是后话了。
I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,正点原子的 I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片。 NXP 官方的I.MX6ULL EVK 开发板使用 KSZ8081 这颗 PHY 芯片, LAN8720A 相比 KSZ8081 具有体积小、外围器件少、价格便宜等优点。直接使用 KSZ8081 固然可以,但是我们在实际的产品中不一定会使用 KSZ8081,有时候为了降低成本会选择其他的 PHY 芯片,这个时候就有个问题:换了PHY 芯片以后网络驱动怎么办?为此,正点原子的 I.MX6U-ALPHA 开发板将 ENET1 和 ENET2的 PHY 换成了 LAN8720A,这样就可以给大家讲解更换 PHY 芯片以后如何调整网络驱动,使网络工作正常。
I.MX6U-ALPHA 开发板 ENET1 的网络原理图如图
所示:
ENET1 的网络 PHY 芯片为 LAN8720A,通过 RMII 接口与 I.MX6ULL 相连,正点原子I.MX6U-ALPHA 开发板的 ENET1 引脚与 NXP 官方的 I.MX6ULL EVK 开发板基本一样,唯独复位引脚不同。从图 33.2.7.1 可以看出,正点原子 I.MX6U-ALPHA 开发板的 ENET1 复位引脚ENET1_RST 接到了 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。
LAN8720A 内部是有寄存器的,I.MX6ULL 会读取 LAN8720 内部寄存器来判断当前的物理链接状态、连接速度(10M 还是 100M)和双工状态(半双工还是全双工)。I.MX6ULL 通过 MDIO接口来读取 PHY 芯片的内部寄存器,MDIO 接口有两个引脚,ENET_MDC 和 ENET_MDIO,ENET_MDC 提供时钟,ENET_MDIO 进行数据传输。一个 MDIO 接口可以管理 32 个 PHY 芯片,同一个 MDIO 接口下的这些 PHY 使用不同的器件地址来做区分,MIDO 接口通过不同的器件地址即可访问到相应的 PHY 芯片。I.MX6U-ALPHA 开发板 ENET1 上连接的 LAN8720A器件地址为 0X0,所示我们要修改ENET1 网络驱动的话重点就三点:
①、ENET1 复位引脚初始化。
②、LAN8720A 的器件 ID。
③、LAN8720 驱动
再来看一下 ENET2 的原理图,如图 所示:
关于ENET2 网络驱动的修改也注意一下三点:
①、ENET2 的复位引脚,从图 33.2.7.2 可以看出,ENET2 的复位引脚 ENET2_RST 接到了
I.MX6ULL 的 SNVS_TAMPER8 上。
②、ENET2 所使用的 PHY 芯片器件地址,从图 33.2.7.2 可以看出,PHY 器件地址为 0X1。
③、LAN8720 驱动,ENET1 和 ENET2 都使用的LAN8720,所以驱动肯定是一样的。
2、网络 PHY 地址修改
首先修改 uboot 中的 ENET1 和 ENET2 的 PHY 地址和驱动,打开 mx6ull_alientek_emmc.h
这个文件,找到如下代码:
vi include/configs/mx6ull_alientek_emmc.h
325 #ifdef CONFIG_CMD_NET 326 #define CONFIG_CMD_PING 327 #define CONFIG_CMD_DHCP 328 #define CONFIG_CMD_MII 329 #define CONFIG_FEC_MXC 330 #define CONFIG_MII 331 #define CONFIG_FEC_ENET_DEV 1 332 333 #if (CONFIG_FEC_ENET_DEV == 0) 334 #define IMX_FEC_BASE ENET_BASE_ADDR 335 #define CONFIG_FEC_MXC_PHYADDR 0x0 336 #define CONFIG_FEC_XCV_TYPE RMII 337 #elif (CONFIG_FEC_ENET_DEV == 1) 338 #define IMX_FEC_BASE ENET2_BASE_ADDR 339 #define CONFIG_FEC_MXC_PHYADDR 0x1 340 #define CONFIG_FEC_XCV_TYPE RMII 341 #endif 342 #define CONFIG_ETHPRIME "FEC" 343 344 #define CONFIG_PHYLIB 345 #define CONFIG_PHY_SMSC 346 #endif
第 331 行的宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择ENET2。第 335 行为 ENET1 的 PHY 地址,默认是 0X2,第 339 行为ENET2 的 PHY 地址,默认为 0x1。根据前面的分析可知,正点原子的 I.MX6U-ALPHA 开发板 ENET1 的 PHY 地址为0X0,ENET2 的 PHY 地址为 0X1,所以需要将第 335 行的宏 CONFIG_FEC_MXC_PHYADDR改为 0x0。
第 345 行定了一个宏 CONFIG_PHY_MICREL,此宏用于使能 uboot 中 Micrel 公司的 PHY驱动,KSZ8081 这颗 PHY 芯片就是 Micrel 公司生产的,不过 Micrel 已经被 Microchip 收购了。如果要使用 LAN8720A,那么就得将 CONFIG_PHY_MICREL 改为 CONFIG_PHY_SMSC,也就是使能 uboot 中的 SMSC 公司中的 PHY 驱动,因为 LAN8720A 就是 SMSC 公司生产的。所以示例代码有三处要修改:
①、修改ENET1 网络 PHY 的地址。
②、修改ENET2 网络 PHY 的地址。
③、使能 SMSC 公司的PHY 驱动。
修改后的网络 PHY 地址参数如下所示:
324 #ifdef CONFIG_CMD_NET 325 #define CONFIG_CMD_PING 326 #define CONFIG_CMD_DHCP 327 #define CONFIG_CMD_MII 328 #define CONFIG_FEC_MXC 329 #define CONFIG_MII 330 #define CONFIG_FEC_ENET_DEV 1 331 332 #if (CONFIG_FEC_ENET_DEV == 0) 333 #define IMX_FEC_BASE ENET_BASE_ADDR 334 #define CONFIG_FEC_MXC_PHYADDR 0x0 335 #define CONFIG_FEC_XCV_TYPE RMII 336 #elif (CONFIG_FEC_ENET_DEV == 1) 337 #define IMX_FEC_BASE ENET2_BASE_ADDR 338 #define CONFIG_FEC_MXC_PHYADDR 0x1 339 #define CONFIG_FEC_XCV_TYPE RMII 340 #endif 341 #define CONFIG_ETHPRIME "FEC" 342 343 #define CONFIG_PHYLIB 344 #define CONFIG_PHY_REALTEK 345 #endif
建议大家将 ENET2 设置为 uboot 的默认网卡!也就是将宏 CONFIG_FEC_ENET_DEV 设置为 1。
3、删除 uboot 中 74LV595 的驱动代码
uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ull_alientek_emmc.c,找到如下代码:
vi board/freescale/mx6ull_alientek_emmc/mx6ull_alientek_emmc.c
91 #define IOX_SDI IMX_GPIO_NR(5, 10) 92 #define IOX_STCP IMX_GPIO_NR(5, 7) 93 #define IOX_SHCP IMX_GPIO_NR(5, 11) 94 #define IOX_OE IMX_GPIO_NR(5, 8)
示例代码 中以 IOX 开头的宏定义是 74LV595 的相关 GPIO,因为 NXP 官方I.MX6ULL EVK 开发板使用 74LV595 来扩展 IO,两个网络的复位引脚就是由 74LV595 来控制的。正点原子的 I.MX6U-ALPHA 开发板并没有使用 74LV595,因此我们将示例代码 中的代码删除掉,替换为如下所示代码:
#define ENET1_RESET IMX_GPIO_NR(5, 7) #define ENET2_RESET IMX_GPIO_NR(5, 8)
ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07, ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08。
继续在 mx6ull_alientek_emmc.c 中找到如下代码:
94 static iomux_v3_cfg_t const iox_pads[] = { 95 /* IOX_SDI */ 96 MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL), 97 /* IOX_SHCP */ 98 MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL), 99 /* IOX_STCP */ 100 MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), 101 /* IOX_nOE */ 102 MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL), 103 };
同理,示例代码是 74LV595 的 IO 配置参数结构体,将其删除掉。继续在mx6ull_alientek_emmc.c 中找到函数 iox74lv_init,如下所示:
153 static void iox74lv_init(void) 154 { 155 int i; 156 157 gpio_direction_output(IOX_OE, 0); 158 159 for (i = 7; i >= 0; i--) { 160 gpio_direction_output(IOX_SHCP, 0); 161 gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]); 162 udelay(500); 163 gpio_direction_output(IOX_SHCP, 1); 164 udelay(500); 165 } 166 167 gpio_direction_output(IOX_STCP, 0); 168 udelay(500); 169 /* 170 * shift register will be output to pins 171 */ 172 gpio_direction_output(IOX_STCP, 1); 173 174 for (i = 7; i >= 0; i--) { 175 gpio_direction_output(IOX_SHCP, 0); 176 gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]); 177 udelay(500); 178 gpio_direction_output(IOX_SHCP, 1); 179 udelay(500); 180 } 181 gpio_direction_output(IOX_STCP, 0); 182 udelay(500); 183 /* 184 * shift register will be output to pins 185 */ 186 gpio_direction_output(IOX_STCP, 1); 187 };
189 void iox74lv_set(int index) 190 { 191 int i; 192 193 for (i = 7; i >= 0; i--) { 194 gpio_direction_output(IOX_SHCP, 0); 195 196 if (i == index) 197 gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]); 198 else 199 gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]); 200 udelay(500); 201 gpio_direction_output(IOX_SHCP, 1); 202 udelay(500); 203 } 204 205 gpio_direction_output(IOX_STCP, 0); 206 udelay(500); 207 /* 208 * shift register will be output to pins 209 */ 210 gpio_direction_output(IOX_STCP, 1); 211 212 for (i = 7; i >= 0; i--) { 213 gpio_direction_output(IOX_SHCP, 0); 214 gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]); 215 udelay(500); 216 gpio_direction_output(IOX_SHCP, 1); 217 udelay(500); 218 } 219 220 gpio_direction_output(IOX_STCP, 0); 221 udelay(500); 222 /* 223 * shift register will be output to pins 224 */ 225 gpio_direction_output(IOX_STCP, 1); 226 };
iox74lv_init 函数是 74LV595 的初始化函数, iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!
在 mx6ull_alientek_emmc.c 中找到 board_init 函数,此函数是板子初始化函数,会被board_init_r 调用, board_init 函数内容如下:
815 int board_init(void) 816 { 817 /* Address of boot parameters */ 818 gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; 819 820 imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads)); 821 822 iox74lv_init(); 823 824 #ifdef CONFIG_SYS_I2C_MXC 825 setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1); 826 #endif 827 828 #ifdef CONFIG_FEC_MXC 829 setup_fec(CONFIG_FEC_ENET_DEV); 830 #endif 831 832 #ifdef CONFIG_USB_EHCI_MX6 833 setup_usb(); 834 #endif 835 836 #ifdef CONFIG_FSL_QSPI 837 board_qspi_init(); 838 #endif 839 840 #ifdef CONFIG_NAND_MXS 841 setup_gpmi_nand(); 842 #endif 843 844 return 0; 845 }
board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。至此, mx6ull_alientek_emmc.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。
4、添加 I.MX6U-ALPHA 开发板网络复位引脚驱动
在 mx6ull_alientek_emmc.c 中找到如下所示代码:
645 static iomux_v3_cfg_t const fec1_pads[] = { 646 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 647 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), 648 MX6_PAD_ENET1_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 649 MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 650 MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 651 MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL), 652 MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 653 MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 654 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 655 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 656 }; 657 658 static iomux_v3_cfg_t const fec2_pads[] = { 659 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 660 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), 661 662 MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 663 MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 664 MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL), 665 MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 666 667 MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 668 MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 669 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 670 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 671 }; 结构体数组 fec1_pads 和 fec2_pads 是 ENET1 和 ENET2 这两个网口的 IO 配置参数,在这两个数组中添加两个网口的复位 IO 配置参数,完成以后如下所示: 645 static iomux_v3_cfg_t const fec1_pads[] = { 646 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 647 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), 648 MX6_PAD_ENET1_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 649 MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 650 MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 651 MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL), 652 MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 653 MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 654 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 655 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 656 MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL), 657 }; 658 659 static iomux_v3_cfg_t const fec2_pads[] = { 660 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL), 661 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL), 662 663 MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 664 MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 665 MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL), 666 MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 667 668 MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL), 669 MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL), 670 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL), 671 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL), 672 MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL), 673 };
示例代码中,第 651 行和 667 行分别是 ENET1 和 ENET2 的复位 IO 配置参数。继续在文件 mx6ull_alientek_emmc.c 中找到函数 setup_iomux_fec,此函数默认代码如下:
675 static void setup_iomux_fec(int fec_id) 676 { 677 if (fec_id == 0) 678 imx_iomux_v3_setup_multiple_pads(fec1_pads, 679 ARRAY_SIZE(fec1_pads)); 680 else 681 imx_iomux_v3_setup_multiple_pads(fec2_pads, 682 ARRAY_SIZE(fec2_pads)); 683 }
函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO。我们需要在其中添加网络复位 IO 的初始化代码,并且复位一下 PHY 芯片,修改后的 setup_iomux_fec 函数如下:
675 static void setup_iomux_fec(int fec_id) 676 { 677 if (fec_id == 0){ 678 imx_iomux_v3_setup_multiple_pads(fec1_pads, 679 ARRAY_SIZE(fec1_pads)); 680 gpio_direction_output(ENET1_RESET, 1); 681 gpio_set_value(ENET1_RESET, 0); 682 mdelay(20); 683 gpio_set_value(ENET1_RESET, 1); 684 }else{ 685 imx_iomux_v3_setup_multiple_pads(fec2_pads, 686 ARRAY_SIZE(fec2_pads)); 687 gpio_direction_output(ENET2_RESET, 1); 688 gpio_set_value(ENET2_RESET, 0); 689 mdelay(20); 690 gpio_set_value(ENET2_RESET, 1); 691 } 692 }
示例代码中第 676 行~679 行和第 685 行~688 行分别对应 ENET1 和 ENET2 的复位 IO 初始化,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A,这个硬件复位很重要!否则可能导致 uboot 无法识别 LAN8720A。
教程中5.不需要!!!!!!!!!!!!!!
5、修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link
8 其他需要修改的地方
在 uboot 启动信息中会有“Board: MX6ULL 14x14 EVK”这一句,也就是说板子名字为“ MX6ULL 14x14 EVK”,要将其改为我们所使用的板子名字,比如“ MX6ULL ALIENTEKEMMC”或者“MX6ULL ALIENTEK NAND”。打开文件 mx6ull_alientek_emmc.c,找到函数checkboard,将其改为如下所示内容:
int checkboard(void){ if (is_mx6ull_9x9_evk()) puts("Board: MX6ULL 9x9 EVK\n"); else puts("Board: MX6ULL ALIENTEK EMMC\n"); return 0; }
修改完成以后重新编译 uboot 并烧写到 SD 卡中验证
结果
至此网络的复位引脚驱动修改完成,重新编译 uboot,然后将 u-boot.bin 烧写到 SD 卡中并启动, uboot 启动信息如图 所示:
5.启动内核
设置开发板为sd卡启动,上电启动uboot,进入uboot命令模式
配置uboot网络信息
setenv ipaddr 192.168.10.101 setenv ethaddr b8:ae:1d:01:00:00 setenv gatewayip 192.168.10.1 setenv netmask 255.255.255.0 setenv serverip 192.168.10.100 saveenv
配置后使用开发板ping serverip,ping通即配置成功
配置环境变量和根文件系统目录
setenv bootargs 'console=tty1 console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/alientek/linux/nfs/rootfs,proto=tcp rw ip=192.168.10.101:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off' saveenv
格式参考:
setenv bootargs ‘console=开发板串口,波特率 root=挂载方式 \nfsroot=虚拟机 IP 地址:文件系统路径,proto=传输协议 读写权限 \ip=开发板 IP 地址:虚拟机 IP 地址:网关地址:子网掩码::开发板网口:off’
注意:
文件系统路径不要错
IP地址等信息不要错
设置环境变量 bootcmd 来挂载 tftp 目录下的内核、设备树文件到开发板内存中。
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000' saveenv
重启开发板即可启动内核: