uboot移植到IMX6ULL平台详细过程

35 篇文章 2 订阅
4 篇文章 1 订阅

uboot移植到IMX6ULL平台详细过程



nxp出厂uboot
https://download.csdn.net/download/weixin_52849254/87663485
移植成功后的uboot
https://download.csdn.net/download/weixin_52849254/87663490

1.解压

tar -vxjf uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2

2 编译 NXP 官方开发板对应的 uboot

找到 NXP 官方 I.MX6ULL EVK 开发板对应的默认配置文件以后就可以编译一下,使用如下命令编译 uboot:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

编译完成以后结果如图

在这里插入图片描述

编译成功。我们在编译的时候需要输入 ARCH 和 CORSS_COMPILE这两个变量的值,这样太麻烦了。我们可以直接在顶层 Makefile 中直接给 ARCH 和CORSS_COMPILE 赋值,修改如图 所示:

 249 ARCH = arm
 250 CROSS_COMPILE = arm-linux-gnueabihf-

在这里插入图片描述

249、 250 行就是直接给 ARCH 和 CROSS_COMPILE 赋值,这样我们就可以使用如下简短的命令来编译 uboot 了

make mx6ull_14x14_evk_emmc_defconfig
make V=1 -j16

如果既不想修改 uboot 的顶层 Makefile,又想编译的时候不用输入那么多,那么就直接创建个 shell 脚本就行了, shell 脚本名为 nxp_uboot_make.sh,然后在 shell 脚本里面输入如下内容:

   #!/bin/bash 
     
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
 make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

在这里插入图片描述

记得给 nxp_uboot_make.sh 这个文件可执行权限,使用 nxp_uboot_make.sh 脚本编译 uboot 的时候每次都会清理一下工程,然后全部重新编译,编译的时候直接执行这个脚本就行了,命令如下:

./nxp_uboot_make.sh

在这里插入图片描述

编译完成以后会生成 u-boot.bin、 u-boot.imx 等文件,但是这些文件是 NXP 官方 I.MX6ULLEVK 开发板。能不能用到正点原子的 I.MX6ULL 开发板上呢?试一下不就知道了!

3 烧写验证与驱动测试

将 imxdownload 软件拷贝到 uboot 源码根目录下,然后使用 imxdownload 软件将 u-boot.bin烧写到 SD 卡中,烧写命令如下:

chmod 777 imxdownload                       //给予 imxdownload 可执行权限
./imxdownload u-boot.bin /dev/sdc        //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 里面

烧写完成以后将 SD 卡插入 I.MX6U-ALPHA 开发板的 TF 卡槽中,最后设置开发板从 SD卡启动。打开 SecureCRT,设置好开发板所使用的串口并打开,复位开发板, SecureCRT 接收到如下图 所示信息:
在这里插入图片描述

uboot 启动正常,虽然我们用的是 NXP 官方 I.MX6ULL 开发板的uboot,但是在正点原子的 I.MX6ULL 开发板上是可以正常启动的。而且 DRAM 识别正确,为512MB,如果用的 NAND 版本的核心版的话 uboot 启动会失败!因为 NAND 核心版用的 256MB的 DRAM。

1、SD 卡和 EMMC 驱动检查

检查一下 SD 卡和EMMC 驱动是否正常,使用命令 mmc list 列出当前的 MMC 设备,结果
在这里插入图片描述

可以看出当前有两个 MMC 设备,检查每个 MMC 设备信息,先检查 MMC 设
备 0,输入如下命令:

mmc dev 0
mmc info

结果如图 所示:
在这里插入图片描述

mmc 设备 0 是 SD 卡, SD 卡容量为 7.4GB,这个和我所使用的SD 卡信息相符,说明 SD 卡驱动正常。再来检查 MMC 设备 1,输入如下命令:
在这里插入图片描述

mmc 设备 1 为 EMMC,容量为 7.3GB,说明 EMMC 驱动也成功,SD 卡和 EMMC 的驱动都没问题。

2、 LCD 驱动检查

如果 uboot 中的 LCD 驱动正确的话,启动 uboot 以后 LCD 上应该会显示出 NXP 的 logo,

在这里插入图片描述

