本篇梳理在uboot中添加自己的开发板,并且进行移植和启动。这里使用的是正点原子的linux教程以及正点原子的开发板,本篇只为梳理,为后续开发整理流程。
简介
在uboot中添加自己的开发板,这里是使用NXP官方imxull-evk开发板进行修改的,首先我们需要添加几个文件>>
1、创建配置文件 mx6ull_xxx_emmc_defconfig
2、添加开发板对应头文件 mx6ull_xxx_emmc.h
3、添加开发板对应的板级文件:文件夹 mx6ull_xxx_emmc
4、修改U-BOOT图形界面文件
5、LCD驱动修改
6、网络驱动修改
7、uboot编译及移植
8、bootcmd和bootargs环境变量
创建配置文件mx6ull_xxx_emmc_defconfig
第一步我们先复制configs目录下面的mx6ull_14x14_env_emmc_defconfig,放到同目录下命名为mx6ull_xxx_emmc_defconfig,后面我们编译需要使用这个配置文件。
修改配置文件内容:
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_xxx_emmc/imximage.cfg"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_XXX_EMMC=y
CONFIG_CMD_GPIO=y
添加开发板对应头文件
复制include/configs/mx6ullevk.h到configs目录下,命名为mx6ull_xxx_emmc.h,修改修改宏定义:
#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H
...
改为
#ifndef __MX6ULLEVK_XXX_EMMC_CONFIG_H
#define __MX6ULLEVK_XXX_EMMC_CONFIG_H
...
该头文件中有很多宏定义用于配置uboot。
添加开发板对应的板级文件
uboot中每个板子都有对应的文件夹来存放板级文件,比如开发板上外设驱动文件等。复制board/freescale/mx6ullevk到freescale文件夹下,命名为mx6ull_xxx_emmc。
修改mx6ull_xxx_emmc.c
进入mx6ull_xxx_emmc文件夹下,将mx6ullevk.c命名为mx6ull_xxx_emmc.c。
修改mx6ull_xxx_emmc文件夹下的Makefile文件:
# (C) Copyright 2015 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y := mx6ullevk.o
extra-$(CONFIG_USE_PLUGIN) := plugin.bin
$(obj)/plugin.bin: $(obj)/plugin.o
$(OBJCOPY) -O binary --gap-fill 0xff $< $@
为
# (C) Copyright 2015 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y := mx6ull_xxx_emmc.o
extra-$(CONFIG_USE_PLUGIN) := plugin.bin
$(obj)/plugin.bin: $(obj)/plugin.o
$(OBJCOPY) -O binary --gap-fill 0xff $< $@
将obj-y修改为mx6ull_xxx_emmc.o,这样就会编译mx6ull_xxx_emmc.c了。
修改imximage.cfg文件
将
PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
改为
PLUGIN board/freescale/mx6ull_xxx_emmc/plugin.bin 0x00907000
修改Kconfig文件
将mx6ull_xxx_emmc目录下的Kconfig改为:
if TARGET_MX6ULL_XXX_EMMC
config SYS_BOARD
default "mx6ull_xxx_emmc"
config SYS_VENDOR
default "freescale"
config SYS_SOC
default "mx6"
config SYS_CONFIG_NAME
default "mx6ull_xxx_emmc"
endif
修改MAINTAINERS文件
修改mx6ull_xxx_emmc文件夹下MAINTAINERS文件:
MX6ULLEVK BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_xxx_emmc/
F: include/configs/mx6ull_xxx_emmc.h
修改U-BOOT图形界面文件
修改 文件arch/arm/cpu/armv7/mx6/Kconfig 如下:
...
config TARGET_MX6ULL_9X9_EVK
bool "Support mx6ull_9x9_evk"
select MX6ULL
select DM
select DM_THERMAL
config TARGET_MX6ULL_ALIENTEK_EMMC
bool "Support mx6ull_xxx_emmc"
select MX6ULL
select DM
select DM_THERMAL
...
source "board/freescale/mx6sxscm/Kconfig"
source "board/freescale/mx6ull_xxx_emmc/Kconfig"
endif
LCD驱动修改
正点原子的LCD所使用的GPIO和NXP官方的开发板一致,背光IO也一致,所以IO部分不需要修改,徐娅ixiugai的只有LCD的配置,这里使用的是4.3寸屏幕,800*480分辨率,修改mx6ull_xxx_emmc.c文件:
...
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
} } };
...
改为:
...
struct display_info_t const displays[] = {{
.bus = MX6UL_LCDIF1_BASE_ADDR,
.addr = 0,
.pixfmt = 24,
.detect = NULL,
.enable = do_enable_parallel_lcd,
.mode = {
.name = "ATK-LCD-4.3-800x480",
.xres = 800,
.yres = 480,
.pixclock = 10119,
.left_margin = 210,
.right_margin = 46,
.upper_margin = 22,
.lower_margin = 23,
.hsync_len = 20,
.vsync_len = 3,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
...
这里定义了类型为display_info_t的变量displays,这个结构体是LCD信息结构体,其中包括了LCD分辨率,像素格式,LCD的各项参数。
pixfmt是像素格式(一个像素点是多少位),如果是RGB565的话就是16,如果是RGB888的话就是24。
变量mode中个成员变量如下:
name:LCD名字,要和环境变量中的panel相等。
xres、yres:LCD X轴和Y轴的像素数量。
pixclock:像素时钟,每个像素时钟周期的长度,单位皮秒。
left_margin:
right_margin:
upper_margin:
lower_,margin:
hsync_len:
vsync_len:
vmode:大多数使用FB_VMODE_NONINTERLACED,也就是不进行隔行扫描。
修改完成后找到mx6ull_xxx_emmc.h文件中的
panel=TFT43AB
改为:
panel=ATK-LCD-4.3-800x480
网络驱动修改
关于网络驱动修改,由于正点原子使用的PHY芯片LAN8720A和NXP官方开发板的PHY芯片KSZ8081不同,这里需要修改的地方比较多:
1、网络PHY地址修改
2、删除uboot中74LV595的驱动代码(官方开发板使用了74LV595扩展IO,正点原子开发板,没有用到)
3、添加开发板复位引脚驱动
4、修改drivers/net/phy.phy.c文件中函数genphy_update_link
网络PHY地址修改
正点原子开发板ENET1的PHY地址是0x0,ENET2的PHY地址是0x1,官方使用的PHY芯片KSZ8081是MICREL生产的,所以使用的是MICREL的驱动,定义宏:
#define CONFIG_PHY_MICREL
现在使用的是LAN8720A,是SMSC公司生产的,定义宏:
#define CONFIG_PHY_SMSC
所以需要修改:
#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
删除uboot中74LV595驱动代码
由于官方开发板使用了74LV595进行IO扩张,74LV595是一款计数器移位寄存器,在正点原子开发板上并未使用,可以在uboot中将涉及的代码删除,一下罗列:
这里打开mx6ull_xxx_emmc.c,
#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)
删除此段代码,ENET1的复位引脚是GPIO_IO07,ENET2的复位引脚是GPIO_IO08,故替换代码:
#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)
删除 static iomux_v3_cfg_t const iox_pads[] 函数
删除 static void iox74lv_init(void)
删除 void iox741v_set(int index)
删除在board_init函数中 imx_iomux_v3_setup_multiple_pads和 iox74lv_init的调用。
添加开发板复位引脚驱动
在mx6ull_xxx_emmc.c中找到网口IO配置参数:
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[] 和static iomux_v3_cfg_t const fec2_pads[] 添加网口复位IO配置参数,如下:
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_TAMPER7__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
在mux6ull_xxx_emmc.c中找到set_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));
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)
}
}
以上代码对应ENET1和ENET2复位引脚初始化,并设置成输出,并且硬件复位LAN8720A。
修改drivers/net/phy.phy.c文件中函数
uboot中关于LAN8720A的驱动有点问题(没试过),打开drivers/net/phy/phy.c,找到函数genphy_update_link,此函数是通用的PHY驱动函数,用于更新PHY的连接状态和速度,在此添加一些代码,修改后如下:
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(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
while( phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0x8000) {
udelay(100);
}
}
#endif
/*
* 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);
...
return 0;
}
以上完成了在uboot中添加自己的开发板!
bootcmd和bootargs环境变量
做完以上工作后我们需要编译uboot并且烧写到SD卡中,启动开发板,在倒计时结束前按下回车进入uboot命令行模式。
我们需要在命令行模式下设置bootcmd和bootargs这两个环境变量。
bootcmd
保存着uboot默认命令,uboot倒计时结束后就会执行bootcmd命令,将linux内核和设备树文件拷贝到DRAM中,然后启动linux内核,我们将zImage和设备树文件放到EMMC当中,然后在EMMC启动内核,设置环境变量:
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-
alientek-emmc.dtb; bootz 80800000 - 83000000;'
bootargs
保存着uboot传递给linux内核的参数,主要分为以下三个参数:
console
用来设置linux终端,可选择串口或者LCD,这里选择使用串口1即/dev/ttymxc0,后面设置波特率。
root
用来设置根文件系统的位置,这里将根文件系统存放在emmc的分区二,参数设定为/dev/mmcblk1p2。
rootfstype
用于设定根文件系统类型:ext、yaffs、jffs、ubifs,如果时ext,此项可以不指定。
下面列出完整的bootargs环境变量的设置:
setenv bootargs ‘console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw’
uboot启动
完成上述工作后就可以重启开发板进行测试了!