【NXP IMX系列】 i.MX BSP UBOOT移植

Chapter 1 Porting U-Boot from an i.MX 6/7 Reference Board to an i.MX 6/7 Custom Board

1.1 U-Boot Overview

本章提供了一个逐步指南,解释如何在U-Boot中添加i.MX 6和i.MX 7自定义板支持。
本开发者指南基于U-Boot v2016.03软件包。有关i.MX补丁,请参阅发布说明。

1.2 Obtaining the Source Code for the U-Boot

//TODO 添加地址和连接以及操作步骤获取UBOOT

注: 以下章节中,U-Boot的主目录被称为<UBOOT_DIR>。同时假设你的shell工作目录是<UBOOT_DIR>。

1.2.1 Preparing the Code

以下是准备代码的步骤:

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

复制板子目录,命令如下:

$ cp -R board/freescale/<mx6 or mx7><reference board name>  board/freescale/<mx6 or mx7><custom board name>
cd board/freescale/
cp mx6ullevk/ -r mx6ull_alientek_emmc
2.添加开发板对应的头文件

将现有的mx.h板子配置文件复制为mx.h,命令如下:

$cp include/configs/mx<reference board name>.h include/configs/mx<custom board name>.h
cp include/configs/mx6ullevk.h include/configs/mx6ull_alientek_emmc.h

拷贝完成以后将:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

改为:

#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
#define __MX6ULL_ALIENTEK_EMMC_CONFIG_H

i.MX 6或i.MX 7的配置文件位于include/configs目录下。与板子相关的文件包括:

  1. i.MX 6 SABRE-SD:

    • mx6sabresd_common.h
    • mx6sabresd.h
  2. i.MX 6 SABRE-AI:

    • mx6sabresd_common.h
    • mx6qsabreauto.h
  3. i.MX 6SoloLite EVK:

    • mx6slevk.h
  4. i.MX 6SoloX SABRE-SD:

    • mx6sxsabresd.h
  5. i.MX 6SoloX SABRE-AI:

    • mx6sxsabreauto.h
  6. i.MX 7Dual SABRE-SD:

    • mx7dsabresd.h
  7. i.MX 6UltraLite EVK

    • mx6ul_14x14_evk.h
  8. i.MX 6UltraLiteLite EVK

    • mx6ullevk.h

    当使用新板子时,应注意以下配置:
    • CONFIG_LOADADDR:一般情况下,zImage将加载到此地址以进行启动。
    • CONFIG_SYS_MALLOC_LEN:堆内存大小。
    • CONFIG_STACKSIZE:栈大小。
    • CONFIG_NR_DRAM_BANKS:DDR芯片数量。
    • PHYS_SDRAM_SIZE:以MB为单位配置DDR内存大小。
    • PHYS_SDRAM:DDR内存的物理地址
    • fdt_file:配置“#define CONFIG_DEFAULT_FDT_FILE .dtb”或直接更改“fdt_file=.dtb”。
    配置文件对U-Boot非常重要。它确定u-boot.bin的大小、功能和性能。

3.添加开发板默认配置文件defconfig文件

在 <UBOOT_DIR>/configs/ 目录下创建一个新文件,用于新的基于 i.MX 架构的配置。以下是 i.MX 6Quad 板子的示例指令:

CONFIG_SYS_EXTRA_OPTIONS=“IMX_CONFIG=board/freescale/mx6q<customer_board>/<customer_board>.cfg,MX6Q”
CONFIG_ARM=y
CONFIG_TARGET_MX6Q<customer_board>=y
CONFIG_SYS_MALLOC_F=y
CONFIG_SYS_MALLOC_F_LEN=0x400
CONFIG_DM=y
CONFIG_DM_THERMAL=y

请确保将 <customer_board> 替换为您的板子配置的适当名称。这个新文件将包含您的 i.MX 板子的特定配置选项。

先在 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 中的内容改成下面的:
示例代码 mx6ull_alientek_emmc_defconfig 文件

1 CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_
emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
2 CONFIG_ARM=y
3 CONFIG_ARCH_MX6=y
4 CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
5 CONFIG_CMD_GPIO=y

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

4. Rename
board/freescale/<mx6 or mx7><reference board name>/<mx6 or mx7><reference board name>.c
to
board/freescale/<mx6 or mx7><custom board name>/<mx6 or mx7><custom board name>.c.
cd mx6ull_alientek_emmc
mv mx6ullevk.c mx6ull_alientek_emmc.c
5、修改 mx6ull_alientek_emmc 目录下的 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 $< $@

