linux-----uboot和kernel移植

目录

1.uboot移植:

1.1 在U-Boot中添加自己的开发板

1.2 添加开发板默认配置文件

1.3 添加开发板对应的头文件

1.4 添加开发板对应的板级文件夹

1.4.1 修改 mx6ull_alientek_emmc 目录下的 Makefile 文件

1.4.2 修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件

1.4.3 修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件

1.4.4 修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件

1.5 使用新添加的板子配置编译 uboot

1.6.1 I.MX6U-ALPHA 开发板网络简介

1.6.2 网络 PHY 地址修改

1.6.3 删除 uboot 中 74LV595 的驱动代码

1.6.4 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动

1.7 其他需要修改的地方

2. Linux内核移植:

2.1 在 Linux 中添加自己的开发板

2.2 添加开发板默认配置文件

2.3 添加开发板对应的设备树文件

2.4 编译测试

2.5 修改网络驱动

2.5.1 修改 LAN8720 的复位引脚驱动

2.5.2 修改 LAN8720A 的 PHY 地址

2.5.3 修改 fec_main.c 文件

2.5.4 配置 Linux 内核,使能 LAN8720 驱动

2.5.5 修改 smsc.c 文件

2.5.6 网络驱动测试

2.6 保存修改后的图形化配置文件

通过图形界面保存配置文件

2.7 Linux 内核的移植步骤大致如下:


1.uboot移植:

1.1 在U-Boot中添加自己的开发板

在U-Boot中添加自己的开发板NXP官方uboot中默认都是 NXP 自己的开发板,虽说我们可以直接在官方的开发板上直接修改,使uboot可以完整的运行在我们的板子上。但是从学习的角度来讲,这样我们就不能了解到uboot是如何添加新平台的。接下来我们就参考NXP官方的I.MX6ULL EVK 开发板学习如何在uboot中添加我们的开发板或者开发平台。

1.2 添加开发板默认配置文件

先在 configs 目录下创建默认配置文件,复制 mx6ull_14x14_evk_emmc_defconfig,然后重命名为mx6ull_alientek_emmc_defconfig,命令如下:

cd configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig

然后将文件 mx6ull_alientek_emmc_defconfig 中的内容改成下面的:

CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y

 可以看出,mx6ull_alientek_emmc_defconfig 基本和 mx6ull_14x14_evk_emmc_defconfig中的内容一样,只是第1行和第4行做了修改

1.3 添加开发板对应的头文件

在目录 include/configs 下添加I.MX6ULL-ALPHA开发板对应的头文件,复制 include/configs/mx6ullevk.h,并重命名为 mx6ull_alientek_emmc.h,命令如下:

cp include/configs/mx6ullevk.h mx6ull_alientek_emmc.h

 拷贝完成以后将:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

改为:

​#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
#define __MX6ULL_ALIENTEK_EMMC_CONFIG_H​

mx6ull_alientek_emmc.h 里面有很多宏定义,这些宏定义基本用于配置 uboot,也有一些 I.MX6ULL 的配置项目。如果我们自己要想使能或者禁止 uboot 的某些功能,那就在 mx6ull_alientek_emmc.h 里面做修改即可。

1.4 添加开发板对应的板级文件夹

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.4.1 修改 mx6ull_alientek_emmc 目录下的 Makefile 文件

mx6ull_alientek_emmc 下的 Makefile 文件内容改为如下所示:

# (C) Copyright 2015 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#

obj-y := mx6ull_alientek_emmc.o

extra-$(CONFIG_USE_PLUGIN) := plugin.bin
$(obj)/plugin.bin: $(obj)/plugin.o
$(OBJCOPY) -O binary --gap-fill 0xff $< $@

重点是第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c这个文件。

1.4.2 修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件

imximage.cfg 中的下面一句:

PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000

改为:

PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000

1.4.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

1.4.4 修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件

修改 MAINTAINERS 文件,修改后的内容如下:

MX6ULL_ALIENTEK_EMMC BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_alientek_emmc/
F: include/configs/mx6ull_alientek_emmc.h

到此为止,I.MX6U-ALPHA 开发板就已经添加到 uboot 中了,接下来就是编译这个新添加的开发板。

1.5 使用新添加的板子配置编译 uboot

在 uboot 根目录下输入如下命令进行编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihfmx6ull_alientek__emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

1.6 网络驱动修改

1.6.1 I.MX6U-ALPHA 开发板网络简介

I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。

