跳到主要内容

I.MX6U学习笔记系统移植篇2

发现篇幅过多转移到第二篇了。

搞一个正点原子的Uboot

尝试编译NXP官方的uboot

image-20230826101924226

在官方uboot的config找到ll的Evaluation Kit config

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

尝试编译通过直接拿来改

我们用emmc的版本

  1. new a config named mx6ull_alientek_emmc_defconfig,copy emmc version defconfig and make some change

    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

    note:改了第一行的board/freescale里的板子信息、将target也改了

  2. 添加开发板的重要头文件in incluede / configs

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

    将最上面的ifndef改成

    #ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
    #define __MX6ULL_ALIENTEK_EMMC_H

    这个.h非常重要,可以用来配置uboot

    危险

    在配置里看到linuxboot的地址可能不是很对,问题是我们并没有define ll的宏定义...,就是说不是从0x80800000启动

    /* Boot options */
    #if (defined(CONFIG_MX6SX) || defined(CONFIG_MX6SL) || defined(CONFIG_MX6UL) || defined(CONFIG_MX6SLL))
    #define CONFIG_LOADADDR 0x80800000
    #ifndef CONFIG_SYS_TEXT_BASE
    #define CONFIG_SYS_TEXT_BASE 0x87800000
    #endif
    #else
    #define CONFIG_LOADADDR 0x12000000
    #ifndef CONFIG_SYS_TEXT_BASE
    #define CONFIG_SYS_TEXT_BASE 0x17800000
    #endif
    #endif

    下次找个机会print一下#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR

  3. 进入board/freescale/复制 mx6ullevk将其重命名为 mx6ull_alientek_emmc

    1. 修改Makefile,obj-y := mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c 这个文件

    2. imximage.cfg的改成PLUGIN board/freescale/mx6ull_alientek_emmc/plugin.bin 0x00907000 /

    3. 将Kconfig改成

      if TARGET_MX6ULL_ALIENTEK_EMMC || TARGET_MX6ULL_9X9_EVK

      config SYS_BOARD
      default "mx6ull_alientek_emmc"

      config SYS_VENDOR
      default "freescale"

      config SYS_CONFIG_NAME
      default "mx6ull_alientek_emmc"

      endif
    4. 修改MAINTAINERS

      MX6ULL_ALIENTEK_EMMC BOARD
      M: Pansy Hou <1677195845@qq.com>
      S: Maintained
      F: board/freescale/mx6ull_alientek_emmc/
    5. 修改arch/arm/cpu/armv7/mx6/Kconfig 插入

      config TARGET_MX6ULL_ALIENTEK_EMMC
      bool "Support mx6ull_alientek_emmc"
      select MX6ULL
      select DM
      select DM_THERMAL

      还有source "board/freescale/mx6ull_alientek_emmc/Kconfig"

    6. 至此已经完成差不多了,最后加入.sh完成脚本编译

修改LCD驱动

uboot中,驱动修改一般在xx.h/c中

主要关注几点

  1. GPIO配置是否正确
  2. 背光引脚设置
  3. LCD参数设置

我们定位到board/freescale/mx6ull_alientek_emmc/mx6ull_alientek_emmc.c

//in 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;
};
//defined in include/linux/fb.h
struct fb_videomode {
const char *name; /* optional */
u32 refresh; /* optional */
u32 xres;
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;
};

struct display_info_t const displays[] = {{
.bus = MX6UL_LCDIF1_BASE_ADDR,
.addr = 0,
.pixfmt = 24, //像素格式
.detect = NULL,
.enable = do_enable_parallel_lcd,
.mode = { // fb_videomode,定义在文件 include/linux/fb.h
.name = "TFT43AB",
.xres = 480,
.yres = 272,
.pixclock = 108695, //像素时钟,每个像素时钟周期的长度,单位为皮秒,pixclock=(1/51200000)*10^12=19531
.left_margin = 8, //HBP水平同步后肩。
.right_margin = 4, //HFP水平同步前肩。
.upper_margin = 2, //VBP垂直同步后肩。
.lower_margin = 4, //VFP垂直同步前肩。
.hsync_len = 41,
.vsync_len = 10,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
size_t display_count = ARRAY_SIZE(displays);

网卡配置

注意,如何修改网卡1网络驱动

提示

evk板子的ENET1 引脚与正点的基本一样,只有复位不一样

  1. 复位引脚初始化
  2. 器件ID
  3. 驱动

PHY地址修改

打开include/configs/mx6ull_alientek_emmc.h,大部分宏定义在这里

我们调整PHY地址和驱动

#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//替换成REALTEK
#endif
  1. CONFIG_FEC_ENET_DEV决定使用哪个网口,默认为1
  2. #define CONFIG_PHY_MICREL使能micrel公司驱动

之后对网络复位引脚修改,因为和evk不同,所以注释掉

// #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)

#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

删除 iox74lv_init()iox74lv_set

找到board_init注释掉上面的init和imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));

添加我们的复位引脚初始化

static iomux_v3_cfg_t const fec1_pads[] = {
MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

在最下面一行加入了MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),

同理,往fec2也加入MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),