修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件
将 imximage.cfg 中的下面一句:

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

改为:

PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000
6. Change the Kconfig.
1 if TARGET_MX6ULL_ALIENTEK_EMMC
2 
3 config SYS_BOARD
4 default "mx6ull_alientek_emmc"
5 
6 config SYS_VENDOR
7 default "freescale"
8 
9 config SYS_SOC
10 default "mx6"
11
12 config SYS_CONFIG_NAME
13 default "mx6ull_alientek_emmc"
14
15 endif

添加条目 arch/arm/cpu/armv7//Kconfig
在这里插入图片描述
arch/arm/cpu/armv7/mx6/Kconfig

1 config TARGET_MX6ULL_ALIENTEK_EMMC
2 bool "Support mx6ull_alientek_emmc"
3 select MX6ULL
4 select DM
5 select DM_THERMAL

在最后一行的 endif 的前一行添加如下内容:

source "board/freescale/mx6ull_alientek_emmc/Kconfig"

添加完成以后的 Kconfig 文件如图
在这里插入图片描述

7 编译
export ARCH=arm
export CROSS_COMPILE= xxxx
make distclean;
make mx<custom board name>_config
make

当您创建了一个新的基于 i.MX 处理器的自定义板,这个板是 i.MX 参考板的精确副本,但是两个板是独立构建的,这意味着您可以按照以下步骤进行下一步操作:定制代码以适应新的硬件设计。

  • 复制参考板配置:
    首先,复制参考板的配置文件和目录。在 U-Boot 或 Linux 内核中,这可能包括设备树(.dts 和 .dtsi 文件)、板级配置文件等。
  • 重命名配置:
    修改复制的目录和文件,使它们反映新的自定义板名称。这通常涉及到重命名文件和修改文件内容中的引用,如 Kconfig 中的板名和设备树中的兼容性字符串。
  • 更新构建系统:
    在构建系统(例如 Makefile 或 Kconfig 文件)中添加对新板的支持。这可能包括添加新的选项来选择您的自定义板作为构建目标。
  • 调整设备树:
    修改设备树文件以匹配新硬件的特定配置,比如 GPIO 分配、外设接口、内存映射等。
  • 定制引导加载程序(U-Boot):
    如果使用 U-Boot,可能需要更新启动脚本、环境变量设置或添加新的板级初始化代码。
    修改内核配置:
    根据新硬件的需求,调整 Linux 内核的配置。这可能涉及启用或禁用特定的驱动程序和功能。
    开发或修改驱动程序:
    如果新硬件包含非标准或自定义组件,您可能需要开发新的驱动程序或修改现有驱动程序。
  • 验证和测试:
    编译新的固件,并在实际硬件上进行测试。检查所有功能是否按预期工作,包括 I/O、网络、存储和其他外设。
  • 迭代改进:
    根据测试结果进行必要的调整和优化,直到系统稳定且性能满足要求。

通过这些步骤,您可以将一个现有的参考设计转变为一个完全定制的硬件平台,同时确保软件与新硬件设计保持同步。在整个过程中,维护良好的文档和变更日志非常重要,以便跟踪所做的更改和任何相关的修复或优化。

1.3 Customizing the i.MX 6 or i.MX 7 Custom Board Code

通过上述章节1.2的操作, i.MX 6 或 i.MX 7 自定义板是 U-Boot 源代码树的一部分,但它只是 i.MX 6 或 i.MX 7 参考板代码的副本,需要进行定制。DDR 技术可能是两个板之间的一个关键区别。如果 DDR 技术有所不同,那么 DDR 初始化需要被移植。DDR 初始化被编码在 U-Boot 镜像的启动头部的 DCD(设备配置数据)表中。当移植引导加载程序、内核或驱动程序代码时,必须能够方便地访问电路原理图以供参考。

1.3.1 Changing the DCD Table for i.MX DDR3, LPDDR2, LPDDR3 Initialization

如果两个板之间的 DDR 技术有差异,DDR 初始化需要被移植。DDR 初始化被编码在 U-Boot 镜像的启动头部的 DCD 表中。
在您初始化内存接口之前,需要先配置相关的 I/O 引脚,设定正确的模式和阻抗,然后初始化 MMDC(多模式动态内存控制器)模块。