lcd显示内容重叠,有问题,因为 NXP 官方 I.MX6ULL 开发板的屏幕就是 4.3 寸 480x272 分辨率的,所以 uboot 默认 LCD 驱动是 4.3 寸 480x272 分辨率的。如果使用其他分辨率的 LCD 就需要修改 LCD 驱动,这里我使用的是800x480

3、网络驱动

uboot 启动的时候提示“Board Net Initialization Failed”和“No ethernet found.”这两行,说明网络驱动也有问题,正常情况下应该是
在这里插入图片描述

现在没有图中的信息,那更别说 ping 一下 ubuntu 主机了,说明当前 uboot 的网络部驱动也是有问题的,这是因为正点原子开发板的网络芯片复位引脚和 NXP 官方开发板不一样,因此需要修改驱动。
总结一下 NXP 官方 I.MX6ULL EVK 开发板的 uboot 在正点原子 EMMC 版本 I.MX6ULL
开发板上的运行情况:
①、uboot 启动正常,DRAM 识别正确,SD 卡和EMMC 驱动正常。
②、uboot 里面的 LCD 驱动默认是给 4.3 寸 480x272 分辨率的,如果使用的其他分辨率的屏幕需要修改驱动。
③、网络不能工作,识别不出来网络信息,需要修改驱动。
接下来我们要做的工作如下:
①、前面我们一直使用着NXP 官方开发板的 uboot 配置,接下来需要在 uboot 中添加我们自己的开发板,也就是正点原子的 I.MX6ULL 开发板。
②、解决LCD 驱动和网络驱动的问题。

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

NXP 官方 uboot 中默认都是 NXP 自己的开发板,虽说我们可以直接在官方的开发板上直接修改,使 uboot 可以完整的运行在我们的板子上。
接下来我们就参考 NXP 官方的 I.MX6ULL EVK 开发板,学习如何在 uboot 中添加我们的开发板或者开发平台。

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

先在 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 行做了修改。

2.添加开发板对应的头文件

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

cd include/configs/
cp mx6ullevk.h mx6ull_alientek_emmc.h

拷贝完成以后将:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

改为:

#ifndef __ALIENTEK_MX6ULL_EMMC_CONFIG_H
#define __ALIENTEK_MX6ULL_EMMC_CONFIG_H

alientek_mx6ull_emmc.h 里面有很多宏定义,这些宏定义基本用于配置 uboot,也有一些I.MX6ULL 的配置项目。如果我们自己要想使能或者禁止 uboot 的某些功能,那就在alientek_mx6ull_emmc.h 里面做修改即可。 alientek_mx6ull_emmc.h 里面的内容比较多,去掉一些用不到的配置,精简后的内容如下:

/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 *
 * Configuration settings for the Freescale i.MX6UL 14x14 EVK board.
 *
 * SPDX-License-Identifier:    GPL-2.0+
 */
#ifndef __ALIENTEK_MX6ULL_EMMC_CONFIG_H
#define __ALIENTEK_MX6ULL_EMMC_CONFIG_H


#include <asm/arch/imx-regs.h>
#include <linux/sizes.h>
#include "mx6_common.h"
#include <asm/imx-common/gpio.h>

/* uncomment for PLUGIN mode support */
/* #define CONFIG_USE_PLUGIN */

/* uncomment for SECURE mode support */
/* #define CONFIG_SECURE_BOOT */

#ifdef CONFIG_SECURE_BOOT
#ifndef CONFIG_CSF_SIZE
#define CONFIG_CSF_SIZE 0x4000
#endif
#endif

#define is_mx6ull_9x9_evk()    CONFIG_IS_ENABLED(TARGET_MX6ULL_9X9_EVK)

#ifdef CONFIG_TARGET_MX6ULL_9X9_EVK
#define PHYS_SDRAM_SIZE        SZ_256M
#define CONFIG_BOOTARGS_CMA_SIZE   "cma=96M "
#else
#define PHYS_SDRAM_SIZE        SZ_512M
#define CONFIG_BOOTARGS_CMA_SIZE   ""
/* DCDC used on 14x14 EVK, no PMIC */
#undef CONFIG_LDO_BYPASS_CHECK
#endif

