)
1 RK3568框图阅读模块框图能够帮我快速建立整体系统框架。我个人理解是懂得越多你面对一个系统框图越能快速的绘制出它的整个神经脉络掌握系统的数据流图。访问地址https://www.rock-chips.com/uploads/pdf/2022.8.26/191/RK3568%20Brief%20Datasheet.pdf硬件IP处理器相关CPUNPUMulti-Media ProcessVPUISPGPU高速外设低速外设高速存储总线AXI高速高带宽设备接入到AXI矩阵中AXI Lite寄存器配置数据流接入到AXI Lite总线AXI to AHB BridgeAHB总线协议AXI to APB BridgeAPB总线协议2 启动顺序基本概念概述U-BootTPLSPLU-Boot嵌入式系统的开源引导加载程序负责在芯片上电后初始化硬件设备尤其是DDR内存并加载启动操作系统内核。由于太大无法被BootROM一次性加载于是分成了多级boot包括TPLVPLSPLTPLTertiary Program Loader。作用是初始化DDR内存VPLVerifying Program Loader。作用是运行安全启动流程SPLSecondary Program Loader。作用是初始化硬件并加载U-Bootddr.bin在RK中指的是TPLminiloader.bin在RK中指的是SPLMiniLoaderAll.bin在RK中是TPL SPL存储器角度BootROM - SRAM(TPL) - SRAM(SPL) - DDR(Uboot) - DDR(Kernel)镜像角度Maskrom - Pre-loader - Trust - U-Boot - Kernel镜像角度next-dev版本MiniloaderAll.bin TPL SPLBootROM - TPLddr.bin - SPLminiloader.bin - U-Boot - Kernel镜像角度rkdevelop版本BootROM - ddr.bin - miniloader.bin - U-Boot - Kernel3 目录- BootROM启动负责加载TPL - TPL开源U-Boot中的功能主要功能是DDR初始化。运行在SRAM中。闭源版本是RK提供的rkxxx_ddr_xxMHz_Version.bin开源版本在编译U-Boot源码版本是生成 - SPL开源U-Boot中的功能主要功能是加载和引导trust/U-Boot两个模块。运行在DDR中 - Uboot - Kernel4 BootROM启动关键概念概述BootROM存储RK3568芯片上电后执行的第一个程序。硬件设计强制CPU从0xFFFF000读取第一条指令。CPU通过AXI总线访问BootROM0xFFFF0000在Address Mapping小节中提到0xFFFF0000可以被两个SRAM重映射 - PMU_SRAM使用在低功耗场景下运行一些程序和SYSTEM_SRAM。刚上电的时候默认的状态是BootROM被映射到0xFFFF0000ID BLOCKIdentification Block对应固件idbloader.img是瑞芯微RK全系列芯片专属的一级引导头预加载程序块是BootROM识别合法启动固件的唯一标识载体包含魔数固件校验和芯片平台安全启动签名地址映射虚拟地址MMU启动后CPU访问的是虚拟地址物理地址MMU启动前CPU直接使用物理地址访问BootROM、SRAM等启动方式存储遍历加载镜像: SPI NOR Flash - SPI NAND Flash - NAND Flash - eMMC - SD卡USB OTG下载镜像执行方式RK3568 BootROM执行流程图访问地址https://opensource.rock-chips.com/images/2/26/Rockchip_RK3568_TRM_Part1_V1.3-20220930P.PDF启动流程概述CPU上电从0xFFFF0000读取第一条指令去运行按照SPI NOR Flash - SPI NAND Flash - NAND Flash - eMMC - SD卡的顺序读取ID BLOCK并校验校验通过按顺序读取镜像并运行加载SDRAM初始化镜像加载DDR初始化镜像加载boot镜像4.1 ID Blockidblock.binidbloader.img4.1.1 ID Block的组成: 结合源码说明打包脚本: u-boot\make.sh./tools/mkimage -n ${PLAT} -T rksd -d ${TPL_BIN}:${SPL_BIN} idblock.binuboot\tools\mkimage: u-boot\tools\mkimage.cRockchip四种镜像主要是头部信息不同IH_TYPE_RKIMAGE: mkimage.c中没有涉及IH_TYPE_RKSD: SD/MMC卡启动镜像IH_TYPE_RKSPI: SPI Flash启动镜像IH_TYPE_RKNAND: NAND Flash启动镜像不同的存储介质特性对应不同的镜像文件填写头部数据根据存储器特性填写bin文件数据RKSD: idblock.bin tpl.bin spl.bin数据分布2KB头部 TPL SPL2KB头部存在不同版本的差异。头部记录魔数引导程序的位置等信息写入TPL数据2KB对齐填充写入SPL数据2KB对齐填充尾部填充struct image_entry { uint32_t size_and_off; //大小和扇区位置 uint32_t address; uint32_t flag; uint32_t counter; uint8_t reserved[8]; uint8_t hash[64]; //哈希值 }; struct header0_info_v2 { uint32_t magic; //魔数 uint8_t reserved[4]; uint32_t size_and_nimage; //镜像数和 uint32_t boot_flag; uint8_t reserved1[104]; struct image_entry images[4]; //镜像入口信息 uint8_t reserved2[1064]; uint8_t hash[512]; }; struct header0_info { uint32_t magic; uint8_t reserved[4]; uint32_t disable_rc4; uint16_t init_offset; uint8_t reserved1[492]; uint16_t init_size; uint16_t init_boot_size; uint8_t reserved2[2]; };4.2 TPLTertiary Program Loader开源集成在U-Boot源码中闭源RK3568以ddr.bin的二进制文件形式提供4.3 SPLSecondary Program Loader开源集成在U-Boot源码中闭源RK3568以spl.bin的二进制文件形式提供4.4 BootROM启动总结BootROM32KB的作用是在存储器中加载TPL到SRAM64KB中运行TPL的作用是初始化DDR内存解决SRAM空间不足无法运行SPL或U-Boot问题为什么不直接在Flash中运行比如NOR Flash因为慢效率低因为性价比低容量小价格高SPL的作用是完成U-Boot运行前的硬件初始化工作加载U-Boot到DDR内存中并将控制权移交给它U-Boot的作用是准备Kernel运行的硬件环境加载Kernel到内存中运行5 TPLDDR初始化- uboot源码仓库https://github.com/rockchip-linux/u-boot.git5.1 DDR内存基于物质基础分析DDR内存组成DDR3/DDR3L/DDR4LPDDR3/LPDDR4/LPDDR4X外部引脚数据输入输出地址/命令控制时钟校准电源详细信息类型DDR3/DDR3L/DDR4LPDDR3/LPDDR4/LPDDR4X频率内存芯片内部时钟的实际运行频率通道信息一个独立的完整数据通道包含自己的数据、地址、命令和控制信号总线数据位宽行数量每个Bank内部存储单元按行和列排列成一个矩阵。寻址一个存储单元需要先指定行再指定列列数量行地址和列地址分时复用同一组地址信号线bank数量DDR颗粒内部被划分为多个独立的存储块可以并行访问以提高速率片选数量选择当前于控制器通信的特点颗粒或颗粒组单颗颗粒的数据位宽每个颗粒一次能输入/输出的数据位数单个通道的DDR总容量5.2 DMCDDR内存控制器集成在SoC上/*DDR性能监控模块DFIDDR Performance Monitor*/ dfi: dfife230000 { reg 0x00 0xfe230000 0x00 0x400; compatible rockchip,rk3568-dfi; rockchip,pmugrf pmugrf; status disabled; }; /*频率属性是可操作性最高的属性*/ dmc: dmc { compatible rockchip,rk3568-dmc; interrupts GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH; interrupt-names complete; devfreq-events dfi, nocp_cpu; clocks scmi_clk 3; clock-names dmc_clk; operating-points-v2 dmc_opp_table; vop-bw-dmc-freq ... ; vop-frame-bw-dmc-freq ... ; cpu-bw-dmc-freq ... ; upthreshold 40; downdifferential 20; system-status-level ... ; auto-min-freq 324000; auto-freq-en 1; #cooling-cells 2; status disabled; }; /*FSPFrequency Scaling Policy频率缩放策略定义不同频率下的时序参数*/ dmc_fsp: dmc-fsp { compatible rockchip,rk3568-dmc-fsp; debug_print_level 0; ddr3_params ddr3_params; ddr4_params ddr4_params; lpddr3_params lpddr3_params; lpddr4_params lpddr4_params; lpddr4x_params lpddr4x_params; status okay; }; /*定义DDR可用的频率和电压的组合*/ dmc_opp_table: dmc-opp-table { compatible operating-points-v2; mbist-vmin 825000 900000 950000; nvmem-cells log_leakage, ... ; ... /* RK3568 dmc OPPs */ opp-1560000000 { opp-supported-hw 0xf9 0xffff; opp-hz /bits/ 64 1560000000; opp-microvolt 900000 900000 1000000; ... }; opp-j-m-1560000000 { opp-supported-hw 0x06 0xffff; opp-hz /bits/ 64 1560000000; opp-microvolt 875000 875000 1000000; }; ... };5.3 DDR初始化都做了哪些工作提示词请分别从物质决定意识的哲学角度和电子信息角度介绍DDR初始化都做了哪些工作物质决定意识物质是第一性意识是第二性物质世界DDR颗粒PCB走线: 走线长度差DMC供电: 电源波纹时钟阻抗意识世界DDR初始化程序DDR初始化程序的所有操作都是适配硬件物质通过可编程的逻辑去拟合不可编程的物理链路将模式世界混沌转变为数字世界的确定性上电、供电稳定与硬件复位阻抗匹配、VTT端接、时钟训练物质世界PCB走线存在寄生电容、寄生电阻、传输效应DDR差分时钟、地址数据线高速传输会产生信号反射、串扰、时序偏移VTT分压电阻、终端电阻是固定硬件物质不同内存插槽不同批次DDR颗粒的驱动能力输入电容存在客观差异意识世界ZQ校准(对抗物理离散性)芯片温度上升导致电阻变化, 驱动能力下降ZQ校准周期性执行DDR内部有一个可变电阻阵列, 会对外部240欧姆精密参考电阻, 通过逐次逼近调整输出驱动器的阻抗对抗芯片制造工艺的偏差和实时温度变化保证输出高/低电平的电压幅值在标准范围内CLK时钟训练解决走线不等长造成的时钟相位偏移解决信号反射、衰减导致的采样窗口变窄DQS数据选通同步训练写通路控制器内部增加延迟控制DDR端CLK上升沿与DQS边沿精准对齐读通路调整控制器内部采样窗口延迟在DQS眼图最开阔位置抓取DQ数据保证读写采样裕量Write Leveling补偿 CPU 内存控制器到 DDR 颗粒之间 CLK 时钟与 DQS 数据选通线的走线长度差。模式寄存器 MRS 配置物质世界MRS 是 DDR 颗粒内部的硬件寄存器存储时序、突发长度、CL/CWL、电压模式、自刷新、读写驱动强度等核心参数意识世界初始化代码发送 MRS 指令往颗粒内置硬件寄存器写入时序、频率、突发长度、刷新周期等配置值据读取到的 SPD 芯片硬件存储介质物质内固化的厂商参数自动匹配合规时序Read Leveling Eye TrainingMRS 写入 CL/CWL、驱动强度、突发长度等基础时序后才能发起读写测试波形意识世界Read Leveling调整 DQS 采样延迟匹配内存颗粒回传数据与控制器采样时钟的相位Eye Training眼图训练精细化扫描采样窗口找出信号最干净、无串扰反射的采样点最大化时序裕量行 / 列寻址、Bank、Rank 拓扑初始化物质世界DDR 内部由 Bank 阵列、行存储单元、列电容阵列组成物理硬件结构多内存条构成多 Rank、多通道拓扑通道间走线长度、颗粒数量是 PCB 与内存条固定的物质布局意识世界初始化代码读取 SPD 识别 Rank 数量、Bank 数量、行列地址位数配置内存控制器地址译码逻辑配置周期性自刷新周期补偿电容漏电的物理缺陷划分通道独立控制逻辑匹配多内存条硬件拓扑内存自检、ECC 初始化、地址掩码校验物质世界存储电容存在漏电、高低温下晶体管出错、数据线存在随机干扰硬件物质本身存在出错可能性ECC 内存额外带校验存储颗粒意识世界初始化执行内存读写遍历测试向全部物理存储单元写入测试数据再读出对比检测硬件单元损坏若为 ECC 内存初始化启用校验硬件通路配置纠错逻辑设置地址掩码屏蔽硬件损坏的存储块关闭初始化、开放内存地址空间所有电气、时序、寻址、校验参数匹配硬件物质特性后内存控制器退出初始化流程把 DDR 物理存储地址映射给 CPU 系统总线操作系统即可读写内存硬件5.4 TPL源码以RK3568为例源码位置u-boot\arch\arm\mach-rockchip\tpl.c执行流程BootROM 启动 │ ▼ board_init_f() ← TPL 入口 │ ├── rockchip_stimer_init() ── 初始化系统定时器 ├── arch_cpu_init() ── CPU 初始化(空可覆盖) ├── debug_uart_init() ── 初始化调试串口 ├── 打印 TPL 版本信息 ├── spl_early_init() ── SPL 早期初始化(DM) ├── timer_init() ── ARM 架构定时器 ├── DRAM 初始化 ── 初始化 DDR 内存 │ ├── [DM模式] uclass_get_device(UCLASS_RAM) │ └── [精简模式] sdram_init() │ ▼ back_to_bootrom(BROM_BOOT_NEXTSTAGE) ── 返回 BootROM 加载 SPL │ ▼ SPL 阶段启动uclass_get_device通过device_probe完成硬件初始化从设备树中获取DMC节点根据节点中的参数完成DRAM初始化sdram_initu-boot\arch\arm\mach-rockchip\rk3066\sdram_rk3066.csdram_init()DMC控制器初始化 │ ├── ① 频率检查 ├── ② 设置 DDR 时钟clk_set_rate() ├── ③ PHY 控制器复位phy_pctrl_reset() ├── ④ DLL 旁路配置(按频率)phy_dll_bypass_set()根据频率配置DLL(延迟锁定环)旁路。DDL的作用是生成精确的、与时钟同步的时序信号。 ├── ⑤ DFI 接口配置dfi_cfg()配置 DFI (DDR PHY Interface)接口 ├── ⑥ 控制器时序配置pctl_cfg()配置控制器时序 ├── ⑦ PHY 参数配置phy_cfg() ├── ⑧ PHY 初始化触发phy_init() ├── ⑨ DDR 上电 ├── ⑩ DRAM 初始化序列memory_init() ├── ⑪ 切换到 CONFIG 状态move_to_config_state() ├── ⑫ 设置初始参数(32bit/双Rank/ZQ)32bit 位宽、双 Rank、ZQ 校准参数 ├── ⑬ Rank 位宽自动检测自动检测 Rank 和位宽 ├── ⑭ 切换到 ACCESS 状态move_to_access_state()切换到访问状态 ├── ⑮ 行列地址自动检测sdram_col_row_detect() ├── ⑯ NIU 配置表查找sdram_get_niu_config() └── ⑰ 写入全局配置到 PMUdram_all_config()6 SPLSecondary Program Loader物质决定意识物质世界DDR内存CPU存储外设eMMC/SDNANDSPI Nor/NAND意识世界完成最小硬件初始化把U-Boot加载到内存中安全启动链如果编译过程中没有定义TPL则SPL会完成DDR的初始化编译配置基础支持CONFIG_SPL_LIBCOMMON_SUPPORTCONFIG_SPL_LIBGENERIC_SUPPORTCONFIG_SPL_SERIAL_SUPPORTCONFIG_SPL_DRIVERS_MISC_SUPPORCONFIG_SPL_LIBDISK_SUPPORTCONFIG_SPL_BOARD_INITCONFIG_SPL_SEPARATE_BSS内存与存储介质支持CONFIG_SPL_NAND_SUPPORTCONFIG_SPL_SPI_FLASH_SUPPORTCONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITIONCONFIG_MTD镜像格式与加载方式支持CONFIG_FITCONFIG_SPL_RAW_IMAGE_SUPPORT is not set禁用RAW镜像也就是无头的纯二进制指令和代码CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set安全启动与校验CONFIG_SPL_SHA256_SUPPORTCONFIG_SPL_CRYPTO_SUPPORTCONFIG_SPL_HASH_SUPPORTCONFIG_SPL_ATFCONFIG_FIT_HW_CRYPTOCONFIG_SPL_FIT_HW_CRYPTODDR内存相关CONFIG_DM_DMCCONFIG_ROCKCHIP_DMC_FSPCONFIG_RAMCONFIG_SPL_RAMCONFIG_TPL_RAMCONFIG_ROCKCHIP_SDRAM_COMMONCONFIG_ROCKCHIP_TPL_INIT_DRAM_TYPE0DDR初始化已经由TPL完成调试与优化功能分析管理DDR内存加载并校验UBoot加载并校验ATF安全固件6.1 板级SPL源码u-boot\arch\arm\mach-rockchip\spl.c执行流程board_init_f() ← SPL 入口 │ ├── ① 保存启动标志 ├── ② 初始化系统定时器 ├── ③ 初始化调试串口 ├── ④ 记录启动 tick ├── ⑤ PCIe EP 初始化可选 ├── ⑥ SPL 早期初始化 (DM/控制台) ├── ⑦ [无 TPL] DRAM 初始化 ├── ⑧ 控制台初始化 ├── ⑨ BootROM 下载模式检测 ├── ⑩ CPU 初始化 ├── ⑪ 板级初始化 ├── ⑫ [PCIe] 获取固件 └── ⑬ 返回 BootROM 加载下一阶段 │ ▼ SPL 框架继续执行 → spl_boot_device() 确定启动源 → 加载镜像 → spl_board_init() ├── 点亮 LED ├── 板级特定初始化 └── [可选] 返回 BootROM → spl_next_stage() 决策 ├── SPL_NEXT_STAGE_KERNEL → 直接启动内核 └── SPL_NEXT_STAGE_UBOOT → 加载 U-Boot → spl_board_prepare_for_jump() ├── 写入回滚版本到 OTP └── 硬件解压缩清理 → 跳转到下一阶段关键模块下一阶段决策spl_rockchip_dnl_key_pressed()检测音量上键是否按下用于强制进入下载模式spl_is_low_power()通过 Fuel Gauge电量计检测电池电压是否过低spl_next_stage()决定 SPL 的下一阶段是 U-Boot普通启动还是直接启动 Kernel快速启动音量上键按下强制进入 U-Boot可用于刷机电量过低低电量时进入 U-Boot 处理BOOT_COLD/PANIC/WATCHDOG/NORMAL/RECOVERY冷启动、Panic 后重启等场景直接启动内核其他启动模式REBOOT_FLAG未设置直接启动内核REBOOT_FLAG已设置进入U-Boot分区选择spl_kernel_partition()从 MISC 分区读取 BCBBootloader Control Block消息若BCB命令为“boot-recovery返回PART_RECOVERY恢复分区否则根据启动模式寄存器的值判断是从恢复分区启动还是普通分区启动FIT 回滚保护6.2 通用SPL源码u-boot\common\spl\spl.c- 规定了 SPL 的标准执行流程初始化 → 获取启动设备 → 加载镜像 → 跳转 - 定义了大量的 __weak函数接口供板级代码实现 - 实现了镜像解析、加载、跳转的通用逻辑执行流程board_init_f() (板级) │ └── spl_early_init() └── spl_common_init(true) ├── spl_dcache_enable() ← 模块6 ├── bootstage_init() ← 模块7 ├── fdtdec_setup() ← 模块7 └── dm_init_and_scan() ← 模块7 └── spl_setup_relocate() ← 模块8 board_init_r() (板级 → 此文件的 board_init_r) │ ├── spl_initr_dm() ← 模块11 ├── spl_set_bd() ← 模块9 ├── 完整 malloc 初始化 ├── spl_init() ← 模块9 ├── timer_init() ├── spl_board_init() │ ├── board_boot_order() ← 模块10 ├── spl_next_stage() ← 模块1 │ ├── boot_from_devices() ← 模块10 │ ├── spl_ll_find_loader() ← 模块10 │ └── spl_load_image() ← 模块10 │ └── loader-load_image() │ ├── spl_perform_fixups() ← 模块1 │ └── 跳转分支 ├── IH_OS_U_BOOT → jump_to_image_no_args() ├── IH_OS_ATF → spl_invoke_atf() ├── IH_OS_OPTEE → spl_optee_entry() └── IH_OS_LINUX → jump_to_image_linux() 跳转前 spl_cleanup_before_jump() ← 模块16 ├── spl_board_prepare_for_jump() ├── disable_interrupts() ├── icache_disable() / dcache_disable() └── 打印启动耗时关键模块SPL地址空间u-boot\include\configs\rk3568_common.hCONFIG_SPL_TEXT_BASE0x00000000CONFIG_SPL_MAX_SIZE0x00040000CONFIG_SPL_BSS_START_ADDR0x03fe0000CONFIG_SPL_STACK0x03fe0000CONFIG_SYS_INIT_SP_ADDR0x00c00000CONFIG_SYS_LOAD_ADDR0x00c00800把栈空间从SRAM搬到DRAMspl_relocate_stack_gd()board_init_f()在SRAM的栈中运行board_init_r()需要更多的栈空间比如MMC子系统于是搬移到SDRAM中镜像加载boot_from_devicesU-Boot镜像加载地址FIT镜像CONFIG_SPL_LOAD_FIT_ADDRESSRAW镜像CONFIG_SYS_TEXT_BASELegacy格式镜像image_get_load()从镜像头中读取Linux内核镜像加载地址CONFIG_SYS_LOAD_ADDR镜像加载驱动spl_boot_list记录了可以启动的设备列表BOOT_DEVICE_MMC1(eMMC)BOOT_DEVICE_MMC2(SD卡)BOOT_DEVICE_SPI(SPI Flash)根据设备类型获取对应的加载镜像的驱动调用驱动完成镜像加载获取加载地址设备树地址程序入口地址跳转路径U-BootATF通过ATF再跳转U-BootOP-TEE通过OP-TEE跳转到U-Boot或KernelKernelU-Boot- 关键函数board_init_f()和board_init_r() - 指导文档Rockchip_Developer_Guide_UBoot_Nextdev_CN.pdf参考博文存储角度理解启动流程https://blog.csdn.net/weixin_43390831/article/details/163141252?spm1011.2415.3001.5331TPLSPLUBoot实战https://blog.csdn.net/weixin_43390831/article/details/163174044?spm1011.2415.3001.5331UBoot实战https://blog.csdn.net/weixin_43390831/article/details/163573548?spm1011.2415.3001.5331Kernel- 操作系统进程管理内存管理文件系统设备管理问题锚点DDR内存结构对于一个硬件IP需要考虑的组成供电时钟寄存器输入输出中断如果从这些角度去考虑DDR是什么样的结构图从内存的本质功能结合结构图去考虑DDR初始化过程需要一篇详细介绍DDR内存的博文多设备树场景下的镜像匹配问题如何理解返回BootROM行为如何理解SPL的跳转决策快速启动一般用于什么场景关于安全跳转在RK3568和GD32芯片的使用过程中在跳转到另一个镜像去执行时通常都需要关闭中断在复杂的SoC中还包含了D-Cache清理避免新镜像程序执行时读取到脏数据MMU关闭使用新的虚拟地址空间关闭中断时为了防止跳转过程中被打断如何理解多处理器引导A/B分区recover分区和普通分区问题