Linux系统移植:官板 uboot 修改(下)
Posted 嵌入式up笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统移植:官板 uboot 修改(下)相关的知识,希望对你有一定的参考价值。
文章目录
Linux系统移植:官板 uboot 修改(下)
上一节我们将官板的 uboot 修改后适配正点原子开发板,可以编译成功下载运行,但其中还有不少驱动没有移植完成,本节完成部分驱动和环境变量配置,适配开发板
修改驱动主要在我们上一章移植的 mx6ull_alientek_emmc.h 和 board/freescake/mx6ull_alientek_emmc/mx6ull_alientek_emmc.c 文件中进行修改
一、LCD 驱动修改
修改 LCD 驱动重点注意以下几点:
- LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确
- LCD 背光引脚 GPIO 的配置
- LCD 配置参数是否正确
原子的开发板和官板的 LCD 接口一致,所以不用修改,IO参数可以在 mx6ull_alientek_emmc.c 中的 lcd_pads 变量查看到
所以我们主要修改软件参数,在文件 mx6ull_alientek_emmc.c 中找到如下所示内容:
这段代码定义了一个 display_info_t 结构体,包含了 LCD 的分辨率,像素格式以及其他参数信息
display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,详细可以去看一看
其中参数如下:
-
bus:LCD 寄存器基地址
-
pixfmt:像素格式,此处使用 RGB888 就是 24 位
-
mode 是 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,也就是不使用隔行扫描
-
具体屏幕参数参考如下:
按照上面参数计算,时钟计算方式如下:
pixclock=(1/屏幕主频)*10^12
屏幕移植后要将 mx6ull_alientek_emmc.h 中的 panel 参数名称和 fb_videomode 结构体的 name 相同,挂载成功后如下:
按道理屏幕会显示 NXP 的 LOGO 但是我移植完并没有显示,直接下载原子的代码也不能正常显示,原子提供代码和硬件肯定存在问题,查看的参考源码和我上面提供的参数,出处很大,后面需要再研究研究,但大致思路没有问题
二、网口驱动修改
IMX 有两个网口接口 ENET1 和 ENET2;
ENET1 的网络 PHY 芯片为 LAN8720A,通过 RMII 接口与 I.MX6ULL 相连,I.MX6U-ALPHA 开发板 ENET1 的网络原理图如图:
开发板的 ENET1 引脚与 NXP 官方的 I.MX6ULL EVK 开发板基本一样,只有复位引脚不同
I.MX6ULL 通过 MDIO接口来读取 PHY 芯片的内部寄存器,来判断当前的物理链接状态、连接速度 (10M 还是 100M) 和双工状态 (半双工还是全双工)
MDIO 接口有两个引脚,ENET_MDC 和 ENET_MDIO,ENET_MDC 提供时钟,ENET_MDIO 进行数据传输。一个 MDIO 接口可以管理 32 个 PHY 芯片,同一个 MDIO 接口下的这些 PHY 使用不同的器件地址来做区分,MIDO 接口通过不同的器件地址即可访问到相应的 PHY 芯片
ENET1 上连接的 LAN8720A器件地址为 0X0,要修改 ENET1 网络驱动的话重点就三点:
- ENET1 复位引脚初始化
- LAN8720A 的器件 ID
- LAN8720 驱动
ENET2 驱动和 1 基本相同,但 ENET2 的复位引脚 ENET2_RST 接到了 I.MX6ULL 的 SNVS_TAMPER8 上,ENET2 所使用的 PHY 芯片器件地址为 0X1,所以修改 uboot 驱动分为以下的步骤:
2.1 PHY 地址修改
打开 mx6ull_alientek_emmc.h,看到如下宏定义:
宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择 ENET2
CONFIG_FEC_MXC_PHYADDR 为 PHY 地址
宏 CONFIG_PHY_MICREL 用于使能 uboot 中的 PHY 驱动,修改为 CONFIG_PHY_SMSC
2.2 删除 uboot 中 74LV595 的驱动代码
芯片地址修改完成以后就是网络复位引脚的驱动修改,NXP 官方 I.MX6ULL EVK 开发板使用 74LV595 来扩展 IO,两个网络的复位引脚就是由 74LV595 来控制的。正点原子的 I.MX6U-ALPHA 开发板并没有使用 74LV595,因此打开 mx6ull_alientek_emmc.c,删除如下代码:
替换为如下:
#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 中找到如下 IO 配置代码结构体,然后删除掉:
然后找到 iox74lv_set 和 iox74lv_init 函数,将他们删除
找到 board_init 函数调用的 iox74lv_init 和 imx_iomux_v3_setup_multiple_pads,然后删除:
2.3 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动
2.2 中我们删除了引脚的初始化代码,2.3 小节需要添加初始化代码:
找到 iomux_v3_cfg_t const fec1_pads[] 和 iomux_v3_cfg_t const fec2_pads[],这两个结构体数组 fec1_pads 和 fec2_pads 是 ENET1 和 ENET2 这两个网口的 IO 配置参数,我么添加两个网口的复位 IO 配置参数
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
添加后如下:
找到网口初始化函数 setup_iomux_fec:
添加网口芯片复位代码:
硬件复位很重要,必须添加
2.4 修改驱动函数
打开文件 drivers/net/phy/phy.c,找到函数 genphy_update_link,这是个通用 PHY 驱动函数此函数用于更
新 PHY 的连接状态和速度。使用 LAN8720A 的时候需要在此函数中添加一些代码,修改后的函数 genphy_update_link 如下
这段代码的宏,我们在一开始已经添加了,只有使用 SMSC 公司的 PHY 这段代码才会执行,读取LAN8720A 的 BMCR 寄存器,然后向寄存器 BMCR 寄存器写入 BMCR_RESET,软件复位 LAN8720A,然后等待 LAN8720A 软件复位完成,最后重新向 BMCR 寄存器写入以前的值
到此网口修改完成,编译下载,运行观察
检测 NET 使用 FEC1成功,下面我们把开发板连接到电脑,设置电脑的网口和开发板在同一个 IP 下,用开发板 Ping Windows 和 ubuntu 的 IP 地址,结果如下,网口 Ping 通
三、其他修改
修改 uboot 启动后的板子名称,打开文件 mx6ull_alientek_emmc.c,找到函数 checkboard:
修改名称:
puts("Board: MX6ULL ALIENTEK EMMC\\n");
编译下载,观察现象:
四、bootcmd 和 bootargs 修改
uboot 中有两个非常重要的环境变量 bootcmd 和 bootargs,这两个变量采用类似 shell 脚本语言编写的,里面有很多的变量引用,这些变量都是环境变量,很多是 NXP 定义的,文 件 mx6ull_alientek_emmc.h 中的宏
CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值
CONFIG_EXTRA_ENV_SETTINGS 是个条件编译语句,通过宏定义在使用 NAND 和 EMMC 的时候宏CONFIG_EXTRA_ENV_SETTINGS 的值是不同
4.1 bootcmd 修改
bootcmd 保存着 uboot 默认命令,uboot 倒计时结束以后就会执行 bootcmd 中的命令,这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量,在文件 include/env_default.h 中代码如下:
可以看到 uchar default_environment[] 数组保存了环境变量,我们可以在这个位置设置 bootcmd 的默认值!
也有一些环境变量调用了其他宏定义,比如 CONFIG_BOOTCOMMAND 这个宏定义,在 mx6ull_alientek_emmc.h 文件中可以找到:
这段代码使用类似 shell 语言代码编写:
- run findfdt:使用的是 uboot 的 run 命令来运行 findfdt,用来查找开发板对应的设备树文件(.dtb)
findfdt 内容如下:
"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" \\
如果 fdt_file 为 undefined 的话,那 uboot 就会根据板子信息得出所需的.dtb 文件名
- mmc dev $mmcdev 用于切换 mmc 设备,mmcdev 为 1,因此这行代码就是:mmcdev 1,也就是切换到 EMMC 上
- 后面的代码先执行 mmc dev $mmcdev切换到 EMMC 上,然后使用命令 mmc rescan 扫描看有没有 SD 卡或者 EMMC 存在,若没有执行 run netboot,netboot 是一个自定义的环境变量,从网络启动 Linux
- 如果有 EMMC 存在,先运行 loadbootscript 环境变量,该变量如下:
loadbootscript=fatload mmc $mmcdev:$mmcpart $loadaddr $script;
其中 mmcdev=1,mmcpart=1,loadaddr=0x80800000,script= boot.scr,这段代码 loadbootscript 就是从 mmc1 的分区 1 中读取文件 boot.src 到 DRAM 的 0X80800000 处
如果加载 boot.src 文件成功就运行 bootscript 环境变量,变量如下:
bootscript=echo Running bootscript from mmc ...;
source
如果 loadbootscript 没有执行成功,就会运行环境变量 loadimage,内容如下:
loadimage=fatload mmc $mmcdev:$mmcpart $loadaddr $image
其中 mmcdev=1,mmcpart=1,loadaddr=0x80800000,image = zImage,这段代码就是从 mmc1 的分区中读取 zImage 到内存的 0X80800000 处,当加载 linux 镜像文件 zImage 成功以后就运行环境变量 mmcboot,mmcboot 环境变量如下:
输出信息,然后运行环境变量 mmcargs(mmcargs 用来设置 bootargs),然后判断boot_fdt是否为yes或者try,进而是否加载设备树,如果读取.dtb 文件成功的话那就调用命令 bootz 启动 linux,然后 Linux 内核启动
总结一下该命令执行过程:
- 切换到 EMMC
- 读取 zImage 镜像文件到 0x80800000
- 读取设备树文件到 0x83000000
- 启动 Linux
4.2 bootargs 修改
bootargs 保存着 uboot 传递给 Linux 内核的参数,bootargs 环境变量是由 mmcargs 设置的,mmcargs 环境变量如下:
mmcargs=setenv bootargs console=$console,$baudrate root=$mmcroot
其中 console=ttymxc0,baudrate=115200,mmcroot=/dev/mmcblk1p2 rootwait rw,所以 mmcargs 就是设置 bootargs 的值为 “console= ttymxc0, 115200 root=/dev/mmcblk1p2 rootwait rw”,bootargs 就是设置了很多的参数的值,这些参数 Linux 内核会使用到,主要用到的参数如下:
4.2.1 console
console 用来设置 linux 终端(或者叫控制台),一般设置串口作为 Linux 终端,I.MX6ULL 的串口 1 在 linux 下的设备文件就是/dev/ttymxc0,刚刚代码中的 console= ttymxc0, 115200 就是设置串口波特率
4.2.2 root
root 用来设置根文件系统的位置,root=/dev/mmcblk1p2 用于指明根文件系统存放在 mmcblk1 设备的分区 2 中
/dev/mmcblkx(x=0~n)表示 mmc 设备
而/dev/mmcblkxpy(x=0n,y=1n)表示 mmc 设备 x 的分区 y
在 I.MX6U-ALPHA 开发板中 /dev/mmcblk1 表示 EMMC,而 /dev/mmcblk1p2 表示 EMMC 的分区 2
4.2.3 rootfstype
此选项一般配置 root 一起使用,rootfstype 用于指定根文件系统类型,如果根文件系统为 ext 格式保持默认就行,如果根文件系统是 yaffs、jffs 或 ubifs 的话就需要设置此项
到此 uboot 的修改基本完成,下一节就是启动 Linux 内核了
以上是关于Linux系统移植:官板 uboot 修改(下)的主要内容,如果未能解决你的问题,请参考以下文章