/* SPL options */
/* We default not support SPL
 * #define CONFIG_SPL_LIBCOMMON_SUPPORT
 * #define CONFIG_SPL_MMC_SUPPORT
 * #include "imx6_spl.h"
*/

#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG

#define CONFIG_DISPLAY_CPUINFO
#define CONFIG_DISPLAY_BOARDINFO

/* Size of malloc() pool */
#define CONFIG_SYS_MALLOC_LEN        (16 * SZ_1M)

#define CONFIG_BOARD_EARLY_INIT_F
#define CONFIG_BOARD_LATE_INIT

#define CONFIG_MXC_UART
#define CONFIG_MXC_UART_BASE        UART1_BASE

/* MMC Configs */
#ifdef CONFIG_FSL_USDHC
#define CONFIG_SYS_FSL_ESDHC_ADDR    USDHC2_BASE_ADDR

/* NAND pin conflicts with usdhc2 */
#ifdef CONFIG_SYS_USE_NAND
#define CONFIG_SYS_FSL_USDHC_NUM    1
#else
#define CONFIG_SYS_FSL_USDHC_NUM    2
#endif
#endif

/* I2C configs */
#define CONFIG_CMD_I2C
#ifdef CONFIG_CMD_I2C
#define CONFIG_SYS_I2C
#define CONFIG_SYS_I2C_MXC
#define CONFIG_SYS_I2C_MXC_I2C1        /* enable I2C bus 1 */
#define CONFIG_SYS_I2C_MXC_I2C2        /* enable I2C bus 2 */
#define CONFIG_SYS_I2C_SPEED        100000

/* PMIC only for 9X9 EVK */
#define CONFIG_POWER
#define CONFIG_POWER_I2C
#define CONFIG_POWER_PFUZE3000
#define CONFIG_POWER_PFUZE3000_I2C_ADDR  0x08
#endif

#define CONFIG_SYS_MMC_IMG_LOAD_PART    1

#ifdef CONFIG_SYS_BOOT_NAND
#define CONFIG_MFG_NAND_PARTITION "mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) "
#else
#define CONFIG_MFG_NAND_PARTITION ""
#endif

#define CONFIG_MFG_ENV_SETTINGS \
    "mfgtool_args=setenv bootargs console=${console},${baudrate} " \
        CONFIG_BOOTARGS_CMA_SIZE \
        "rdinit=/linuxrc " \
        "g_mass_storage.stall=0 g_mass_storage.removable=1 " \
        "g_mass_storage.file=/fat g_mass_storage.ro=1 " \
        "g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF "\
        "g_mass_storage.iSerialNumber=\"\" "\
        CONFIG_MFG_NAND_PARTITION \
        "clk_ignore_unused "\
        "\0" \
    "initrd_addr=0x83800000\0" \
    "initrd_high=0xffffffff\0" \
    "bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};\0" \

#if defined(CONFIG_SYS_BOOT_NAND)
#define CONFIG_EXTRA_ENV_SETTINGS \
    CONFIG_MFG_ENV_SETTINGS \
    "panel=TFT43AB\0" \
    "fdt_addr=0x83000000\0" \
    "fdt_high=0xffffffff\0"      \
    "console=ttymxc0\0" \
    "bootargs=console=ttymxc0,115200 ubi.mtd=4 "  \
        "root=ubi0:rootfs rootfstype=ubifs "             \
        CONFIG_BOOTARGS_CMA_SIZE \
        "mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs)\0"\
    "bootcmd=nand read ${loadaddr} 0x4000000 0x800000;"\
        "nand read ${fdt_addr} 0x5000000 0x100000;"\
        "bootz ${loadaddr} - ${fdt_addr}\0"