I.MX6UL/ULL 有两个网络接口 ENET1ENET2,正点原子的 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 开发板基本一样,唯独复位引脚不同。从图可以看出,正点原子 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 进行数据传输。一个 MIDO 接口可以管理 32 个 PHY 芯
片,同一个 MDIO 接口下的这些 PHY 使用不同的器件地址来做区分, MIDO 接口通过不同的器件地址即可访问到相应的 PHY 芯片。 I.MX6U-ALPHA 开发板 ENET1 上连接的 LAN8720A器件地址为 0X0,所示我们要修改 ENET1 网络驱动的话重点就三点:①、 ENET1 复位引脚初始化。
②、 LAN8720A 的器件 ID。
③、 LAN8720 驱动

再来看一下 ENET2 的原理图,如图所示:

 关于 ENET2 网络驱动的修改也注意一下三点:
①、 ENET2 的复位引脚,从图可以看出,ENET2 的复位引脚 ENET2_RST 接到了I.MX6ULL 的 SNVS_TAMPER8上。
②、 ENET2 所使用的 PHY 芯片器件地址,从图 33.2.7.2 可以看出, PHY 器件地址为 0X1。
③、 LAN8720 驱动, ENET1 和 ENET2 都使用的 LAN8720,所以驱动肯定是一样的。

1.6.2 网络 PHY 地址修改

首先修改 uboot 中的 ENET1 ENET2 的 PHY 地址和驱动,打开 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 0x2
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_MICREL
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 公司生产的。所以示例代码 33.2.7.1 有三处要修改:
①、修改 ENET1 网络 PHY 的地址。
②、修改 ENET2 网络 PHY 的地址。
③、使能 SMSC 公司的 PHY 驱动。

修改后的网络 PHY 地址参数如下所示:

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

1.6.3 删除 uboot 中 74LV595 的驱动代码

uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ull_alientek_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)

示例代码中以 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_IO07ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08

继续在 mx6ull_alientek_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,如下所示:

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);
    }

    ......

    /*
    * 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);
    }

    ......

    /*
    * shift register will be output to pins
    */
    gpio_direction_output(IOX_STCP, 1);
};

 iox74lv_init 函数是 74LV595 的初始化函数, iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!

mx6ull_alientek_emmc.c 中找到 board_init 函数,此函数是板子初始化函数,会被board_init_r 调用, board_init 函数内容如下:

int board_init(void)
{
    ......
    imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
    iox74lv_init();
    ......
    return 0;
}

board_init 会调用 imx_iomux_v3_setup_multiple_pads iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。至此, mx6ull_alientek_emmc.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。

1.6.4 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动

mx6ull_alientek_emmc.c 中找到如下所示代码:

640 static iomux_v3_cfg_t const fec1_pads[] = {
641     MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
642     MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
        ......
649     MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
650     MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
651 };
652
653 static iomux_v3_cfg_t const fec2_pads[] = {
654     MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
655     MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
        ......
664     MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
665     MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
666 };

 结构体数组 fec1_pads 和 fec2_padsENET1 ENET2 这两个网口的 IO 配置参数,在这两个数组中添加两个网口的复位 IO 配置参数,完成以后如下所示:

640 static iomux_v3_cfg_t const fec1_pads[] = {
641     MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
642     MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
        ......
649     MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
650     MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
651     MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
652 };
653
654 static iomux_v3_cfg_t const fec2_pads[] = {
655     MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
656     MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
        ......
665     MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
666     MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
667     MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
668 };

 示例代码中,第 651 行和 667 行分别是 ENET1 和 ENET2 的复位 IO 配置参数。继续在文件 mx6ull_alientek_emmc.c 中找到函数 setup_iomux_fec,此函数默认代码如下:

668 static void setup_iomux_fec(int fec_id)
669 {
670     if (fec_id == 0)
671     imx_iomux_v3_setup_multiple_pads(fec1_pads,
672                   ARRAY_SIZE(fec1_pads));
673     else
674     imx_iomux_v3_setup_multiple_pads(fec2_pads,
675                   ARRAY_SIZE(fec2_pads));
676 }

函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO。我们需要在其中添加网络复位 IO 的初始化代码,并且复位一下 PHY 芯片,修改后的 setup_iomux_fec 函数如下:

668 static void setup_iomux_fec(int fec_id)
669 {
670     if (fec_id == 0)
671     {
672
673         imx_iomux_v3_setup_multiple_pads(fec1_pads,
674                       ARRAY_SIZE(fec1_pads));
675
676         gpio_direction_output(ENET1_RESET, 1);
677         gpio_set_value(ENET1_RESET, 0);
678         mdelay(20);
679         gpio_set_value(ENET1_RESET, 1);
680     }
681     else
682     {
683         imx_iomux_v3_setup_multiple_pads(fec2_pads,
684                       ARRAY_SIZE(fec2_pads));
685         gpio_direction_output(ENET2_RESET, 1);
686         gpio_set_value(ENET2_RESET, 0);
687         mdelay(20);
688         gpio_set_value(ENET2_RESET, 1);
689     }
690 }

 示例代码中第 676 行~679 行和第 685 行~688 行分别对应 ENET1 和 ENET2 的复位 IO 初始化,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A,这个硬件复位很重要!否则可能导致 uboot 无法识别 LAN8720A。

大功基本上告成,还差最后一步, uboot 中的 LAN8720A 驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数genphy_update_link,这是个通用 PHY 驱动函数,此函数用于更新 PHY 的连接状态和速度。使用 LAN8720A 的时候需要在此函数中添加一些代码,修改后的函数 genphy_update_link 如下所示:

221 int genphy_update_link(struct phy_device *phydev)
222 {
223     unsigned int mii_reg;
224
225 #ifdef CONFIG_PHY_SMSC
226     static int lan8720_flag = 0;
227     int bmcr_reg = 0;
228     if (lan8720_flag == 0) {
229         bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
230         phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
231         while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {
232             udelay(100);
233         }
234         phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
235         lan8720_flag = 1;
236     }
237 #endif
238
239     /*
240     * Wait if the link is up, and autonegotiation is in progress
241     * (ie - we're capable and it's not done)
242     */
243     mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
        ......
291
292     return 0;
293 }

225 行~237 行就是新添加的代码,为条件编译代码段,只有使用 SMSC 公司的 PHY 这段代码才会执行(目前只测试了 LAN8720A, SMSC 公司其他的芯片还未测试)。第 229 行读取LAN8720A 的 BMCR 寄存器(寄存器地址为 0),此寄存器为 LAN8720A 的配置寄存器,这里先读取此寄存器的默认值并保存起来。 230 行向寄存器 BMCR 寄存器写入 BMCR_RESET(值为
0X8000),因为 BMCR 的 bit15 是软件复位控制位,因此 230 行就是软件复位 LAN8720A,复位完成以后此位会自动清零。第 231~233 行等待 LAN8720A 软件复位完成,也就是判断 BMCR的 bit15 位是否为 1,为 1 的话表示还没有复位完成。第 234 行重新向 BMCR 寄存器写入以前的值,也就是 229 行读出的那个值。

至此网络的复位引脚驱动修改完成,重新编译 uboot。

1.7 其他需要修改的地方

在 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 ALIENTEK EMMC\n");
    return 0;
}

至此 uboot 的驱动部分就修改完成了, uboot 移植也完成了。

2. Linux内核移植:

2.1 在 Linux 中添加自己的开发板

我们就参考 I.MX6ULL EVK 开发板的设置,在 Linux 内核中添加正点原子的 I.MX6U-ALPHA 开发板。

2.2 添加开发板默认配置文件

arch/arm/configs目录下的imx_v7_mfg_defconfig重新复制一份 ,命名为imx_alientek_emmc_defconfig,命令如下:

cd arch/arm/configs
cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig

 以后 imx_alientek_emmc_defconfig 就是正点原子的 EMMC 版开发板默认配置文件了。完成以后如图所示:

以后就可以使用如下命令来配置正点原子 EMMC 版开发板对应的 Linux 内核了:

make imx_alientek_emmc_defconfig

2.3 添加开发板对应的设备树文件

添加适合正点原子 EMMC 版开发板的设备树文件,进入目录 arch/arm/boot/dts 中,复制一份 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alientek-emmc.dts,命令如下:

cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-alientek-emmc.dts

