一、NXP官方Uboot编译与测试
1、将NXP提供的uboot拷贝到ubuntu中。
一个开发板也好运行uboot,DDR或者叫DRAM,串口,SD、EMMC、NAND。板子能工作。
测似结果:
1、uboot能正常启动
2、LCD驱动要根据所使用的屏幕修改。
3、NET初始化失败。
SD卡Formatter V4.0 格式化后,环境变量会被格式化掉。再烧录,
U-Boot 2016.03 (Feb 03 2025 - 19:31:00 +0800)
CPU: Freescale i.MX6ULL rev1.1 69 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 32C
Reset cause: WDOG
Board: MX6ULL 14x14 EVK
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
MMC: FSL_SDHC: 0, FSL_SDHC: 1
*** Warning - bad CRC, using default environment
Display: TFT43AB (480x272)
Video: 480x272x24
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc0 is current device
Net: Board Net Initialization Failed
No ethernet found.
Normal Boot
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
switch to partitions #0, OK
mmc0 is current device
** No partition table - mmc 0 **
** No partition table - mmc 0 **
Booting from net ...
No ethernet found.
No ethernet found.
Bad Linux ARM zImage magic!
=>
环境变量没清是这样
二、移植NXP官方uboot到ALPHA开发板
2.1 添加板子默认配置文件
借鉴NXP官方6ULL EVK开发板,默认配置文件也用他的,
/uboot_m/configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_14x14_my_emmc_defconfig
新建my.sh
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_my_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
修改mx6ull_14x14_my_emmc_defconfig
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_my_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_MY_EMMC=y
CONFIG_CMD_GPIO=y
修改Kconfig
if TARGET_MX6ULL_MY_EMMC
config SYS_BOARD
default “mx6ull_my_emmc”
config SYS_VENDOR
default “freescale”
config SYS_CONFIG_NAME
default “mx6ull_my_emmc”
endif
修改MAINTAINERS
MX6ULLEVK BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_my_emmc/
F: include/configs/mx6ull_my_emmc.h
F: configs/mx6ull_my_emmc_defconfig
2.2添加板子对应的头文件
不同的板子,有一些需要配置的信息,一般是在一个头文件里面配置,每个板子有一个。对于NXP官方的6ULL EVK板子,这个头文件就是
/uboot_m/include/configs
cp mx6ullevk.h mx6ull_my_emmc.h
2.3 添加板子对应的板级文件夹
每个板子都有特有的文件,也叫做板级文件。这里我们将6ULL EVK的板级文件直接拷贝过来。
/uboot_m/board/freescale
cp mx6ullevk/ mx6ull_my_emmc -r
重命名
/uboot_m/board/freescale/mx6ull_my_emmc
mv mx6ullevk.c mx6ull_my_emmc.c
修改Makefile
修改
#ifdef CONFIG_USE_PLUGIN
/*PLUGIN plugin-binary-file IRAM_FREE_START_ADDR*/
PLUGIN board/freescale/mx6ull_my_emmc/plugin.bin 0x00907000
#else
2.4 修改uboot的配置界面
config TARGET_MX6ULL_9X9_EVK
bool "Support mx6ull_9x9_evk"
select MX6ULL
select DM
select DM_THERMAL
config TARGET_MX6ULL_MY_EMMC
bool "Support mx6ull_my_emmc"
select MX6ULL
select DM
select DM_THERMAL
source "board/freescale/mx6dqscm/Kconfig"
source "board/freescale/mx6sxscm/Kconfig"
source "board/freescale/mx6ull_my_emmc/Kconfig"
endif
2.5 使用新添加的板子配置并编译Uboot
编译
./my.sh
mx6ull_my_emm.c编译成.o,mx6ullevk里没有编译
查看.h文件有没有被引用
~/uboot_m/uboot_m$ grep -nR "mx6ull_my_emmc.h"
disk/.part.o.cmd:152: include/configs/mx6ull_my_emmc.h \
disk/.part_dos.o.cmd:134: include/configs/mx6ull_my_emmc.h \
drivers/block/.disk-uclass.o.cmd:133: include/configs/mx6ull_my_emmc.h \
drivers/gpio/.mxc_gpio.o.cmd:142: include/configs/mx6ull_my_emmc.h \
drivers/spi/.spi.o.cmd:134: include/configs/mx6ull_my_emmc.h \
drivers/spi/.fsl_qspi.o.cmd:139: include/configs/mx6ull_my_emmc.h \
至此,说明我们在uboot里成功添加了我们的板子。下载测试下。
2.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,找到如下所示内容:
1、确定LCD IO初始化正确,mx6ull_alientek_emmc.c中的lcd_pads。
#ifdef CONFIG_VIDEO_MXS
static iomux_v3_cfg_t const lcd_pads[] = {
MX6_PAD_LCD_CLK__LCDIF_CLK | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_ENABLE__LCDIF_ENABLE | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_HSYNC__LCDIF_HSYNC | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_VSYNC__LCDIF_VSYNC | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA00__LCDIF_DATA00 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA01__LCDIF_DATA01 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA02__LCDIF_DATA02 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA03__LCDIF_DATA03 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA04__LCDIF_DATA04 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA05__LCDIF_DATA05 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA06__LCDIF_DATA06 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA07__LCDIF_DATA07 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA08__LCDIF_DATA08 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA09__LCDIF_DATA09 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA10__LCDIF_DATA10 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA11__LCDIF_DATA11 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA12__LCDIF_DATA12 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA13__LCDIF_DATA13 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA14__LCDIF_DATA14 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA15__LCDIF_DATA15 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA16__LCDIF_DATA16 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA17__LCDIF_DATA17 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA18__LCDIF_DATA18 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA19__LCDIF_DATA19 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA20__LCDIF_DATA20 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA21__LCDIF_DATA21 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA22__LCDIF_DATA22 | MUX_PAD_CTRL(LCD_PAD_CTRL),
MX6_PAD_LCD_DATA23__LCDIF_DATA23 | MUX_PAD_CTRL(LCD_PAD_CTRL),
/* LCD_RST */
MX6_PAD_SNVS_TAMPER9__GPIO5_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* Use GPIO for Brightness adjustment, duty cycle = period. */
MX6_PAD_GPIO1_IO08__GPIO1_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
改为
/* LCD_RST */
// MX6_PAD_SNVS_TAMPER9__GPIO5_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL),
2、LCD参数,mx6ull_alientek_emmc.c中的displays。fb_videomode表示RGB LCD参数。
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 = 480,
.yres = 272,
.pixclock = 108695,
.left_margin = 8,
.right_margin = 4,
.upper_margin = 2,
.lower_margin = 4,
.hsync_len = 41,
.vsync_len = 10,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
size_t display_count = ARRAY_SIZE(displays);
MX6ULL_LCDIF1_BASE_ADDR (AIPS2_OFF_BASE_ADDR + 0x48000)
AIPS2_OFF_BASE_ADDR (ATZ2_BASE_ADDR + 0x80000)
ATZ2_BASE_ADDR AIPS2_ARB_BASE_ADDR
AIPS2_ARB_BASE_ADDR 0x02100000
MX6ULL_LCDIF1_BASE_ADDR = 0x02100000 + 0x80000 + 0x48000 = 0x21c8000
void do_enable_parallel_lcd(struct display_info_t const *dev)
{
enable_lcdif_clock(dev->bus);
imx_iomux_v3_setup_multiple_pads(lcd_pads, ARRAY_SIZE(lcd_pads));
/* Reset the LCD */
gpio_direction_output(IMX_GPIO_NR(5, 9) , 0);
udelay(500);
gpio_direction_output(IMX_GPIO_NR(5, 9) , 1);
/* Set Brightness to high */
gpio_direction_output(IMX_GPIO_NR(1, 8) , 1);
}
改为
/* Reset the LCD */
// gpio_direction_output(IMX_GPIO_NR(5, 9) , 0);
// udelay(500);
// gpio_direction_output(IMX_GPIO_NR(5, 9) , 1);
修改参数
12 .left_margin = 88, //HBPD
13 .right_margin = 40 //HFPD
14 .upper_margin = 32, //VBPD
15 .lower_margin = 13, //VFBD
16 .hsync_len = 48, //HSPW
17 .vsync_len = 3, //VSPW
结构体 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 的含义不同,以正点原子的 7 寸 1024*600 分辨率的屏幕(ATK7016)为例,屏幕要求的像素时钟为 51.2MHz,因此:
pixclock=(1/51200000)*10^12=19531
struct display_info_t const displays[] = {{
.bus = MX6UL_LCDIF1_BASE_ADDR,
.addr = 0,
.pixfmt = 24,
.detect = NULL,
.enable = do_enable_parallel_lcd,
.mode = {
.name = "TFT4384",
.xres = 800,
.yres = 480,
.pixclock = 19531,
.left_margin = 88,
.right_margin = 40,
.upper_margin = 32,
.lower_margin = 13,
.hsync_len = 48,
.vsync_len = 3,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
Panel环境变量表示LCD ID。
打开 mx6ull_my_emmc.h,找到所有如下语句:
panel=TFT43AB将其改为: panel=TFT4384
SD全部格式化
U-Boot 2016.03 (Feb 04 2025 - 16:19:07 +0800)
CPU: Freescale i.MX6ULL rev1.1 69 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 32C
Reset cause: POR
Board: MX6ULL 14x14 EVK
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
*** Warning - bad CRC, using default environment
Display: TFT4384 (800x480)
Video: 800x480x24
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc0 is current device
Net: Board Net Initialization Failed
No ethernet found.
Normal Boot
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
switch to partitions #0, OK
mmc0 is current device
** No partition table - mmc 0 **
** No partition table - mmc 0 **
Booting from net ...
No ethernet found.
No ethernet found.
Bad Linux ARM zImage magic!
环境变量panel=TFT4384,识别出TFT4384,LCD屏显示NXP图标。
如果 EMMC 中的环境变量 panel 不等于 TFT7016,那么 LCD 显示肯定不正常,我们只需要在uboot 中修改 panel 的值为 TFT7016 即可,在 uboot 的命令模式下输入如下命令:
setenv panel TFT4384
saveenv
2.7 网络驱动修改
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 芯片以后如何调整网络驱动,使网络工作正常。
6ULL网络方案采用内部MAC+外部PHY,6ULL官方开发板使用的PHY芯片就是KSZ8081。正点原子的ALPHA开发板没有使用KSZ8081,我们使用的LAN8720A。因此要修改驱动。
LAN872有一个管理接口,叫做MDIO,两根线,MDIO和MDC,一个MDIO接口可以管理32个PHY芯片。MIDO通过PHY ADDR来确定访问那个PHY芯片。ALPHA开发板ENET1的PHY ADDR是0x0,ENET2的PHY ADDR是0X1.
每个LAN8720都有一个复位引脚,ENET1是SNVS_TAMPER7,ENET2是SNVS_TAMPER8。
LAN8720驱动,因为所有的PHY,其前16个寄存器一模一样,因此uboot里面已经写好了通用PHY驱动,所以理论上不需要修改。
驱动修改
1、修改PHY ADDR
/uboot_m/uboot_m/include/configs/mx6ull_my_emmc.h
#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 0x2
#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_MICREL
#endif
改为
#if (CONFIG_FEC_ENET_DEV == 0)
#define IMX_FEC_BASE ENET_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR 0x0
#define CONFIG_PHY_SMSC
2、删除原有的74LV595相关代码。
// #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)
// 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),
// };
//static void iox74lv_init(void)
//{
//
//}
//void iox74lv_set(int index)
//{
//
//}
3、添加ALPHA开发板的网络复位IO
#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)
修改
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_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | 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),
};
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_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | 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),
};
为
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_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | 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_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | 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),
};
修改
static void setup_iomux_fec(int fec_id)
{
if (fec_id == 0)
imx_iomux_v3_setup_multiple_pads(fec1_pads,
ARRAY_SIZE(fec1_pads));
else
imx_iomux_v3_setup_multiple_pads(fec2_pads,
ARRAY_SIZE(fec2_pads));
}
为
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);
}
}
修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link
修改
/**
* genphy_update_link - update link status in @phydev
* @phydev: target phy_device struct
*
* Description: Update the value in phydev->link to reflect the
* current link value. In order to do this, we need to read
* the status register twice, keeping the second value.
*/
int genphy_update_link(struct phy_device *phydev)
{
unsigned int mii_reg;
/*
* Wait if the link is up, and autonegotiation is in progress
* (ie - we're capable and it's not done)
*/
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
/*
* If we already saw the link up, and it hasn't gone down, then
* we don't need to wait for autoneg again
*/
if (phydev->link && mii_reg & BMSR_LSTATUS)
return 0;
if ((phydev->autoneg == AUTONEG_ENABLE) &&
!(mii_reg & BMSR_ANEGCOMPLETE)) {
int i = 0;
printf("%s Waiting for PHY auto negotiation to complete",
phydev->dev->name);
while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
/*
* Timeout reached ?
*/
if (i > PHY_ANEG_TIMEOUT) {
printf(" TIMEOUT !\n");
phydev->link = 0;
return 0;
}
if (ctrlc()) {
puts("user interrupt!\n");
phydev->link = 0;
return -EINTR;
}
if ((i++ % 500) == 0)
printf(".");
udelay(1000); /* 1 ms */
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
}
printf(" done\n");
phydev->link = 1;
} else {
/* Read the link a second time to clear the latched state */
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
if (mii_reg & BMSR_LSTATUS)
phydev->link = 1;
else
phydev->link = 0;
}
return 0;
}
为
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 2016.03 (Feb 04 2025 - 18:54:14 +0800)
CPU: Freescale i.MX6ULL rev1.1 69 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 38C
Reset cause: POR
Board: MX6ULL 14x14 EVK
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
Display: TFT4384 (800x480)
Video: 800x480x24
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc0 is current device
Net: FEC1
Normal Boot
Hit any key to stop autoboot: 0
改到ETH0
#define CONFIG_FEC_ENET_DEV 0
2.8 其他需要修改的地方
在 uboot 启动信息中会有“Board: MX6ULL 14x14 EVK”这一句,也就是说板子名字为“ MX6ULL 14x14 EVK”,要将其改为我们所使用的板子名字,比如“ MX6ULL ALIENTEK EMMC”或者“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 14x14 EVK\n");
return 0;
}
改为
int checkboard(void)
{
if (is_mx6ull_9x9_evk())
puts("Board: MX6ULL 9x9 EVK\n");
else
puts("Board: MX6ULL MY EMMC\n");
return 0;
}
打印环境变量
U-Boot 2016.03 (Feb 04 2025 - 19:07:16 +0800)
CPU: Freescale i.MX6ULL rev1.1 69 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 43C
Reset cause: POR
Board: MX6ULL MY EMMC
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
Display: TFT4384 (800x480)
Video: 800x480x24
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc0 is current device
Net: FEC1
Normal Boot
Hit any key to stop autoboot: 0
=> print
baudrate=115200
board_name=EVK
board_rev=14X14
boot_fdt=try
bootargs=console=ttymxc0,115200 root=/dev/nfs ip=dhcp nfsroot=:,v3,tcp
bootcmd=run findfdt;mmc dev ${mmcdev};mmc dev ${mmcdev}; if mmc rescan; then if
run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot
; else run netboot; fi; fi; else run netboot; fi
bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};
bootdelay=3
bootscript=echo Running bootscript from mmc ...; source
console=ttymxc0
ethact=FEC1
ethaddr=00:04:9f:04:d2:35
ethprime=FEC
fdt_addr=0x83000000
fdt_file=imx6ull-14x14-evk.dtb
fdt_high=0xffffffff
findfdt=if test $fdt_file = undefined; then if test $board_name = EVK && test $b
oard_rev = 9X9; then setenv fdt_file imx6ull-9x9-evk.dtb; fi; if test $board_nam
e = EVK && test $board_rev = 14X14; then setenv fdt_file imx6ull-14x14-evk.dtb;
fi; if test $fdt_file = undefined; then echo WARNING: Could not determine dtb to
use; fi; fi;
gatewayip=192.168.32.1
get_cmd=dhcp
image=zImage
initrd_addr=0x83800000
initrd_high=0xffffffff
ip_dyn=yes
ipaddr=192.168.32.50
loadaddr=0x80800000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc g_ma
ss_storage.stall=0 g_mass_storage.removable=1 g_mass_storage.file=/fat g_mass_st
orage.ro=1 g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF g_mass
_storage.iSerialNumber="" clk_ignore_unused
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
mmcautodetect=yes
mmcboot=echo Booting from mmc ...; run mmcargs; if test ${boot_fdt} = yes || tes
t ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdt_addr};
else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT;
fi; fi; else bootz; fi;
mmcdev=0
mmcpart=1
mmcroot=/dev/mmcblk0p2 rootwait rw
netargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfs
root=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...; run netargs; if test ${ip_dyn} = yes; then se
tenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${image}; if test ${
boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_
file}; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; the
n bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
netmask=255.255.255.0
panel=TFT4384
script=boot.scr
serverip=192.168.32.100
Environment size: 2657/8188 bytes
=>
在启动 Linux 内核之前我们先来学习两个重要的环境变量 bootcmd 和 bootargs。
三、bootcmd和bootargs环境变量
3.1 bootcmd环境变量
宏CONFIG_BOOTCOMMAND也可以设置bootcmd的值。
"run findfdt;" \
"mmc dev ${mmcdev};" \
"mmc dev ${mmcdev}; if mmc rescan; then " \
"if run loadbootscript; then " \
"run bootscript; " \
"else " \
"if run loadimage; then " \
"run mmcboot; " \
"else run netboot; " \
"fi; " \
"fi; " \
"else run netboot; fi"
Findfdt 设置fdt_file环境变量,也就是dtb文件名字。
mmc dev 1 //切换到emmc
fatload mmc 1:1 80800000 zImage
fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb
booz 80800000 - 83000000
"loadbootscript=" \
"fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
展开以后:fatload mmc 1:1 80800000 boot.scr
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
展开:fatload mmc 1:1 80800000 zImage
"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
展开
fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb
bootz ${loadaddr} - ${fdt_addr};
booz 80800000 - 83000000
3.2 bootargs环境变量
宏CONFIG_BOOTARGS也可以设置bootargs的值
mmcargs=setenv bootargs console=${console},${baudrate} " \
CONFIG_BOOTARGS_CMA_SIZE \
"root=${mmcroot}\0" \
展开以后就是:
bootargs console= ttymxc0,115200 root=/dev/mmcblk1p2
Bootargs是会传递给Linux内核,设置了一些东西
Bootargs环境变量也叫做命令行参数。
四、uboot启动Linux测试
4.1 从EMMC启动
1、首先查看EMMC里面是否有系统,linux镜像zImage和.dtb文件。先将当前设备切换到EMMC:
mmc dev 1 //切换到EMMC
mmcinfo //查看信息
fatls mmc 1:1 //查看EMMC分区1里面的文件
fatload mmc 1:1 80800000 zImage //将zimage下载到DDR的0x80800000处
fatload mmc 1:1 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb //将dtb读取到0X83000000
bootz 80800000 – 83000000 //启动内核
如果内核启动成功,说明uboot支持emmc启动,验证成功。
4.2 从网络启动
\8、系统镜像\1、出厂系统镜像\2、kernel镜像\linux-imx-4.1.15-2.1.0-gb78e551-v1.4
imx6ull-14x14-emmc-4.3-800x480-c.dtb、zImage复制到tftp服务器
先启动下tftp服务器
sudo service tftpd-hpa restart
tftp 80800000 zImage //从tftp服务器下载zimage
tftp 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb //从tftp服务器下载.dtb
bootz 80800000 - 83000000//启动系统
五、uboot DDR初始化
1、裸 机
imxdownload软件下载,会在bin文件头部添加IVT DCD数据,
2、uboot
uboot编译生成u-boot.imx。u-boot.imx已经包含了IVT DCD数据。
u-boot.imx的头部信息是怎么添加的?
u-boot.imx的DCD中的DDR初始化代码该怎么修改。
uboot编译会输出
./tools/mkimage -n board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp -T imximage -e 0x87800000 -d u-boot.bin u-boot.imx
可以看出uboot使用/tools/mkimage工具,向u-boot.bin添加board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp文件信息,从而得到u-boot.imx。
默认只有imximage.cfg文件,imximage.cfg里面保存的就是DCD数据。DDR初始化也此文件里面。
我们要修改DDR初始化代码,就需要修改imximage.cfg文件。此文件默认拷贝的NXP给IMX6ULL EVK开发板写的,默认是给512MB DDR3L写的。