#else
#define CONFIG_EXTRA_ENV_SETTINGS \
    CONFIG_MFG_ENV_SETTINGS \
    "script=boot.scr\0" \
    "image=zImage\0" \
    "console=ttymxc0\0" \
    "fdt_high=0xffffffff\0" \
    "initrd_high=0xffffffff\0" \
    "fdt_file=undefined\0" \
    "fdt_addr=0x83000000\0" \
    "boot_fdt=try\0" \
    "ip_dyn=yes\0" \
    "panel=TFT43AB\0" \
    "mmcdev="__stringify(CONFIG_SYS_MMC_ENV_DEV)"\0" \
    "mmcpart=" __stringify(CONFIG_SYS_MMC_IMG_LOAD_PART) "\0" \
    "mmcroot=" CONFIG_MMCROOT " rootwait rw\0" \
    "mmcautodetect=yes\0" \
    "mmcargs=setenv bootargs console=${console},${baudrate} " \
        CONFIG_BOOTARGS_CMA_SIZE \
        "root=${mmcroot}\0" \
    "loadbootscript=" \
        "fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
    "bootscript=echo Running bootscript from mmc ...; " \
        "source\0" \
    "loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
    "loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
    "mmcboot=echo Booting from mmc ...; " \
        "run mmcargs; " \
        "if test ${boot_fdt} = yes || test ${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;\0" \
    "netargs=setenv bootargs console=${console},${baudrate} " \
        CONFIG_BOOTARGS_CMA_SIZE \
        "root=/dev/nfs " \
    "ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp\0" \
        "netboot=echo Booting from net ...; " \
        "run netargs; " \
        "if test ${ip_dyn} = yes; then " \
            "setenv 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; then " \
                    "bootz; " \
                "else " \
                    "echo WARN: Cannot load the DT; " \
                "fi; " \
            "fi; " \
        "else " \
            "bootz; " \
        "fi;\0" \
        "findfdt="\
            "if test $fdt_file = undefined; then " \
                "if test $board_name = EVK && test $board_rev = 9X9; then " \
                    "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \
                "if test $board_name = 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;\0" \

#define CONFIG_BOOTCOMMAND \
       "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"
#endif

/* Miscellaneous configurable options */
#define CONFIG_CMD_MEMTEST
#define CONFIG_SYS_MEMTEST_START    0x80000000
#define CONFIG_SYS_MEMTEST_END        (CONFIG_SYS_MEMTEST_START + 0x8000000)

#define CONFIG_SYS_LOAD_ADDR        CONFIG_LOADADDR
#define CONFIG_SYS_HZ            1000

#define CONFIG_STACKSIZE        SZ_128K

/* Physical Memory Map */
#define CONFIG_NR_DRAM_BANKS        1
#define PHYS_SDRAM            MMDC0_ARB_BASE_ADDR

#define CONFIG_SYS_SDRAM_BASE        PHYS_SDRAM
#define CONFIG_SYS_INIT_RAM_ADDR    IRAM_BASE_ADDR
#define CONFIG_SYS_INIT_RAM_SIZE    IRAM_SIZE

