step 1:增加mx6ul_14x14_nes_game_emmc_defconfig(由mx6ul_14x14_evk_emmc_defconfig复制修改而来)
step 2:修改mx6ul_14x14_nes_game_emmc_defconfig中的内容,下边为修改内容
step 2.1:CONFIG_DEFAULT_DEVICE_TREE="imx6ul-14x14-nes-game-emmc"
step 2.2:CONFIG_IMX_CONFIG="board/freescale/mx6ul_14x14_nes_game_emmc/imximage.cfg"
step 2.3:CONFIG_TARGET_MX6UL_14X14_NES_GAME_EMMC=y
注意点: mx6ul_14x14_nes_game_emmc_defconfig与TARGET_MX6UL_14X14_NES_GAME_EMMC必须严格对应
即_defconfig之前文件名与TARGET_之后文件名相同
step 3:修改编译脚本imx6ul_nes_game_compile.sh
step 3.1:make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- mx6ul_14x14_nes_game_emmc_defconfig
step 4: 增加mx6ul_14x14_nes_game_emmc.h,并修改头文件的防重复添加的宏(由mx6ul_14x14_evk.h修改)
step 5: 增加board/freescale/mx6ul_14x14_nes_game_emmc文件夹(由mx6ul_14x14_evk复制而来)
step 5.1 修改mx6ul_14x14_evk.c为mx6ul_14x14_nes_game_emmc.c,同时修改内容,修改如下
修改点1: #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG-----board_late_init函数中
env_set("board_name", "imx6ul_nes_game_emmc");
修改点2: if (is_mx6ul_9x9_evk())---------checkboard函数中
puts("Board: MX6UL 9x9 EVK\n");
else
puts("Board: IMX6UL 14x14 NES GAME EMMC BOARD\n");
step 5.2 修改MAINTAINERS文件中相关内容,修改如下
F: board/freescale/mx6ul_14x14_nes_game_emmc/
F: include/configs/mx6ul_14x14_nes_game_emmc.h
F: configs/mx6ul_14x14_nes_game_emmc_defconfig
step 5.3 修改imximage.cfg文件,修改如下
PLUGIN board/freescale/mx6ul_14x14_nes_game_emmc/plugin.bin 0x00907000
step 5.4 修改Kconfig文件,修改如下
if TARGET_MX6UL_14X14_NES_GAME_EMMC
config SYS_BOARD
default "mx6ul_14x14_nes_game_emmc"
config SYS_VENDOR
default "freescale"
config SYS_CONFIG_NAME
default "mx6ul_14x14_nes_game_emmc"
step 5.5 修改Makefile,修改如下
obj-y := mx6ul_14x14_nes_game_emmc.o
step 6:修改arch/arm/mach-imx/mx6/修改Kconfig文件,修改如下
config TARGET_MX6UL_14X14_NES_GAME_EMMC------新增
bool "mx6ul_14x14_nes_game_emmc"
depends on MX6UL
select BOARD_LATE_INIT
select DM
select DM_THERMAL
select SUPPORT_SPL
select IMX_MODULE_FUSE
select OF_SYSTEM_SETUP
imply CMD_DM
select FSL_CAAM
select FSL_BLOB
select ARCH_MISC_INIT
source "board/freescale/mx6ul_14x14_nes_game_emmc/Kconfig"------新增
step 7: 修改arch/arm/dts中设备树
step 7.1: 增加imx6ul-14x14-nes-game-emmc.dts(由imx6ul-14x14-evk-emmc.dts复制修改)
修改:#include "imx6ul-14x14-nes-game.dts"
step 7.2: 增加imx6ul-14x14-nes-game.dtsi(由imx6ul-14x14-evk.dtsi复制修改)
step 7.3: 增加imx6ul-14x14-nes-game.dts(由imx6ul-14x14-evk.dts复制修改)
修改: #include "imx6ul-14x14-nes-game.dtsi"
/ {
model = "Freescale i.MX6 UltraLite 14x14 Nes_Game_Emmc Board";
compatible = "fsl,imx6ul-14x14-nes-game-emmc", "fsl,imx6ul";
};
step 7.4: 增加imx6ul-14x14-nes-game-emmc-u-boot.dtsi(由imx6ul-14x14-evk-emmc-u-boot.dtsi复制修改)
修改:: #include "imx6ul-14x14-nes-game-u-boot.dtsi"
step 7.5: 增加imx6ul-14x14-nes-game-u-boot.dtsi(由imx6ul-14x14-evk-u-boot.dtsi复制修改)
step 7.6: (optional)可在imx6ul-14x14-nes-game-emmc.dts显式增加#include "imx6ul-14x14-nes-game-emmc-u-boot.dtsi"
step 7.7: 修改Makefile,dtb-$(CONFIG_MX6UL) +=中新增imx6ul-14x14-nes-game-emmc.dtb \
step 8: 修改增加mx6ul_14x14_nes_game_emmc.h,修改如下
"findfdt="\
"if test $fdt_file = undefined; then " \
"if test $board_name = imx6ul_nes_game_emmc; then " \
"setenv fdt_file imx6ul-14x14-nes-game-emmc.dtb; fi; " \
step 9: 使用网络,只要设置如下内容即可
setenv ipaddr 192.168.1.55 //开发板 IP地址
setenv ethaddr b8:ae:1d:01:00:00 //开发板网卡 MAC地址
setenv eth1addr b8:ae:1d:01:00:01 //开发板网卡 MAC地址
setenv gatewayip 192.168.1.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.1.250 //服务器地址,也就是 服务器地址,也就是Ubuntu地址
saveenv //保存环境变量
step 10: 将SD进行分区,分区脚本如下:
#!/bin/bash
SD_CARD=/dev/sdb
echo "=========================================="
echo "SD卡一键分区脚本"
echo "目标设备: ${SD_CARD}"
echo "=========================================="
if [ "$EUID" -ne 0 ]; then
echo "请使用 sudo 运行此脚本"
exit 1
fi
echo "卸载所有分区..."
sudo umount ${SD_CARD}* 2>/dev/null
echo "创建分区表..."
sudo parted ${SD_CARD} --script mklabel msdos
echo "创建分区1(100MB FAT32)..."
sudo parted ${SD_CARD} --script mkpart primary fat32 1MiB 100MiB
echo "创建分区2(剩余空间 ext4)..."
sudo parted ${SD_CARD} --script mkpart primary ext4 100MiB 100%
echo "格式化分区1为FAT32..."
sudo mkfs.vfat -F 32 ${SD_CARD}1
echo "格式化分区2为ext4..."
sudo mkfs.ext4 ${SD_CARD}2
echo "=========================================="
echo "分区完成!"
echo "分区1: ${SD_CARD}1 (100MB FAT32)"
echo "分区2: ${SD_CARD}2 (370MB ext4)"
echo "=========================================="
step 11: 将sd卡分区1与分区2添加"777"权限
step 11.1: sudo chmod 777 /media/你的linux登录用户名/分区1对应的文件夹
step 11.2: sudo chmod 777 /media/你的linux登录用户名/分区2对应的文件夹
step 11.3: 将zImage与对应的设备树文件(xxx.dtb)复制到分区1中
step 12: 修改为由SD卡启动
step 12.1: 修改mx6ul_14x14_nes_game_emmc.h中mmcpart=1对应分区1
step 12.2: 修改mx6ul_14x14_nes_game_emmc.h中mmcroot=/dev/mmcblk0p2 rootwait rw 根文件系统指向 SD 卡 2 分区
step 12.3: 修改mx6ul_14x14_nes_game_emmc_defconfig中CONFIG_SYS_MMC_ENV_DEV=0
最近编辑记录 2074840899 (2026-05-19 01:57:12)
离线
移植步骤整体方向是对的,不过 i.MX6UL 新增板级支持时,除了文件名/TARGET 对齐,还建议重点核对 SPL、imximage 和 pinmux 这几处,否则很容易“能编译但不能启动”。
可以按这个清单再过一遍:
CONFIG_TARGET_...、defconfig 文件名、SYS_BOARD、SYS_CONFIG_NAME、board 目录名必须完全一致;
imximage.cfg 里的 DCD/PLUGIN 是否适配你自己的 DDR、电源和启动介质,不能只复制 EVK;
如果走 eMMC,确认 USDHC 的 iomux、pad 配置、供电、reset 没沿用 EVK 不匹配的管脚;
arch/arm/dts/Makefile 加了 dtb 后,确认最终编译产物里确实生成并打包了对应 dtb;
SPL 阶段如果启用,board_init_f、DDR init、clock init、watchdog 这些也要跟板子匹配;
findfdt 只影响运行时选择 dtb,不等于启动镜像里一定带了这个 dtb,最好用 dumpimage 或编译输出确认。
如果现在已经能进 U-Boot prompt,主要查 env/fdt/emmc;如果连 SPL/U-Boot 都没打印,优先查 imximage.cfg、DDR 初始化和启动介质管脚。
离线
================================================================================
SiI9022A HDMI Transmitter - U-Boot移植教程 (DM Bridge)
适用: i.MX6ULL + SiI9022A | U-Boot 2025.04 (Driver Model)
================================================================================
硬件连接 :
I2C2_SCL (UART5_TX) -> SCL (I2C addr: 0x39)
I2C2_SDA (UART5_RX) -> SDA
LCD_CLK -> PCLK
LCD_DE -> DE
LCD_HSYNC -> HSYNC
LCD_VSYNC -> VSYNC
LCD_DATA[3:7] -> D[0:7] (Blue)
LCD_DATA[10:15] -> D[8:15] (Green)
LCD_DATA[19:23] -> D[16:23] (Red)
LCD_DATA16 (GPIO3_IO21) -> RESET# (低有效)
SNVS_TAMPER3 (GPIO5_IO03) -> INT# (低有效,下降沿触发)
================================================================================
Step 1: 复制驱动文件
================================================================================
将文件替换到 U-Boot 源码:
sii902x.h -> uboot.../drivers/video/sii902x.h
sii902x.c -> uboot.../drivers/video/sii902x.c
================================================================================
Step 2: 修改 drivers/video/Makefile
================================================================================
在 lt8912b 行之后添加:
obj-$(CONFIG_VIDEO_SII902X) += sii902x.o
================================================================================
Step 3: 修改 drivers/video/Kconfig
================================================================================
在 VIDEO_LT8912B 配置项之后添加:
config VIDEO_SII902X
bool "Silicon Image SiI9022A HDMI transmitter"
depends on VIDEO
select VIDEO_BRIDGE
default n
help
Support for SiI9022A/9024A HDMI transmitter connected via I2C.
Uses UCLASS_VIDEO_BRIDGE for automatic probe via device tree.
================================================================================
Step 4: 修改 defconfig
================================================================================
文件: configs/mx6ull_14x14_nes_game_emmc_defconfig
添加:
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_CONSOLE=y
CONFIG_VIDEO_SII902X=y
CONFIG_CONSOLE_MUX=y
CONFIG_DM_VIDEO=y
================================================================================
Step 5: 修改设备树
================================================================================
文件: arch/arm/dts/imx6ull-14x14-nes-game.dts (或对应 .dtsi)
5.1 引脚配置 (与 V3 相同):
&iomuxc {
pinctrl_i2c2: i2c2grp {
fsl,pins = <
MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
;
};
pinctrl_sii902x: sii902xgrp {
fsl,pins = <
MX6UL_PAD_LCD_DATA16__GPIO3_IO21 0x10b0
MX6UL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x10b0
;
};
};
5.2 I2C2 + SiI9022A 节点 (V4 关键变化 — 包含 port/endpoint):
&i2c2 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
sii9022a: hdmi@39 {
compatible = "sil,sii902x";
reg = <0x39>;
reset-gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
/ 加上这两行!引用引脚配置 /
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sii902x>;
/ V4 新增: 视频模式选择 /
/ 1=480p 2=576p 3=720p60 4=720p50 /
/ 5=1080p60 6=1080p50 7=1024x768 8=800x600 /
/ 不设置则默认 3 (720p@60Hz) /
sil,video-mode = <3>;
/ V4 关键: port/endpoint 连接到 LCDIF /
/ 没有这个连接,video_link 框架找不到 SiI9022A /
port {
sii9022_in: endpoint {
remote-endpoint = <&lcdif_out>;
};
};
};
};
5.3 LCDIF 节点 (必须包含 port/endpoint + display-timings):
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif>;
status = "okay";
/ V4 关键: port/endpoint 连接到 SiI9022A /
/ video_link 框架通过这个连接发现 SiI9022A 桥接芯片 /
port {
lcdif_out: endpoint {
remote-endpoint = <&sii9022_in>;
};
};
display0: display@0 {
bits-per-pixel = <24>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
/ 必须与 sil,video-mode = <3> (720p@60Hz) 匹配 /
clock-frequency = <74250000>;
hactive = <1280>;
vactive = <720>;
hback-porch = <220>;
hfront-porch = <110>;
vback-porch = <20>;
vfront-porch = <5>;
hsync-len = <40>;
vsync-len = <5>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};
};
port/endpoint 连接原理:
LCDIF port.endpoint <--remote-endpoint--> SiI9022A port.endpoint
(lcdif_out) (sii9022_in)
U-Boot video_link 框架通过 remote-endpoint 建立设备链:
LCDIF → SiI9022A
LCDIF probe 时自动发现 SiI9022A,自动调用 bridge attach/set_backlight。
如果没有 port/endpoint,LCDIF 不知道 SiI9022A 的存在,HDMI 不会初始化。
显示时序来源(后续修改对应的uboot文件):
video_link 框架只从 UCLASS_PANEL / UCLASS_DISPLAY 设备读取时序,
UCLASS_VIDEO_BRIDGE (SiI9022A) 的时序会被跳过。
实际时序来源: LCDIF 节点的 display-timings。
因此 LCDIF 的 display-timings 必须与 SiI9022A 的 sil,video-mode 一致!
如果 sil,video-mode = <1> (480p), LCDIF timing 也要改为 480p 参数。
SiI9022A 节点中不需要 display-timings 子节点 (驱动不会读取它)。
================================================================================
Step 6: 设置 HDMI 控制台输出 (可选)
================================================================================
文件: /home/kdd/linux_study/linux_program/imx6ull_nes_game_uboot/board/freescale/mx6ull_14x14_nes_game_emmc/mx6ull_14x14_nes_game_emmc.c
a.函数board_late_init中最后添加
#ifdef CONFIG_VIDEO
env_set("stdout", "serial,vidconsole");
env_set("stderr", "serial,vidconsole");
#endif
b.函数board_late_init中删除(同时将setup_lcd()函数源码删除即可)
setup_lcd();
================================================================================
Step 6.1: CONFIG_SPLASH_SCREEN 与 HDMI 控制台的关系 (重要)-----不设置splashimage环境变量即可
================================================================================
CONFIG_SPLASH_SCREEN 的作用:
启用后,U-Boot 启动时显示开机 Logo (splash screen)
同时会将 stdout 重定向到串口,防止启动 log 覆盖 Logo
影响: common/console.c:1199-1202
if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
}
================================================================================
Step 7: 修改文件: drivers/video/mxsfb.c
================================================================================
修改文件: drivers/video/mxsfb.c
找到 mxs_of_get_timings() 中以下代码块 (约第 303-316 行):
priv->disp_dev = video_link_get_next_device(dev);
if (priv->disp_dev) {
ret = video_link_get_display_timings(timings);
if (ret) {
dev_err(dev, "failed to get any video link display timings\n");
return -EINVAL;
}
} else {
ret = ofnode_decode_display_timing(display_node, 0, timings);
if (ret) {
dev_err(dev, "failed to get any display timings\n");
return -EINVAL;
}
}
替换为:
priv->disp_dev = video_link_get_next_device(dev);
if (priv->disp_dev) {
ret = video_link_get_display_timings(timings);
if (ret)
debug("video link timings not found, trying display node\n");
}
if (ret || !priv->disp_dev) {
ret = ofnode_decode_display_timing(display_node, 0, timings);
if (ret)
dev_err(dev, "display node timing not found\n");
}
if (ret) {
dev_err(dev, "failed to get any display timings\n");
return -EINVAL;
}
================================================================================
Step 8: 修改文件: drivers/video/mxsfb.c
================================================================================
修改文件: drivers/video/mxsfb.c
找到 mxs_video_probe() 修改为以下代码块
static int mxs_video_probe(struct udevice *dev)
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
struct mxsfb_priv *priv = dev_get_priv(dev);
struct display_timing timings;
u32 bpp = 0;
u32 fb_start, fb_end;
int ret;
bool enable_bridge = false;
debug("%s() plat: base 0x%lx, size 0x%x\n",
__func__, plat->base, plat->size);
priv->reg_base = dev_read_addr(dev);
if (priv->reg_base == FDT_ADDR_T_NONE) {
dev_err(dev, "lcdif base address is not found\n");
return -EINVAL;
}
ret = mxs_of_get_timings(dev, &timings, &bpp);
if (ret)
return ret;
timings.flags |= DISPLAY_FLAGS_DE_HIGH;
if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
if (check_module_fused(MODULE_LCDIF)) {
printf("LCDIF@0x%lx is fused, disable it\n", (ulong)priv->reg_base);
return -ENODEV;
}
}
if (priv->disp_dev) {
#if IS_ENABLED(CONFIG_DISPLAY)
if (device_get_uclass_id(priv->disp_dev) == UCLASS_DISPLAY) {
ret = display_enable(priv->disp_dev, bpp, &timings);
if (ret) {
dev_err(dev, "fail to enable display\n");
return ret;
}
}
#endif
/*
#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
if (device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
ret = video_bridge_attach(priv->disp_dev);
if (ret) {
dev_err(dev, "fail to attach bridge\n");
return ret;
}
ret = video_bridge_set_backlight(priv->disp_dev, 80);
if (ret) {
dev_err(dev, "fail to set backlight\n");
return ret;
}
enable_bridge = true;
// sec dsim needs enable ploarity at low, default we set to high
if (!strcmp(priv->disp_dev->driver->name, "imx_sec_dsim"))
timings.flags &= ~DISPLAY_FLAGS_DE_HIGH;
}
#endif
if (device_get_uclass_id(priv->disp_dev) == UCLASS_PANEL) {
ret = panel_enable_backlight(priv->disp_dev);
if (ret) {
dev_err(dev, "panel %s enable backlight error %d\n",
priv->disp_dev->name, ret);
return ret;
}
}
}
ret = mxs_probe_common(dev, &timings, bpp, plat->base, enable_bridge);
*/
#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
if (device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
ret = video_bridge_attach(priv->disp_dev);
if (ret) {
dev_err(dev, "fail to attach bridge\n");
return ret;
}
//ret = video_bridge_set_backlight(priv->disp_dev, 80);
//if (ret) {
// dev_err(dev, "fail to set backlight\n");
// return ret;
//}
enable_bridge = true;
// sec dsim needs enable ploarity at low, default we set to high
if (!strcmp(priv->disp_dev->driver->name, "imx_sec_dsim"))
timings.flags &= ~DISPLAY_FLAGS_DE_HIGH;
}
#endif
if (device_get_uclass_id(priv->disp_dev) == UCLASS_PANEL) {
ret = panel_enable_backlight(priv->disp_dev);
if (ret) {
dev_err(dev, "panel %s enable backlight error %d\n",
priv->disp_dev->name, ret);
return ret;
}
}
}
ret = mxs_probe_common(dev, &timings, bpp, plat->base, enable_bridge);
if (ret)
return ret;
#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
/ LCDIF已启动,现在配置SiI9022A /
if (priv->disp_dev && device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
ret = video_bridge_set_backlight(priv->disp_dev, 80);
if (ret) {
dev_err(dev, "fail to set backlight\n");
return ret;
}
}
#endif
switch (bpp) {
case 32:
case 24:
case 18:
uc_priv->bpix = VIDEO_BPP32;
break;
case 16:
uc_priv->bpix = VIDEO_BPP16;
break;
case 8:
uc_priv->bpix = VIDEO_BPP8;
break;
default:
dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp);
return -EINVAL;
}
uc_priv->xsize = timings.hactive.typ;
uc_priv->ysize = timings.vactive.typ;
/ Enable dcache for the frame buffer /
fb_start = plat->base;
fb_end = plat->base + plat->size;
mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
DCACHE_WRITEBACK);
video_set_flush_dcache(dev, true);
return ret;
}
离线