关于如何为 DDR 生成校准参数,可以参考 i.MX 6 系列的 DDR 校准应用笔记(AN4467)。用户还可以使用 i.MX 设计和工具列表中的 DDR 脚本辅助工具和 DDR 压力测试工具来进行 DDR 初始化。
imximage.cfg
在这里插入图片描述

以下是一些具体步骤:

  • 配置 I/O 引脚:
    在初始化内存之前,必须先设置处理器的 I/O 引脚,以便它们能够与外部 DDR 内存通信。这包括设置引脚的功能模式(如 GPIO、SDRAM 或其他专用功能),以及适当的电气特性,如驱动强度和阻抗匹配。这通常在启动过程的早期阶段完成,可能涉及到修改 U-Boot 中的引导代码或设备树文件。
  • 初始化 MMDC 模块:
    MMDC 是负责管理 DDR 内存交互的内部模块。初始化 MMDC 涉及到设置时序参数、内存大小和其他重要的配置选项。这些设置通常基于内存数据手册和硬件设计。
  • 生成 DDR 校准参数:
    参考 i.MX 6 系列 DDR 校准应用笔记(AN4467),了解如何生成 DDR 的校准参数。这些参数对于确保 DDR 性能和稳定性至关重要。DDR 校准涉及到调整读写延迟、数据路径延迟和其他重要的时序参数。
  • 使用 DDR 辅助脚本和压力测试工具:
    NXP 提供了 DDR 脚本辅助工具和 DDR 压力测试工具,以帮助用户生成初始化和校准参数。这些工具可以自动执行许多校准步骤,并提供有关最佳设置的指导。
  • 测试和验证:
    使用生成的参数初始化 DDR,并通过运行压力测试来验证其性能和稳定性。确保在各种操作条件下内存都能可靠工作。
    集成到启动过程中:
    将最终的初始化和校准参数集成到 U-Boot 的启动过程中。这可能涉及到更新 DCD 表或其他启动时配置代码。
  • 编译并测试:
    编译更新后的 U-Boot,并在目标硬件上进行测试,确保系统能够正常启动,并且内存表现出预期的性能。
    通过这些步骤,您可以确保新的自定义 i.MX 6 或 i.MX 7 板的 DDR 内存得到正确的配置和优化,从而实现最佳性能。

为了将代码移植到自定义板,需要正确初始化 DDR 内存。以 i.MX 6Quad 自定义板为例,进行 DDR 初始化的步骤如下:

  • 打开配置文件:
    导航到 U-Boot 源代码目录中相应的位置,打开位于 board/freescale/mx6<customer_board_name>/ 的 imximage.cfg 文件。假设您的自定义板名为 mx6mycustomboard,那么您需要找到并打开 board/freescale/mx6mycustomboard/imximage.cfg。如果您是基于一个现有的配置(比如 mx6q.cfg),那么您可能需要复制这个文件作为起点,并重命名为适合您的自定义板的名称。
  • 修改配置项:
    在 imximage.cfg 文件中,您会找到用于初始化 DDR 内存的一系列命令和参数。这些包括设置内存大小、时序、电压等级等。您需要根据您的 DDR 内存规格来修改这些参数。通常,这些信息可以从内存的数据手册或从内存制造商提供的配置指南中获得。
    对于 i.MX 6 系列,您可能会看到包含 DATA 4 或 DATA 8 开头的行,这些行定义了写入到 MMDC 寄存器的具体值。例如:
DATA 4, 0x021b001c, 0x00008000

这表示在地址 0x021b001c 处写入数据 0x00008000。

  • 由 ROM 代码读取:
    修改后的 imximage.cfg 文件中的配置块将被 ROM 代码读取,以初始化您的 DDR 内存。当您构建 U-Boot 时,这个配置文件会被编译进 DCD(Device Configuration Data)表中,并嵌入到生成的 U-Boot 映像的启动头部分中。
    请确保您对 imximage.cfg 文件中的每一项都有充分理解,因为错误的配置可能导致系统无法启动或内存运行不稳定。在修改配置之后,重新编译 U-Boot 并在您的自定义板上进行充分测试,以验证内存初始化是否成功且系统稳定运行。如果遇到问题,可能需要反复调整参数并测试,直到找到最佳配置。

1.3.2 Booting with the Modified U-Boot