#define CONFIG_SYS_INIT_SP_OFFSET \
    (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_INIT_SP_ADDR \
    (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)

/* FLASH and environment organization */
#define CONFIG_SYS_NO_FLASH

#ifdef CONFIG_SYS_BOOT_QSPI
#define CONFIG_FSL_QSPI
#define CONFIG_ENV_IS_IN_SPI_FLASH
#elif defined CONFIG_SYS_BOOT_NAND
#define CONFIG_SYS_USE_NAND
#define CONFIG_ENV_IS_IN_NAND
#else
#define CONFIG_FSL_QSPI
#define CONFIG_ENV_IS_IN_MMC
#endif

#define CONFIG_SYS_MMC_ENV_DEV        1   /* USDHC2 */
#define CONFIG_SYS_MMC_ENV_PART        0    /* user area */
#define CONFIG_MMCROOT            "/dev/mmcblk1p2"  /* USDHC2 */

#define CONFIG_CMD_BMODE

#ifdef CONFIG_FSL_QSPI
#define CONFIG_QSPI_BASE        QSPI0_BASE_ADDR
#define CONFIG_QSPI_MEMMAP_BASE        QSPI0_AMBA_BASE

#define CONFIG_CMD_SF
#define CONFIG_SPI_FLASH
#define CONFIG_SPI_FLASH_BAR
#define CONFIG_SF_DEFAULT_BUS        0
#define CONFIG_SF_DEFAULT_CS        0
#define CONFIG_SF_DEFAULT_SPEED    40000000
#define CONFIG_SF_DEFAULT_MODE        SPI_MODE_0
#define CONFIG_SPI_FLASH_STMICRO
#endif

/* NAND stuff */
#ifdef CONFIG_SYS_USE_NAND
#define CONFIG_CMD_NAND
#define CONFIG_CMD_NAND_TRIMFFS

#define CONFIG_NAND_MXS
#define CONFIG_SYS_MAX_NAND_DEVICE    1
#define CONFIG_SYS_NAND_BASE        0x40000000
#define CONFIG_SYS_NAND_5_ADDR_CYCLE
#define CONFIG_SYS_NAND_ONFI_DETECTION

/* DMA stuff, needed for GPMI/MXS NAND support */
#define CONFIG_APBH_DMA
#define CONFIG_APBH_DMA_BURST
#define CONFIG_APBH_DMA_BURST8
#endif

#define CONFIG_ENV_SIZE            SZ_8K
#if defined(CONFIG_ENV_IS_IN_MMC)
#define CONFIG_ENV_OFFSET        (12 * SZ_64K)
#elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
#define CONFIG_ENV_OFFSET        (768 * 1024)
#define CONFIG_ENV_SECT_SIZE        (64 * 1024)
#define CONFIG_ENV_SPI_BUS        CONFIG_SF_DEFAULT_BUS
#define CONFIG_ENV_SPI_CS        CONFIG_SF_DEFAULT_CS
#define CONFIG_ENV_SPI_MODE        CONFIG_SF_DEFAULT_MODE
#define CONFIG_ENV_SPI_MAX_HZ        CONFIG_SF_DEFAULT_SPEED
#elif defined(CONFIG_ENV_IS_IN_NAND)
#undef CONFIG_ENV_SIZE
#define CONFIG_ENV_OFFSET        (60 << 20)
#define CONFIG_ENV_SECT_SIZE        (128 << 10)
#define CONFIG_ENV_SIZE            CONFIG_ENV_SECT_SIZE
#endif


/* USB Configs */
#define CONFIG_CMD_USB
#ifdef CONFIG_CMD_USB
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_MX6
#define CONFIG_USB_STORAGE
#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_MXC_USB_PORTSC  (PORT_PTS_UTMI | PORT_PTS_PTW)
#define CONFIG_MXC_USB_FLAGS   0
#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
#endif

#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

#define CONFIG_IMX_THERMAL

#ifndef CONFIG_SPL_BUILD
#define CONFIG_VIDEO
#ifdef CONFIG_VIDEO
#define CONFIG_CFB_CONSOLE
#define CONFIG_VIDEO_MXS
#define CONFIG_VIDEO_LOGO
#define CONFIG_VIDEO_SW_CURSOR
#define CONFIG_VGA_AS_SINGLE_DEVICE
#define CONFIG_SYS_CONSOLE_IS_IN_ENV
#define CONFIG_SPLASH_SCREEN
#define CONFIG_SPLASH_SCREEN_ALIGN
#define CONFIG_CMD_BMP
#define CONFIG_BMP_16BPP
#define CONFIG_VIDEO_BMP_RLE8
#define CONFIG_VIDEO_BMP_LOGO
#define CONFIG_IMX_VIDEO_SKIP
#endif
#endif

#define CONFIG_IOMUX_LPSR

#if defined(CONFIG_ANDROID_SUPPORT)
#include "mx6ullevk_android.h"
#endif

#endif

可以看出, alientek_mx6ull_emmc.h 文件中基本都是“CONFIG_”开头的宏定义,这也说明 alientek_mx6ull_emmc.h 文件的主要功能就是配置或者裁剪 uboot。如果需要某个功能的话就在里面添加这个功能对应的 CONFIG_XXX 宏即可,如果不需要某个功能的话就删除掉对应的宏即可。我们以示例代码 为例,详细的看一下 alientek_mx6ull_emmc.h中这些宏都是什么功能。

  • 第 14 行,添加了头文件 mx6_common.h,如果在 mx6ull_alientek_emmc.h 中没有发现配置某个功能或命令,但是实际却存在的话,可以到 mx6_common.h 文件里面去找一下。
  • 第 29~39 行,设置 DRAM 的大小,宏 PHYS_SDRAM_SIZE 就是板子上 DRAM 的大小,如果用的NXP 官方的 9X9 EVK 开发板的话DRAM 大小就为 256MB。否则的话默认为 512MB,正点原子的I.MX6U-ALPHA 开发板用的是 512MB DDR3。
  • 第 50 行,定义宏 CONFIG_DISPLAY_CPUINFO,uboot 启动的时候可以输出 CPU 信息。
  • 第 51 行,定义宏 CONFIG_DISPLAY_BOARDINFO,uboot 启动的时候可以输出板子信息。
  • 第 54 行,CONFIG_SYS_MALLOC_LEN 为 malloc 内存池大小,这里设置为 16MB。
  • 第 56 行,定义宏 CONFIG_BOARD_EARLY_INIT_F,这样 board_init_f 函数就会调用board_early_init_f 函数。
  • 第 57 行, 定义宏 CONFIG_BOARD_LATE_INIT ,这样 board_init_r 函数就会调用board_late_init 函数。
  • 第 59、60 行,使能 I.MX6ULL 的串口功能,宏 CONFIG_MXC_UART_BASE 表示串口寄存器基地址, 这里使用的串口 1 , 基地址为 UART1_BASE , UART1_BASE 定义在文件arch/arm/include/asm/arch-mx6/imx-regs.h 中,imx-regs.h 是 I.MX6ULL 寄存器描述文件,根据imx-regs.h 可得到UART1_BASE 的值如下:
UART1_BASE= (ATZ1_BASE_ADDR + 0x20000)
            =AIPS1_ARB_BASE_ADDR + 0x20000
            =0x02000000 + 0x20000
            =0X02020000

查阅 I.MX6ULL 参考手册, UART1 的寄存器基地址正是 0X02020000
在这里插入图片描述

  • 第63、64行, EMMC接在I.MX6ULL的USDHC2上,宏CONFIG_SYS_FSL_ESDHC_ADDR为 EMMC 所使用接口的寄存器基地址,也就是 USDHC2 的基地址。
  • 第 67~72 行,跟 NAND 相关的宏,因为 NAND 和 USDHC2 的引脚冲突,因此如果使用NAND 的只能使用一个 USDHC 设备(SD 卡)。如果没有使用 NAND,那么就有两个 USDHC 设备(EMMC 和 SD 卡),宏 CONFIG_SYS_FSL_USDHC_NUM 表示 USDHC 数量。 EMMC 版本的核心版没有用到 NAND,所以 CONFIG_SYS_FSL_USDHC_NUM=2。
  • 第 75~81,和 I2C 有关的宏定义,用于控制使能哪个 I2C, I2C 的速度为多少。
  • 第 92~96 行, NAND 的分区设置,如果使用 NAND 的话,默认的 NAND 分区为:"mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) ",分区结果如表
    在这里插入图片描述

NAND 的分区是可以调整的,比如 boot 分区我们用不了 64M 这么大,因此可以将其改小,其他的分区一样的。

  • 第 98~111 行,宏 CONFIG_MFG_ENV_SETTINGS 定义了一些环境变量,使用 MfgTool 烧写系统时候会用到这里面的环境变量。
  • 第 113~202 行 , 通 过 条 件 编 译 来 设 置 宏 CONFIG_EXTRA_ENV_SETTINGS , 宏CONFIG_EXTRA_ENV_SETTINGS 也是设置一些环境变量,此宏会设置 bootargs 这个环境变量,后面我们会详细分析这个宏定义。
  • 第 204~217 行,设置宏 CONFIG_BOOTCOMMAND,此宏就是设置环境变量 bootcmd 的值。后面会详细的分析这个宏定义。
  • 第 220~222 行,设置命令 memtest 相关宏定义,比如使能命令 memtest,设置 memtest 测试的内存起始地址和内存大小。
  • 第 224 行,宏 CONFIG_SYS_LOAD_ADDR 表示 linux kernel 在 DRAM 中的加载地址,也就是 linux kernel 在 DRAM 中的存储首地址, CONFIG_LOADADDR=0X80800000。
  • 第 225 行,宏 CONFIG_SYS_HZ 为系统时钟频率,这里为 1000Hz。
  • 第 227 行,宏 CONFIG_STACKSIZE 为栈大小,这里为 128KB。第 230 行,宏 CONFIG_NR_DRAM_BANKS 为 DRAM BANK 的数量, I.MX6ULL 只有一个 DRAM BANK,我们也只用到了一个 BANK,所以为 1。
  • 第 231 行,宏 PHYS_SDRAM 为 I.MX6ULL 的 DRAM 控制器 MMDC0 所管辖的 DRAM 范围起始地址,也就是 0X80000000。
  • 第 233 行,宏 CONFIG_SYS_SDRAM_BASE 为 DRAM 的起始地址。
  • 第 234 行,宏 CONFIG_SYS_INIT_RAM_ADDR 为 I.MX6ULL 内部 IRAM 的起始地址(也就是 OCRAM 的起始地址),为 0X00900000。
  • 第 235 行,宏 CONFIG_SYS_INIT_RAM_SIZE 为 I.MX6ULL 内部 IRAM 的大小(OCRAM的大小),为 0X00040000=128KB。
  • 第 237~240 行,宏 CONFIG_SYS_INIT_SP_OFFSET 和 CONFIG_SYS_INIT_SP_ADDR 与初始 SP 有关,第一个为初始 SP 偏移,第二个为初始 SP 地址。第256行,宏CONFIG_SYS_MMC_ENV_DEV为默认的MMC设备,这里默认为USDHC2,也就是 EMMC。
  • 第257 行,宏 CONFIG_SYS_MMC_ENV_PART 为模式分区,默认为第 0 个分区。
  • 第 258 行,宏 CONFIG_MMCROOT 设置进入 linux 系统的根文件系统所在的分区,这里设置为"/dev/mmcblk1p2",也就是 EMMC 设备的第 2 个分区。第 0 个分区保存 uboot,第 1 个分区保存 linux 镜像和设备树,第 2 个分区为 Linux 系统的根文件系统。
  • 第 277~291 行,与 NAND 有关的宏定义,如果使用 NAND 的话。
  • 第 293 行,宏 CONFIG_ENV_SIZE 为环境变量大小,默认为 8KB。
  • 第 294~308 行,宏 CONFIG_ENV_OFFSET 为环境变量偏移地址,这里的偏移地址是相对于存储器的首地址。如果环境变量保存在 EMMC 中的话,环境变量偏移地址为 1264KB。如果环境变量保存在 SPI FLASH 中的话,偏移地址为 7681024。如果环境变量保存在 NAND 中的话,偏移地址为 60<<20(60MB),并且重新设置环境变量的大小为 128KB。
  • 第 312~323 行,与 USB 相关的宏定义。
  • 第 325~342 行,与网络相关的宏定义,比如使能 dhcp、 ping 等命令。
  • 第 331 行的宏CONFIG_FEC_ENET_DEV 指定 uboot 所使用的网口, I.MX6ULL 有两个网口,为 0 的时候使用 ENET1,为 1 的时候使用 ENET2。宏 IMX_FEC_BASE 为 ENET 接口的寄存器首地址,宏CONFIG_FEC_MXC_PHYADDR 为网口 PHY 芯片的地址。宏 CONFIG_FEC_XCV_TYPE 为PHY 芯片所使用的接口类型, I.MX6U-ALPHA 开发板的两个 PHY 都使用的 RMII 接口。
  • 第 344~END,剩下的都是一些配置宏,比如 CONFIG_VIDEO 宏用于开启 LCD,CONFIG_VIDEO_LOGO 使能 LOGO 显示, CONFIG_CMD_BMP 使能 BMP 图片显示指令。这样就可以在 uboot 中显示图片了,一般用于显示 logo。
    关于 alientek_mx6ull_emmc.h 就讲解到这里,其中以 CONFIG_CMD 开头的宏都是用于使能相应命令的,其他的以 CONFIG 开头的宏都是完成一些配置功能的。以后会频繁的和alientek_mx6ull_emmc.h 这个文件打交道。

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

重启开发板即可启动内核:
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦梨甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值