1.LCD 驱动修改
一般 uboot 中修改驱动基本都是在 xxx.h 和 xxx.c 这两个文件中进行的,xxx 为板子名称,比如 mx6ull_hnor_emmc.h 和 mx6ull_hnor_emmc.c 这两个文件
一般修改 LCD 驱动重点注意以下几点:
①、LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
②、LCD 背光引脚 GPIO 的配置。
③、LCD 配置参数是否正确。
I.MX6U-ALPHA 开发板 LCD 原理图和 NXP 官方 I.MX6ULL 开发板一致,也就是 LCD 的 IO 和背光 IO 都一样的,所以 IO 部分就不用修改了。需要修改第三项 LCD 参数。
使用 cd board/freescale/mx6ull_hnor_emmc 进入mx6ull_hnor_emmc目录,打开mx6ull_hnor_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_NONINTERLACED
799 } } };
示例代码中定义了一个变量 displays,类型为 display_info_t,这个结构体是 LCD信息结构体,其中包括了 LCD 的分辨率,像素格式,LCD 的各个参数等。
display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,定义如下:
17 struct display_info_t {
18 int bus;
19 int addr;
20 int pixfmt;
21 int (*detect)(struct display_info_t const *dev);
22 void (*enable)(struct display_info_t const *dev);
23 struct fb_videomode mode;
24 };
pixfmt 是像素格式,也就是一个像素点是多少位,如果是 RGB565 的话就是 16 位,如果是 888 的话就是 24 位,一般使用 RGB888。结构体 display_info_t 还有个 mode 成员变量,此成员变量也是个结构体,为 fb_videomode,定义在文件 include/linux/fb.h 中,定义如下:
598 struct fb_videomode {
599 const char *name; /* optional */
600 u32 refresh; /* optional */
601 u32 xres;
602 u32 yres;
603 u32 pixclock;
604 u32 left_margin;
605 u32 right_margin;
606 u32 upper_margin;
607 u32 lower_margin;
608 u32 hsync_len;
609 u32 vsync_len;
610 u32 sync;
611 u32 vmode;
612 u32 flag;
613 };
结构体 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,也就是不使用隔行扫描。
正点原子的 7 寸 1024*600 分辨率的屏幕(ATK7016)屏幕要求的像素时钟为 51.2MHz,因此:
pixclock=(1/51200000)*10^12=19531
根据其他的屏幕参数,可以得出 ATK7016 屏幕的配置参数如下:
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 = "TFT7016",
788 .xres = 1024,
789 .yres = 600,
790 .pixclock = 19531,
791 .left_margin = 140,
792 .right_margin = 160,
793 .upper_margin = 20,
794 .lower_margin = 12,
795 .hsync_len = 20,
796 .vsync_len = 3,
797 .sync = 0,
798 .vmode = FB_VMODE_NONINTERLACED
799 } } };
打开 mx6ull_alientek_emmc.h,找到所有如下语句:
panel=TFT43AB
将其改为:
panel=TFT7016
也就是设置 panel 为 TFT7016,panel 的值要与代码中的.name 成员变量的值一致。修改完成以后重新编译一遍 uboot 并烧写到 SD 中启动。
2.7 网络驱动修改
1、I.MX6U-ALPHA 开发板网络简介
I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,正点原子的 I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片。NXP 官方的I.MX6ULL EVK 开发板使用 KSZ8081 这颗 PHY 芯片,正点原子的 I.MX6U-ALPHA 开发板将 ENET1 和 ENET2的 PHY 换成了 LAN8720A。
接下来调整网络驱动,使网络工作正常。
我们要修改 ENET1 网络驱动的话重点就三点:
①、ENET1 复位引脚初始化。
②、LAN8720A 的器件 ID。
③、LAN8720 驱动
关于 ENET2 网络驱动的修改也注意一下三点
①、ENET2 的复位引脚,从上图可以看出,ENET2 的复位引脚 ENET2_RST 接到了
I.MX6ULL 的 SNVS_TAMPER8 上。
②、ENET2 所使用的 PHY 芯片器件地址,从上图可以看出,PHY 器件地址为 0X1。
③、LAN8720 驱动,ENET1 和 ENET2 都使用的 LAN8720,所以驱动肯定是一样的。
2、网络 PHY 地址修改
首先修改 uboot 中的 ENET1 和 ENET2 的 PHY 地址和驱动,打开 mx6ull_hnor_emmc.h这个文件,找到如下代码:
318 #ifdef CONFIG_CMD_NET
319 #define CONFIG_CMD_PING
320 #define CONFIG_CMD_DHCP
321 #define CONFIG_CMD_MII
322 #define CONFIG_FEC_MXC
323 #define CONFIG_MII
324 #define CONFIG_FEC_ENET_DEV 1
325
326 #if (CONFIG_FEC_ENET_DEV == 0)
327 #define IMX_FEC_BASE ENET_BASE_ADDR
328 #define CONFIG_FEC_MXC_PHYADDR 0x2
329 #define CONFIG_FEC_XCV_TYPE RMII
330 #elif (CONFIG_FEC_ENET_DEV == 1)
331 #define IMX_FEC_BASE ENET2_BASE_ADDR
332 #define CONFIG_FEC_MXC_PHYADDR 0x1
333 #define CONFIG_FEC_XCV_TYPE RMII
334 #endif
335 #define CONFIG_ETHPRIME "FEC"
336
337 #define CONFIG_PHYLIB
338 #define CONFIG_PHY_MICREL
339 #endif
324 行的宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择ENET2。第 328 行为 ENET1 的 PHY 地址,默认是 0X2,第 332行为 ENET2 的 PHY 地址,默认为 0x1。根据前面的分析可知,正点原子的 I.MX6U-ALPHA 开发板 ENET1 的 PHY 地址为0X0,ENET2 的 PHY 地址为 0X1,所以需要将第 328行的宏 CONFIG_FEC_MXC_PHYADDR改为 0x0。
第 338 行定了一个宏 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 地址参数如下所示:
318 #ifdef CONFIG_CMD_NET
319 #define CONFIG_CMD_PING
320 #define CONFIG_CMD_DHCP
321 #define CONFIG_CMD_MII
322 #define CONFIG_FEC_MXC
323 #define CONFIG_MII
324 #define CONFIG_FEC_ENET_DEV 1
325
326 #if (CONFIG_FEC_ENET_DEV == 0)
327 #define IMX_FEC_BASE ENET_BASE_ADDR
328 #define CONFIG_FEC_MXC_PHYADDR 0x0
329 #define CONFIG_FEC_XCV_TYPE RMII
330 #elif (CONFIG_FEC_ENET_DEV == 1)
331 #define IMX_FEC_BASE ENET2_BASE_ADDR
332 #define CONFIG_FEC_MXC_PHYADDR 0x1
333 #define CONFIG_FEC_XCV_TYPE RMII
334 #endif
335 #define CONFIG_ETHPRIME "FEC"
336
337 #define CONFIG_PHYLIB
338 #define CONFIG_PHY_SMSC
339 #endif
3、删除 uboot 中 74LV595 的驱动代码
uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ull_hnor_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,因此我们将示例代码中的代码删除掉,替换为如下所示代码:
91 #define ENET1_RESET IMX_GPIO_NR(5, 7)
92 #define ENET2_RESET IMX_GPIO_NR(5, 8)
ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07,ENET2 的复位引脚连
接到 SNVS_TAMPER8 上,对应 GPIO5_IO08。
继续在 mx6ull_hnor_emmc.c 中找到如下代码:
static iomux_v3_cfg_t const iox_pads[] = {
/* IOX_SDI */
MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_SHCP */
MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_STCP */
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_nOE */
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
同理,上述示例代码是 74LV595 的 IO 配置参数结构体,将其删除掉。继续在mx6ull_alientek_emmc.c 中找到函数 iox74lv_init和iox74lv_set,如下所示:
static void iox74lv_init(void)
{
int i;
gpio_direction_output(IOX_OE, 0);
for (i = 7; i >= 0; i--)
{
gpio_direction_output(IOX_SHCP, 0);
gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
gpio_direction_output(IOX_STCP, 0);
udelay(500);
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
for (i = 7; i >= 0; i--)
{
gpio_direction_output(IOX_SHCP, 0);
gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
gpio_direction_output(IOX_STCP, 0);
udelay(500);
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
};
void iox74lv_set(int index)
{
int i;
for (i = 7; i >= 0; i--)
{
gpio_direction_output(IOX_SHCP, 0);
if (i == index)
gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);
else
gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
gpio_direction_output(IOX_STCP, 0);
udelay(500);
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
for (i = 7; i >= 0; i--)
{
gpio_direction_output(IOX_SHCP, 0);
gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
gpio_direction_output(IOX_STCP, 0);
udelay(500);
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
};
iox74lv_init 函数是 74LV595 的初始化函数,iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!
在 mx6ull_hnor_emmc.c 中找到 board_init 函数,此函数是板子初始化函数,会被board_init_r 调用,board_init 函数内容如下:
int board_init(void)
{
/* Address of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
iox74lv_init();
#ifdef CONFIG_SYS_I2C_MXC
setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
#endif
#ifdef CONFIG_FEC_MXC
setup_fec(CONFIG_FEC_ENET_DEV);
#endif
#ifdef CONFIG_USB_EHCI_MX6
setup_usb();
#endif
#ifdef CONFIG_FSL_QSPI
board_qspi_init();
#endif
#ifdef CONFIG_NAND_MXS
setup_gpmi_nand();
#endif
return 0;
}
board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。至此,mx6ull_znn_emmc.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。