1.背景
1.1 全志的SPL头部结构简述
| SPL位于以eMMC起始的0x2000偏移,特征如下: | 偏移 | HEX(小端) | 描述 |
|---|---|---|---|
0x0 |
BE 02 00 EA | ARM跳转指令 | |
0x4 |
65 47 4F 4E 2E 42 54 30 | SPL魔数头(eGON.BT0) | |
0xC |
4字节 | checksum(校验和) | |
0x10 |
4字节 | SPL镜像长度(字节) |
DRAM初始化参数存储在 string_pool 区域(偏移0x2C~0x5F),具体布局由 struct dram_para 定义(见 dram_sun50i_a133.h),关键参数偏移如下(相对于SPL起始): |
参数 | 偏移 | 长度 | 描述 |
|---|---|---|---|---|
clk |
0x38 | ? | clk(DRAM频率) | |
para0 |
0x40 ? | ? | - | |
para1 |
0x50~0x51 | 2字节 | 行/列地址配置(低4位列地址,bit4-7行地址) | |
para2 |
0x54~0x57 | 4字节 | 高16位表示容量(MB),低16位暂未知 | |
tpr13 |
0xB0~0xB3 | 4字节 | 控制位,bit0=1时禁用自动扫描,使用静态参数 |
1.2 容量计算原理
在 dram_libdram_sun50iw10p1.c 中,容量由以下公式决定:
- 行地址位数 = (
para1>> 4) & 0xFF - 列地址位数 =
para1& 0xF - 总容量 = 2^(
行位数+列位数+其他) *总线宽度等1.3 自动扫描
在全志 A133 平台的 DRAM 初始化代码(
dram_libdram_sun50iw10p1.c)中,有一段逻辑根据tpr13的最低 bit 决定是否启用自动扫描:if ((para->tpr13 & 1) == 0 && !libdram_auto_scan_dram_config(para)) { debug("auto_scan_dram_config: failed\n"); return false; //在主线U-Boot中,该函数并不真正执行扫描 } - 当
tpr13的 bit0 (最低位) = 0 时,会调用libdram_auto_scan_dram_config(para)尝试自动检测并调整 DRAM 参数。 - 当
bit0 = 1时,跳过自动扫描,直接使用静态参数(即 SPL 中预置的dram_para值)2.实践
2.1 读取并定位
全志设备eMMC的前36M为保留区域,包含了SPL和Uboot还有GPT头部,不要尝试使用parted的修复GPT备份表功能,这会直接损坏SPL头部范围,也不要尝试在强安全启动的设备上进行修改(TOC0.GLH),任何更改都需要重新计算校验和(checksum) SPL位于以eMMC起始的0x2000偏移,并且有明显的跳转指令和魔数头特征,长度一般默认为48Kbyte(0x2000~0xDFFF)
2.2 修改DRAM_para
对于修改原始固化的1G DRAM参数为2G时
- 1GB配置:
para1=0x30ea→ 行位数=0x0E(14),列位数=0xA(10) - 2GB配置:
para1=0x30fa→ 行位数=0x0F(15),列位数=0xA(10)(行地址增加1位,容量翻倍) 同时,para2的高16位直接反映容量(MB):1GB为0x0400,2GB为0x0800。低16位不可修改,用于配置其他硬件特性2.3 尝试启用自动扫描(不一定有效)
自动扫描由
tpr13参数的 bit0 控制。当 bit0 =时启用自动扫描;bit0 =1时使用静态参数(默认值) - 假设原始
tpr13值为0x00006063(小端存储在 SPL 文件偏移0xB0~0xB3为63 60 00 00,二进制为0110 0000 0110 0011) - 将偏移
0x6A的字节从0x63改为0x62,使tpr13变为0x00006062(bit0 = 0,二进制为0110 0000 0110 0010)2.4 尝试修改DRAM时钟
clk位于偏移0x38~0x3B,使用16进制直接存储频率参数,实践修改后生效,但是可能需要同时修改部分时序参数(如tRFC、tREFI),目前实践修改过后可能会造成内存训练不通过,由于试错成本较高且收益有限便没有继续深入研究[184]DRAM CLK =984 MHZ [186]DRAM Type =8 (3:DDR3,4:DDR4,7:LPDDR3,8:LPDDR4) [194]DRAM SIZE =2048 MBytes, para1 = 30fa, para2 = 8001000, dram_tpr13 = 6063 [202]dram_tpr11 = 29261f27,dram_tpr12 = 14151513 [208]DRAM simple test FAIL-----1dc4567 != 1234567 at address 40000000其中984 Mhz已经在DragonHD中确认可以稳定使用,实际情况初步怀疑是时序和驱动强度等问题
2.5 重新计算校验和
全志eGON头部校验和算法(参考
sunxi_egon.c):
- 将头部偏移0x0C~0x0F的4字节临时写入固定值
0x5F0A6C39 - 以4字节为单位,对整个SPL镜像(长度由头部0x10~0x13指定,本例为0xC000)进行32位累加
- 将累加和(截断为32位)以小端序写回头部0x0C~0x0F
一个简单的python用于更新校验和:
import struct BROM_STAMP = 0x5f0a6c39 SPL_FILE = "spl.bin" with open(SPL_FILE, "r+b") as f: data = bytearray(f.read()) old_checksum = data[0x0C:0x10].hex() # 将校验和字段临时设为 BROM_STAMP(小端) data[0x0C:0x10] = struct.pack("<I", BROM_STAMP) # 以4字节为单位累加整个镜像(小端序) checksum = 0 for i in range(0, len(data), 4): word = struct.unpack("<I", data[i:i+4])[0] checksum = (checksum + word) & 0xFFFFFFFF # 将新校验和写回 data[0x0C:0x10] = struct.pack("<I", checksum) # 写回文件 f.seek(0) f.write(data) print(f"旧校验和: {old_checksum}") print(f"新校验和: {struct.pack('<I', checksum).hex()}")参考项目:GitHub - aodzip/u-boot-2022.10-Allwinner-A133: Playground for myself by:Sui2786

Comments NOTHING