.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件。imx6ull-alientek-emmc.dts创建好以后我们还需要修改文件 arch/arm/boot/dts/Makefile , 找到 “ dtb-$(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-alientek-emmc.dtb” ,如下所示:

400 dtb-$(CONFIG_SOC_IMX6ULL) += \
401     imx6ull-14x14-ddr3-arm2.dtb \
402     imx6ull-14x14-ddr3-arm2-adc.dtb \
403     imx6ull-14x14-ddr3-arm2-cs42888.dtb \
404     imx6ull-14x14-ddr3-arm2-ecspi.dtb \
405     imx6ull-14x14-ddr3-arm2-emmc.dtb \
406     imx6ull-14x14-ddr3-arm2-epdc.dtb \
407     imx6ull-14x14-ddr3-arm2-flexcan2.dtb \
408     imx6ull-14x14-ddr3-arm2-gpmi-weim.dtb \
409     imx6ull-14x14-ddr3-arm2-lcdif.dtb \
410     imx6ull-14x14-ddr3-arm2-ldo.dtb \
411     imx6ull-14x14-ddr3-arm2-qspi.dtb \
412     imx6ull-14x14-ddr3-arm2-qspi-all.dtb \
413     imx6ull-14x14-ddr3-arm2-tsc.dtb \
414     imx6ull-14x14-ddr3-arm2-uart2.dtb \
415     imx6ull-14x14-ddr3-arm2-usb.dtb \
416     imx6ull-14x14-ddr3-arm2-wm8958.dtb \
417     imx6ull-14x14-evk.dtb \
418     imx6ull-14x14-evk-btwifi.dtb \
419     imx6ull-14x14-evk-emmc.dtb \
420     imx6ull-14x14-evk-gpmi-weim.dtb \
421     imx6ull-14x14-evk-usb-certi.dtb \
422     imx6ull-alientek-emmc.dtb \
423     imx6ull-9x9-evk.dtb \
424     imx6ull-9x9-evk-btwifi.dtb \
425     imx6ull-9x9-evk-ldo.dtb

 第 422 行为“imx6ull-alientek-emmc.dtb”,这样编译 Linux 的时候就可以从 imx6ull-alientekemmc.dts 编译出 imx6ull-alientek-emmc.dtb 文件了。

2.4 编译测试

经过前面两个小节,Linux内核里面已经添加了正点原子 I.MX6UL-ALIPHAEMMC版开发板了 ,接下接编译测试一下 ,按如下顺序输入命令进行编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihfimx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

第 1 行,清理工程。
第 2 行,使用默认配置文件 imx_alientek_emmc_defconfig 来配置 Linux 内核。
第 3 行,打开 Linux 的图形配置界面,如果不需要每次都打开图形配置界面可以删除此行。
第 4 行,编译 Linux。

编译完成以后就会在目录arch/arm/boot下生成 zImage 镜像文件。在 arch/arm/boot/dts 目录下生成 imx6ull-alientek-emmc.dtb文件。将这两个文件拷贝到 tftp 目录下,然后重启开发板,在 uboot 命令模式中使用 tftp 命令下载这两个文件并启动,命令如下:

tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 – 83000000

2.5 修改网络驱动

因为在后面学习 Linux 驱动开发的时候要用到网络调试驱动,所以必须要把网络驱动调试好。在讲解 uboot 移植的时候就已经说过了,正点原子开发板的网络和 NXP 官方的网络硬件上不同,网络 PHY 芯片由 KSZ8081 换为了 LAN8720A,两个网络 PHY 芯片的复位 IO 也不同。所以 Linux 内核自带的网络驱动是驱动不起来 I.MX6U-ALPHA 开发板上的网络的,需要做修改。

2.5.1 修改 LAN8720 的复位引脚驱动

ENET1 复位引脚 ENET1_RST 连接在 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。 ENET2的复位引脚 ENET2_RST 连接在I.MX6ULL 的 SNVS_TAMPER8 上。打开设备树文件 imx6ullalientek-emmc.dts,找到如下代码:

584 pinctrl_spi4: spi4grp {
585              fsl,pins = <
586                 MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
587                 MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
588                 MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
589                 MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000
590             >;
591 };

示例代码中第 588 和 589 行就是初始化 SNVS_TAMPER7 和 SNVS_TAMPER8 这两个引脚的,不过看样子好像是作为了 SPI4 的 IO,这不是我们想要的,所以将 588 和 589 这两行删除掉!删除掉以后继续在 imx6ull-alientek-emmc.dts 中找到如下所示代码:

125 spi4 {
126     compatible = "spi-gpio";
127     pinctrl-names = "default";
128     pinctrl-0 = <&pinctrl_spi4>;
129     pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
        ......
133     cs-gpios = <&gpio5 7 0>;

第 129 行,设置 GPIO5_IO08 为 SPI4 的一个功能引脚(我也不清楚具体作为什么功能用),而 GPIO5_IO08 就是 SNVS_TAMPER8 的 GPIO 功能引脚。

第 133 行,设置 GPIO5_IO07 作为 SPI4 的片选引脚,而 GPIO5_IO07 就是 SNVS_TAMPER7的 GPIO 功能引脚。

现在我们需要 GPIO5_IO07 和 GPIO5_IO08 分别作为 ENET1 和 ENET2 的复位引脚,而不是 SPI4 的什么功能引脚,因此将示例代码 37.4.3.2 中的第 129 行和第 133 行处的代码删除掉!!否则会干扰到网络复位引脚!

继续在 imx6ull-alientek-emmc.dts 中找到如下所示代码:

309 pinctrl_enet1: enet1grp {
310     fsl,pins = <
311         MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
312         MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
313         MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00 0x1b0b0
314         MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01 0x1b0b0
315         MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN 0x1b0b0
316         MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00 0x1b0b0
317         MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01 0x1b0b0
318         MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
319     >;
320 };
321
322 pinctrl_enet2: enet2grp {
323     fsl,pins = <
324         MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
325         MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
326         MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
327         MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
328         MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
329         MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
330         MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
331         MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
332         MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
333         MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
334     >;
335 };

第 309~320 行, pinctrl_enet1 是 ENET1 的 IO 初始化配置。

第 322~335 行, pinctrl_enet2 是 ENET2 的 IO 初始化配置。

根据示例代码,我们需要将 ENET1 的复位 IO 初始化配置添加到 pinctrl_enet1 中,将 ENET2 的复位 IO 初始化配置添加到 pinctrl_enet2 中,添加完成以后的代码如下所示:

309 pinctrl_enet1: enet1grp {
310     fsl,pins = <
311         MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN 0x1b0b0
312         MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER 0x1b0b0
            ...
318         MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b031
319         MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0/* ENET1 RESET */
320     >;
321 };
322
323 pinctrl_enet2: enet2grp {
324     fsl,pins = <
325         MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
326         MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
            ...
334         MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
335         MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0 /* ENET2 RESET */
336     >;
337 };

第 319 行, ENET1 复位引脚 SNVS_TAMPER7 的配置代码。

第 335 行, ENET2 复位引脚 SNVS_TAMPER8 的配置代码。

修改完成以后记得保存一下 imx6ull-alientek-emmc.dts,网络的复位引脚驱动就修改好了。

2.5.2 修改 LAN8720A 的 PHY 地址

在 uboot 移植章节中,我们说过 ENET1 的 LAN8720A 地址为 0x0, ENET2 的 LAN8720A地址为 0x1。在 imx6ull-alientek-emmc.dts 中找到如下代码:

171 &fec1 {
172     pinctrl-names = "default";
173     pinctrl-0 = <&pinctrl_enet1>;
174     phy-mode = "rmii";
175     phy-handle = <&ethphy0>;
176     status = "okay";
177 };
178
179 &fec2 {
180     pinctrl-names = "default";
181     pinctrl-0 = <&pinctrl_enet2>;
182     phy-mode = "rmii";
183     phy-handle = <&ethphy1>;
184     status = "okay";
185
186     mdio {
187         #address-cells = <1>;
188         #size-cells = <0>;
189
190         ethphy0: ethernet-phy@0 {
191             compatible = "ethernet-phy-ieee802.3-c22";
192             reg = <2>;
193         };
194
195         ethphy1: ethernet-phy@1 {
196             compatible = "ethernet-phy-ieee802.3-c22";
197             reg = <1>;
198         };
199     };
200 };

第 171~177 行, ENET1 对应的设备树节点。

第 179~200 行, ENET2 对应的设备树节点。但是第 186~198 行的 mdio 节点描述了 ENET1和 ENET2 的 PHY 地址信息。将示例代码改为如下内容:

171 &fec1 {
172     pinctrl-names = "default";
173     pinctrl-0 = <&pinctrl_enet1>;
174     phy-mode = "rmii";
175     phy-handle = <&ethphy0>;
176     phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
177     phy-reset-duration = <26>;
178     status = "okay";
179 };
180
181 &fec2 {
182     pinctrl-names = "default";
183     pinctrl-0 = <&pinctrl_enet2>;
184     phy-mode = "rmii";
185     phy-handle = <&ethphy1>;
186     phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
187     phy-reset-duration = <26>;
188     status = "okay";
189
190     mdio {
191         #address-cells = <1>;
192         #size-cells = <0>;
193
194         ethphy0: ethernet-phy@0 {
195             compatible = "ethernet-phy-ieee802.3-c22";
196             smsc,disable-energy-detect;
197             reg = <0>;
198         };
199
200         ethphy1: ethernet-phy@1 {
201             compatible = "ethernet-phy-ieee802.3-c22";
202             smsc,disable-energy-detect;
203             reg = <1>;
204         };
205     };
206 };

第 176 和 177 行,添加了 ENET1 网络复位引脚所使用的 IO 为 GPIO5_IO07,低电平有效。复位低电平信号持续时间为 26ms。

第 186 和 187 行, ENET2 网络复位引脚所使用的 IO 为 GPIO5_IO08,同样低电平有效,持续时间同样为 26ms。

第 196 和 202 行,“smsc,disable-energy-detect”表明 PHY 芯片是 SMSC 公司的,这样 Linux 内核就会找到 SMSC 公司的 PHY 芯片驱动来驱动 LAN8720A。

第 194 行,注意“ethernet-phy@”后面的数字是 PHY 的地址, ENET1 的 PHY 地址为 0,所以“@”后面是 0(默认为 2)。

第 197 行, reg 的值也表示 PHY 地址, ENET1 的 PHY 地址为 0,所以 reg=0。

第 200 行, ENET2 的 PHY 地址为 1,因此“@”后面为 1。

第 203 行,因为 ENET2 的 PHY 地址为 1,所以 reg=1。

至此, LAN8720A 的 PHY 地址就改好了,保存一下 imx6ull-alientek-emmc.dts 文件。然后使用“make dtbs”命令重新编译一下设备树。

2.5.3 修改 fec_main.c 文件

要 在 I.MX6ULL 上 使 用 LAN8720A , 需 要 修 改 一 下 Linux 内 核 源 码 , 打 drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_probe,在 fec_probe 中加入如下代码:

3438 static int
3439 fec_probe(struct platform_device *pdev)
3440 {
3441     struct fec_enet_private *fep;
3442     struct fec_platform_data *pdata;
3443     struct net_device *ndev;
3444     int i, irq, ret = 0;
3445     struct resource *r;
3446     const struct of_device_id *of_id;
3447     static int dev_id;
3448     struct device_node *np = pdev->dev.of_node, *phy_node;
3449     int num_tx_qs;
3450     int num_rx_qs;
3451
3452     /* 设置 MX6UL_PAD_ENET1_TX_CLK 和 MX6UL_PAD_ENET2_TX_CLK
3453     * 这两个 IO 的复用寄存器的 SION 位为 1。
3454     */
3455     void __iomem *IMX6U_ENET1_TX_CLK;
3456     void __iomem *IMX6U_ENET2_TX_CLK;
3457
3458     IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
3459     writel(0X14, IMX6U_ENET1_TX_CLK);
3460
3461     IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
3462     writel(0X14, IMX6U_ENET2_TX_CLK);
3463
        ......
3656     return ret;
3657 }

 第 3455~3462 就是新加入的代码,如果要在 I.MX6ULL 上使用 LAN8720A 就需要设置ENET1 和 ENET2 的 TX_CLK 引脚复位寄存器的 SION 位为 1。

2.5.4 配置 Linux 内核,使能 LAN8720 驱动

输入命令“make menuconfig”,打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:

-> Device Drivers
  -> Network device support
    -> PHY Device support and infrastructure
      -> Drivers for SMSC PHYs

如图所示:
 

 图中选择将“Drivers for SMSC PHYs”编译到 Linux 内核中,因此“<>”里面变为了“*”。 LAN8720A 是 SMSC 公司出品的,因此勾选这个以后就会编译 LAN8720 驱动,配置好以后退出配置界面,然后重新编译一下 Linux 内核。

2.5.5 修改 smsc.c 文件

在修改 smsc.c 文件之前先说点题外话,那就是我是怎么确定要修改 smsc.c 这个文件的。在写本书之前我并没有修改过 smsc.c 这个文件,都是使能 LAN8720A 驱动以后就直接使用。但是我在测试 NFS 挂载文件系统的时候发现文件系统挂载成功率很低!老是提示 NFS 服务器找不到,三四次就有一次挂载失败!很折磨人。 NFS 挂载就是通过网络来挂载文件系统,这样做的好处就是方便我们后续调试 Linux 驱动。既然老是挂载失败那么可以肯定的是网络驱动有问题,网络驱动分两部分:内部 MAC+外部 PHY,内部 MAC 驱动是由 NXP 提供的,一般不会出问题,否则的话用户早就给 NXP 反馈了。而且我用 NXP 官方的开发板测试网络是一直正常的,但是 NXP 官方的开发板所使用的 PHY 芯片为 KSZ8081。所以只有可能是外部 PHY,也就是LAN8720A 的驱动可能出问题了。鉴于 LAN8720A 有“前车之鉴”,那就是在 uboot 中需要对LAN8720A 进行一次软复位,要设置 LAN8720A 的 BMCR(寄存器地址为 0)寄存器 bit15 为 1。所以我猜测,在 Linux 中也需要对 LAN8720A 进行一次软复位。

首先需要找到 LAN8720A 的驱动文件, LAN8720A 的驱动文件是 drivers/net/phy/smsc.c,在此文件中有个叫做smsc_phy_reset 的函数,看名字都知道这是 SMSC PHY 的复位函数,因此, LAN8720A 肯定也会使用到这个复位函数,此函数内容如下:

60 static int smsc_phy_reset(struct phy_device *phydev)
61 {
62     int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
63     if (rc < 0)
64         return rc;
65
66     /* If the SMSC PHY is in power down mode, then set it
67     * in all capable mode before using it.
68     */
69     if ((rc & MII_LAN83C185_MODE_MASK) ==
MII_LAN83C185_MODE_POWERDOWN) {
70         int timeout = 50000;
71
72         /* set "all capable" mode and reset the phy */
73         rc |= MII_LAN83C185_MODE_ALL;
74         phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
75         phy_write(phydev, MII_BMCR, BMCR_RESET);
76
77         /* wait end of reset (max 500 ms) */
78         do {
79             udelay(10);
80             if (timeout-- == 0)
81                 return -1;
82             rc = phy_read(phydev, MII_BMCR);
83         } while (rc & BMCR_RESET);
84     }
85     return 0;
86 }

第 69 行,只有 PHY 处于 power down 模式的时候第 70~83 行的代码段才会执行。

第 75 行,向 LAN872A0 的 BMCR 寄存器写入 BMCR_RESET,也就是对 LAN8720A 进行软件初始化,所以 smsc_phy_reset 函数会对 LAN8720A 进行软件初始化。

看到没,只有 LAN8720A 处于 power down 模式的时候才会对 LAN8720A 进行软复位,但是我们在 uboot 中已经“唤醒”了 LAN8720A, LAN8720A 也已经工作了,因此它不可能处于power down 模式,进而就没法对 LAN8720A 进行软复位。因此,我们要对 smsc_phy_reset 函数函数进行修改,将复位相关的代码从条件语句中提出来,不管 LAN8720A 有没有工作在 power down 模式下,只要调用 smsc_phy_reset 函数就对 LAN8720A 进行软复位,修改后的smsc_phy_reset 函数内容如下:

60 static int smsc_phy_reset(struct phy_device *phydev)
61 {
62     int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
63     if (rc < 0)
64         return rc;
65
66     /* If the SMSC PHY is in power down mode, then set it
67     * in all capable mode before using it.
68     */
69     if ((rc & MII_LAN83C185_MODE_MASK) ==
MII_LAN83C185_MODE_POWERDOWN) {
70
71         /* set "all capable" mode and reset the phy */
72         rc |= MII_LAN83C185_MODE_ALL;
73         phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
74     }
75
76     phy_write(phydev, MII_BMCR, BMCR_RESET);
77     /* wait end of reset (max 500 ms) */
78     int timeout = 50000;
79     do {
80         udelay(10);
81         if (timeout-- == 0)
82             return -1;
83         rc = phy_read(phydev, MII_BMCR);
84     } while (rc & BMCR_RESET);
85
86     return 0;
87 }

 重点是 76~84 行,我们将软复位代码移出来,这样每次调用 smsc_phy_reset 函数 LAN8720A都会被软复位。修改以后基本上每次通过 NFS 挂载根文件系统都会成功。

2.5.6 网络驱动测试

修改好设备树和 Linux 内核以后重新编译一下,得到新的 zImage 镜像文件和 imx6ullalientek-emmc.dtb 设备树文件,使用网线将 I.MX6U-ALPHA 开发板的两个网口与路由器或者电脑连接起来,最后使用新的文件启动 Linux 内核。启动以后使用“ifconfig”命令查看一下当前活动的网卡有哪些,结果如图所示:

从图可以看出,当前没有活动的网卡。输入命令“ifconfig -a”来查看一下开发板中存在的所有网卡,结果如图所示:
 

图中 can0 和 can1 为 CAN 接口的网卡, eth0 和 eth1 才是网络接口的网卡,其中eth0 对应于 ENET1, eth1 对应于 ENET2。使用如下命令依次打开 eth0 和 eth1 这两个网卡:
 

上述命令配置 eth0 和 eth1 这两个网卡的 IP 地址分别为 192.168.1.251 和 192.168.1.252,注意 IP 地址选择的合理性,一定要和自己的电脑处于同一个网段内,并且没有被其他的设备占用!设置好以后,使用“ping”命令来 ping 一下自己的主机,如果能 ping 通那说明网络驱动修改成功!比如我的 Ubuntu 主机 IP 地址为 192.168.1.250,使用如下命令 ping 一下:
 

可以看出, ping 成功,说明网络驱动修改成功!我们在后面的构建根文件系统和 Linux 驱动开发中就可以使用网络调试代码啦,好嗨森!

2.6 保存修改后的图形化配置文件

在修改网络驱动的时候我们通过图形界面使能了 LAN8720A 的驱动,使能以后会在.config中存在如下代码:

CONFIG_SMSC_PHY=y

打开 drivers/net/phy/Makefile,有如下代码:

11 obj-$(CONFIG_SMSC_PHY) += smsc.o

当 CONFIG_SMSC_PHY=y 的时候就会编译 smsc.c 这个文件, smsc.c 就是 LAN8720A 的驱动文件。但是当我们执行“make clean”清理工程以后.config 文件就会被删除掉,因此我们所有的配置内容都会丢失,结果就是前功尽弃,一“删”回到解放前!所以我们在配置完图形界面以后经过测试没有问题,就必须要保存一下配置文件。保存配置的方法有两个。

通过图形界面保存配置文件

在图形界面中保存配置文件,在图形界面中会有“< Save >”选项,如图所示:

通过键盘的“→”键,移动到“< Save >”选项,然后按下回车键,打开文件名输入对话框,如图所示:
          在图中输入要保存的文件名,可以带路径,一般是相对路径(相对于 Linux 内核源码 根目 录 )。 比如 我们要 将新 的配 置文 件保存 到目 录 arch/arm/configs 下 , 文件 名为imx_alientek_emmc_defconfig,也就是用新的配置文件替换掉老的默认配置文件。那么我们在图中输入“arch/arm/configs/imx_alientek_emmc_defconfig”即可,如图所示:

 设置好文件名以后选择下方的“< Ok >”按钮,保存文件并退出。退出以后再打开imx_alientek_emmc_defconfig 文件,就会在此文件中找到“CONFIG_SMSC_PHY=y”这一行,如图所示:

同样的,使用“make imx_alientek_emmc_defconfig”重新配置 Linux 内核的时候, LAN8720A的驱动就会使能,并被编译进 Linux 镜像文件 zImage 中。

2.7 Linux 内核的移植步骤大致如下:

①、在 Linux 内核中查找可以参考的板子,一般都是半导体厂商自己做的开发板。
②、编译出参考板子对应的 zImage 和.dtb 文件。
③、使用参考板子的 zImage 文件和.dtb 文件在我们所使用的板子上启动 Linux 内核,看能否启动。
④、如果能启动的话就万事大吉,如果不能启动那就悲剧了,需要调试 Linux 内核。不过一般都会参考半导体官方的开发板设计自己的硬件,所以大部分情况下都会启动起来。启动Linux 内核用到的外设不多,一般就 DRAM(Uboot 都初始化好的)和串口。作为终端使用的串口一般都会参考半导体厂商的 Demo 板。
⑤、修改相应的驱动,像 NAND Flash、 EMMC、 SD 卡等驱动官方的 Linux 内核都是已经提供好了,基本不会出问题。重点是网络驱动,因为 Linux 驱动开发一般都要通过网络调试代码,所以一定要确保网络驱动工作正常。如果是处理器内部 MAC+外部 PHY 这种网络方案的话,一般网络驱动都很好处理,因为在 Linux 内核中是有外部 PHY 通用驱动的。只要设置好复位引脚、 PHY 地址信息基本上都可以驱动起来。
⑥、Linux 内核启动以后需要根文件系统,如果没有根文件系统的话肯定会崩溃,所以确定 Linux内核移植成功以后就要开始根文件系统的构建。

-END-


关于更多嵌入式C语言、FreeRTOS、RT-Thread、Linux应用编程、linux驱动等相关知识,关注公众号【嵌入式Linux知识共享】,后续精彩内容及时收看了解。

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值