全志A133更改DRAM_para部分重定义DRAM容量

SoraNeko 发布于 2026-04-29 131 次阅读


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中,该函数并不真正执行扫描
    }
  • tpr13bit0 (最低位) = 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~0xB363 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进制直接存储频率参数,实践修改后生效,但是可能需要同时修改部分时序参数(如 tRFCtREFI),目前实践修改过后可能会造成内存训练不通过,由于试错成本较高且收益有限便没有继续深入研究

    [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):

  1. 将头部偏移0x0C~0x0F的4字节临时写入固定值 0x5F0A6C39
  2. 以4字节为单位,对整个SPL镜像(长度由头部0x10~0x13指定,本例为0xC000)进行32位累加
  3. 将累加和(截断为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

此作者没有提供个人介绍。
最后更新于 2026-05-01