描述了如何编译 U-Boot 并将 u-boot.imx 写入 SD 卡。如果 DDR 配置(位于 board/freescale/mx6<customer_board_name>/imximage.cfg)已经成功修改,您可以继续编译并将 u-boot.imx 写入 SD 卡。为了验证这一点,将 SD 卡插入 CPU 板的 SD 卡插槽并开启电源。

如果您的板是基于 i.MX 6Quad SABRE_SD 的,那么在控制台上应该会显示以下消息:
在这里插入图片描述

1.3.3 Adding New Driver Initialization Code to Board Files

以下步骤描述了如何添加新驱动程序以及如何初始化代码:

  1. 在 board/freescale/mx<customer_board>/ 目录中找到 mx<customer_board>.c 文件。
  2. 编辑 mx<customer_board>.c 文件,并添加新驱动程序的初始化代码,包括时钟(clock)、I/O 复用(IOMUX)和通用输入输出(GPIO)。
  3. 将驱动程序的初始化函数放入 board_init 或 board_late_init 函数中。
  • board_early_init_f() 函数在非常早期的阶段被调用,如果你定义了 CONFIG_BOARD_EARLY_INIT_F 配置项。您可以在这个阶段设置那些需要非常早期配置的功能,比如 UART(通用异步收发传输器)、SPI-NOR(串行外设接口闪存)、NAND(一种类型的闪存)的 I/O 复用(IOMUX)设置函数。
  • board_init() 函数在 board_early_init_f 和 board_late_init 之间被调用。你可以在这里进行一些通用的板级设置。如果你没有定义 CONFIG_BOARD_EARLY_INIT_F,那么在 UART 设置完成之前不要调用 printf 函数。否则,系统可能会崩溃。
  • board_late_init() 函数相对较晚被调用。为了调试初始化代码,可以将初始化函数放入其中。

1.3.4 Further Customization at System Boot

要进一步定制您的 U-Boot 板子项目,请使用系统引导调用的第一个函数:
common/board_f.c 中的 board_init_f
board_early_init_f()
board_init()
所有的板子初始化都在这个函数中执行。它首先通过运行 init_sequence_f[] 和 init_sequence_r[] 函数指针的数组来开始。init_sequence_f[] 数组中的第一个与板子相关的函数是 board_early_init_f()。board_early_init_f() 在 board/freescale/mx6.c 中实现。

以下代码行是最重要的:

setup_iomux_uart();

1.3.5 Customizing the Printed Board Name

要自定义打印的板子名称,请使用 checkboard() 函数。
该函数是从 board/freescale/mx6.c 中实现的 init_sequence_f[] 数组中调用的。有两种方法可以使用 checkboard() 来自定义打印的板子名称:强制方式或者通过更灵活的标识方法(如果在自定义板子上实现)。

要使用强制方式自定义,删除 checkboard() 中的 identify_board_id() 函数,并将 printf("Board: "); 替换为 printf(“Board: i.MX on \n”)。
如果不进行这个替换,自定义板子可能会使用其他标识方法。标识方法可以根据自定义板子上的标识方法来实现 __print_board_info() 函数,以便检测和打印标识信息。

int checkboard(void)
{
	if (is_mx6ul_9x9_evk())
		puts("Board: MX6UL 9x9 EVK\n");
	else
		puts("Board: MX6UL 14x14 EVK\n");

	return 0;
}

1.4 调试

有两种调试方法:
• 使用 JTAG 工具
• 使用 printf

1.4.1 使用 JTAG 工具进行调试

通常,我们在非常早期的阶段使用 JTAG 工具进行调试,例如,在 UART 初始化之前,或者在使用 printf 进行调试困难的情况下。

确保您的 JTAG 工具支持 i.MX 6 上的 ARM® Cortex®-A9 核心,并支持 i.MX 7Dual 和 6UltraLite 上的 ARM® Cortex®-A7 核心。建议使用 TRACE32。
将 U-Boot(elf 文件)完全加载到 U-Boot 的根目录中,或者只加载符号(更快),以便逐步调试。我们可以在编译时使用优化级别 0,这样更容易在 JTAG 工具中进行调试。

1.4.2 使用 printf 进行调试

这是我们在调试中最常用的方法。您可以在驱动程序中打印值进行调试。
注意:
如果您想在早期阶段使用 printf,例如在 board_init 中,
我们可以将 UART 初始化代码放在更早的位置,例如在 board_early_init_f() 中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值