setup_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);
}
mdelay(150);/* 复位结束后至少延时 150ms 才能正常使用*/
}

坑比SR8201F,还要等150ms才能识别,150ms什么概念?

image-20230830123625650

提示

在学习Linux内核前,有必要学习两个环境变量bootcmd bootargs

bootcmd环境变量

bootcmd保存着 uboot 默认命令,uboot 倒计时结束以后就会执行 bootcmd 中的命令。

这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 中的 Linux 内核镜像文件设备树文件到 DRAM 中,然后启动 Linux 内核。可以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。

默认的bootcmd在include/env_default.h,没有修改过(指的是板子第一次运行、或者EMMC等没有保存的话)的话应该是这货

DEFAULT_ENV_INSTANCE_EMBEDDEDCONFIG_SYS_REDUNDAND_ENVIRONMENT没有被定义,所以用静态的方法存储

#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
env_t environment __PPCENV__ = {
ENV_CRC, /* CRC Sum */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
1, /* Flags: valid */
#endif
{
#elif defined(DEFAULT_ENV_INSTANCE_STATIC)
static char default_environment[] = {
#else
const uchar default_environment[] = {
#endif

bootcmd 的默认值就是CONFIG_BOOTCOMMAND bootargs 的默认值就是 CONFIG_BOOTARGS

#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

加载linux镜像文件zimage成功之后就运行mmcboot环境变量

"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" \
危险

run mmcargs运行,用于设置bootargs

"mmcargs=setenv bootargs console=console,{console},{baudrate} "

判断boot_fdt是不是yes

run loadfdtloadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}

loadfdt=fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb

从mmc1的分区1中读取dtb到0x83..

读取成功后bootz 0x80800 - 0x8300.

至此,Linux内核启动,为了从emmc读取zImage和dtb,浓缩成4行精华

mmc dev 1//切换到emmc
fatload mmc 1:1 0x80800000 zImage //读取 zImage 到 0x80800000 处
fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb //读取设备树到 0x83000000 处
bootz 0x80800000 - 0x83000000 //启动 Linux
提示

我们可以直接修改COMMAND_BOOTCOMMAND简化过程

bootargs环境变量

这个是用于传递给内核启动的参数

bootargs由mmcargs设置的:

mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}

其中 console=ttymxc0, baudrate=115200, mmcroot=/dev/mmcblk1p2 rootwait rw, 因 此将mmcargs 展开以后就是:

mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw

rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的

之后就是启动Linux

后面就是Kconfig的一些讲解,暂时用不上,而且这玩意不能跨平台,本来想用于我们新架构的.config编写

Linux内核顶层Makefile

image-20230901200941499

image-20230901200954627

内核启动流程

Linux内核移植

配置并编译内核

提示

每个板子对应默认文件在arch/arm/configs,大概叫imx_v7_mfg_defconfig 或者imx_v7_defconfig

同时,编译出来的zImage可以通过NXP官方的MfgTool烧写

make clean
make imx_v7_mfg_defconfig//配置Linux内核
make -j12
  1. .dtbarch/arm/boot/dts目录
  2. zImage在arch/arm/boot

在arch/arm/boot/dts/Makefile加入imx6ull-alientek-emmc.dtb \

image-20230904102936679

就可以从imx6ull-alientek-emmc.dts 编译出 imx6ull-alientek-emmc.dtb 文件了

莫名其妙的超频

去menuconfig把CPU Power Management的CPU Frequency scaling改一下策略就行

修改设备树

找到linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts/imx6ull.dtsi

    cpus {
#address-cells = <1>;
#size-cells = <0>;

cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
clock-latency = <61036>; /* two CLK32 periods */
operating-points = <
/* kHz uV */
996000 1275000
792000 1225000
528000 1175000
396000 1025000
198000 950000
>;
fsl,soc-operating-points = <
/* KHz uV */
996000 1175000
792000 1175000
528000 1175000
396000 1175000
198000 1175000
>;

可以看到6ull理论上是可以到996MHz的,但是为什么cat cpuinfo_cur_freq之/sys/devices/system/cpu/cpu0/cpufreq/ scaling_available_frequencies 后的可用频率最高只有528?

按照正点的说法,芯片不同默认最高不一样

在什么情况会认芯片?

修改8线emmc驱动

简单修改一下设备树即可

修改网络驱动

根文件系统构建rootfs