301fc08890
Previous commit committed sibling claims without verifying against
the TRM bit tables. Verification fails for d328:
Sibling: +0x110 = CAL_RD_VWML0 (from TRM §2.4.3).
Blob: writes 0xF000F000 to that offset.
TRM: CAL_RD_VWML0 is READ-ONLY, bits[9:0]=rd_vwml0 code, [25:16]=rd_vwml1.
Writing is a no-op.
Root cause of sibling's error: conflated 'DDRPHY_OPB + offset' with
d328's 'DDRPHY_OPB + 0x8000 + offset'. The +0x8000 sub-block is NOT
documented in the TRM; offsets 0x110/0x118/0x120/0x154/0x160/0x184
WITHIN that sub-block mean something different from CAL_RD_VWML0 etc.
Kept the TRM-verified names I DID check:
- DDRCTL_DFISTAT @ +0x10514 (site 3)
- DDRCTL_STAT @ +0x10014 (sites 2,4,5,7)
- DDRPHY_SCHD_TRAIN_CON0 @ +0xa24 — bit layout verified directly
Retracted names for d328's +0x8XXX accesses; restoring the PHY_CTL_110
etc. RE-guess labels as the safe fallback. True names remain unknown
until we get hardware-trace data or the Synopsys DWC PUB databook.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
200 lines
11 KiB
C
200 lines
11 KiB
C
/* RK3588 DDR Init Blob - Annotated MMIO Register Map
|
|
* Cross-referenced with TRM Part 2 and kernel sources
|
|
*/
|
|
|
|
/* === Blob-internal data tables (not MMIO) === */
|
|
/* 0x0001xxxx - timing params, DDR config tables within the binary */
|
|
/* 0x001Fxxxx - likely shared memory / mailbox area */
|
|
|
|
/* === PMU1 GRF (0xFD588000) === */
|
|
#define _DAT_fd588080 REG32(0xFD588080) /* PMU1_GRF: DDR status/config */
|
|
|
|
/* === DDR GRF CH2 (0xFD598000) === */
|
|
#define _DAT_fd59800c REG32(0xFD59800C) /* DDR_GRF_CH2: channel config */
|
|
|
|
/* === BUS GRF (0xFD5F4000 / 0xFD5F8000) === */
|
|
/* BUS_IOC or DDR-related bus fabric config - 27 registers */
|
|
#define _DAT_fd5f4000 REG32(0xFD5F4000) /* BUS_GRF: base config */
|
|
#define _DAT_fd5f400c REG32(0xFD5F400C) /* BUS_GRF: status */
|
|
/* 0xFD5F8000-0xFD5F809C: Dense register block - DDR bus interconnect */
|
|
/* These control AXI fabric, QoS, and DDR routing */
|
|
#define _DAT_fd5f800c REG32(0xFD5F800C) /* bus_grf: DDR route cfg */
|
|
#define _DAT_fd5f8018 REG32(0xFD5F8018)
|
|
#define _DAT_fd5f8020 REG32(0xFD5F8020)
|
|
#define _DAT_fd5f8028 REG32(0xFD5F8028)
|
|
#define _DAT_fd5f802c REG32(0xFD5F802C)
|
|
#define _DAT_fd5f8030 REG32(0xFD5F8030)
|
|
#define _DAT_fd5f8038 REG32(0xFD5F8038)
|
|
#define _DAT_fd5f8044 REG32(0xFD5F8044)
|
|
#define _DAT_fd5f804c REG32(0xFD5F804C)
|
|
#define _DAT_fd5f8050 REG32(0xFD5F8050)
|
|
#define _DAT_fd5f8054 REG32(0xFD5F8054)
|
|
#define _DAT_fd5f805c REG32(0xFD5F805C)
|
|
#define _DAT_fd5f8060 REG32(0xFD5F8060)
|
|
#define _DAT_fd5f8068 REG32(0xFD5F8068)
|
|
#define _DAT_fd5f806c REG32(0xFD5F806C)
|
|
#define _DAT_fd5f8070 REG32(0xFD5F8070)
|
|
#define _DAT_fd5f8074 REG32(0xFD5F8074)
|
|
#define _DAT_fd5f8078 REG32(0xFD5F8078)
|
|
#define _DAT_fd5f807c REG32(0xFD5F807C)
|
|
#define _DAT_fd5f8080 REG32(0xFD5F8080)
|
|
#define _DAT_fd5f8084 REG32(0xFD5F8084)
|
|
#define _DAT_fd5f8088 REG32(0xFD5F8088)
|
|
#define _DAT_fd5f808c REG32(0xFD5F808C)
|
|
#define _DAT_fd5f8098 REG32(0xFD5F8098)
|
|
#define _DAT_fd5f809c REG32(0xFD5F809C)
|
|
|
|
/* === PMU CRU / Secure CRU (0xFD8C8000) === */
|
|
/* Clock gate and reset controls for DDR subsystem */
|
|
#define _DAT_fd8c8004 REG32(0xFD8C8004) /* SCRU: DDR clock gate */
|
|
#define _DAT_fd8c8008 REG32(0xFD8C8008) /* SCRU: DDR reset */
|
|
#define _DAT_fd8c8014 REG32(0xFD8C8014) /* SCRU: DPLL config */
|
|
#define _DAT_fd8c8018 REG32(0xFD8C8018) /* SCRU: DPLL status */
|
|
|
|
/* === DDRC CH0 (0xFE010000) === */
|
|
/* Synopsys UMCTL2 registers - only 4 accessed directly */
|
|
#define _DAT_fe0100f0 REG32(0xFE0100F0) /* DDRC_CH0 + 0xF0: MSTR/timing? */
|
|
#define _DAT_fe0100f4 REG32(0xFE0100F4) /* DDRC_CH0 + 0xF4 */
|
|
#define _DAT_fe0100f8 REG32(0xFE0100F8) /* DDRC_CH0 + 0xF8 */
|
|
#define _DAT_fe0100fc REG32(0xFE0100FC) /* DDRC_CH0 + 0xFC */
|
|
|
|
/* === FIREWALL DDR (0xFE030000) === */
|
|
#define _DAT_fe030040 REG32(0xFE030040) /* FW_DDR: access control */
|
|
|
|
/* === SGRF (0xFE050000) - Security GRF === */
|
|
/* Controls which bus masters can access DDR regions */
|
|
#define _DAT_fe050000 REG32(0xFE050000) /* SGRF_DDR_CON0 */
|
|
#define _DAT_fe050004 REG32(0xFE050004) /* SGRF_DDR_CON1 */
|
|
#define _DAT_fe050008 REG32(0xFE050008) /* SGRF_DDR_CON2 */
|
|
#define _DAT_fe05000c REG32(0xFE05000C) /* SGRF_DDR_CON3 */
|
|
#define _DAT_fe05002c REG32(0xFE05002C) /* SGRF_DDR_CON11 */
|
|
#define _DAT_fe050054 REG32(0xFE050054) /* SGRF_DDR_CON21 */
|
|
#define _DAT_fe050058 REG32(0xFE050058) /* SGRF_DDR_CON22 */
|
|
#define _DAT_fe0500e0 REG32(0xFE0500E0) /* SGRF: status/busy poll */
|
|
#define _DAT_fe0500e4 REG32(0xFE0500E4) /* SGRF: enable/lock */
|
|
|
|
/* === Unknown 0xFECC0000 region === */
|
|
/* Possibly DDR Scramble / ECC or VO-related */
|
|
#define _DAT_fecc0004 REG32(0xFECC0004)
|
|
#define _DAT_fecc0008 REG32(0xFECC0008)
|
|
#define _DAT_fecc0020 REG32(0xFECC0020)
|
|
#define _DAT_fecc0084 REG32(0xFECC0084)
|
|
|
|
/* === SRAM (0xFF000000) === */
|
|
#define _DAT_ff000010 REG32(0xFF000010) /* SRAM: boot flag/mailbox */
|
|
|
|
/* =====================================================================
|
|
* TRM-CANONICAL names for poll-site registers (RK3588 TRM Part 2 Ch.2)
|
|
* Added 2026-04-15 after cross-referencing the 522-page DMC chapter.
|
|
* Offsets are within a DDRCTL (uMCTL2) per-channel base.
|
|
* =====================================================================
|
|
*/
|
|
|
|
#define DDRCTL_MRCTRL0 0x10080 /* Mode Register Control 0
|
|
- mr_wr[31]: write a MR command
|
|
- mr_addr[23:16]: MR address
|
|
- mr_data[15:0]: MR data to write
|
|
Previously guessed as "MicroReset". */
|
|
|
|
#define DDRCTL_MRSTAT 0x10090 /* Mode Register Status
|
|
- mr_wr_busy[0]: 1 while MR cmd in flight
|
|
Poll: WAIT for bit 0 == 0.
|
|
Previously guessed as "MicroContMuxSel". */
|
|
|
|
#define DDRCTL_DFISTAT 0x10514 /* DFI Status
|
|
- dfi_init_complete[0]: 1 when PHY ready
|
|
Poll: WAIT for bit 0 == 1.
|
|
Previously guessed as "UctWriteProtShadow". */
|
|
|
|
/* Low-offset polls in FUN_0000d328 (train_phy_block) and friends are
|
|
* Synopsys DWC PUB registers — NOT in RK3588 TRM. Still require RE.
|
|
* The heuristic labels below come from the d328 analysis (2026-04-15):
|
|
*/
|
|
#define PHY_OFF_BASE 0x8000 /* sub-block offset within a PHY used by d328 */
|
|
|
|
#define PHY_CTL_110 0x110 /* write 0xF000F000 to trigger step, 0xF0000000 to clear */
|
|
#define PHY_STAT_A_118 0x118 /* wait for bits[31:28] != 0 */
|
|
#define PHY_STAT_B_120 0x120 /* wait for bits[31:28] != 0 */
|
|
#define PHY_CFG_A_154 0x154 /* write 0x30003 (go), 0x30000 (end) */
|
|
#define PHY_CFG_B_160 0x160 /* write 0x30003 (go), 0x30000 (end) */
|
|
#define PHY_HANDSHAKE_184 0x184 /* wait for bits[1:0] non-zero, then zero */
|
|
|
|
/* The large-offset polls (0xb88, 0xa24, 0x684) in the early-cluster
|
|
* functions are also DWC PUB; semantic guesses in BUG_ANALYSIS.md. */
|
|
|
|
|
|
/* =====================================================================
|
|
* TRM §2.4.3 "Registers Summary For DDRPHY" — confirmed 2026-04-15
|
|
* (sibling research surfaced this section of the TRM we'd missed).
|
|
* All offsets are within a per-channel DDRPHY Operational Base.
|
|
* =====================================================================
|
|
*/
|
|
|
|
#define DDRPHY_CAL_RD_VWML0 0x0110 /* Calibration Read Valid Window
|
|
Margin Left Code 0 (TRM HIGH) */
|
|
/* +0x118 : TRM-reserved in the register summary. RE: per-slice "window
|
|
* valid" or shadow register; the blob reads [31:28] as per-slice done
|
|
* flags. Private training-engine FSM register. */
|
|
#define DDRPHY_CAL_RD_VWMR0 0x0120 /* Calibration Read Valid Window
|
|
Margin Right Code 0 (TRM HIGH) */
|
|
/* +0x154 : TRM-reserved. RE: accompanies CAL_CON5 in d328; likely a
|
|
* per-slice write-training trigger or training-engine shadow. */
|
|
#define DDRPHY_CAL_CON5 0x0160 /* Calibration Control Register 5:
|
|
[10] binary_en (TBD)
|
|
[9:2] wrtrn_cyc_th (write training cycle threshold)
|
|
[1] wrtrn_cyc_en (write training cycle delay enable)
|
|
[0] wrtrn_cyc_mode (1=low freq 500MHz-1GHz, 0=matched edges)
|
|
(TRM HIGH) */
|
|
/* +0x184 : TRM-reserved. RE: DFI phyupd / update-request handshake
|
|
* (pattern matches — wait non-zero, then wait zero). */
|
|
#define DDRPHY_PRBS_CON0 0x0684 /* PRBS Training Control Register 0
|
|
(our old "CalBusy" guess was wrong)
|
|
LPDDR5 high-speed PRBS pattern
|
|
training start/done (TRM HIGH) */
|
|
#define DDRPHY_SCHD_TRAIN_CON0 0x0A24 /* **Master training scheduler**
|
|
[0] phy_train_en (start)
|
|
[1] phy_train_done (RO, completion)
|
|
[2] phy_cbt_en
|
|
[3] phy_wrlvl_en
|
|
[4] phy_gttrn_en (gate leveling)
|
|
[5] phy_rdtrn_en (read training)
|
|
[6] phy_wrtrn_en (write training)
|
|
[7] phy_wlcal_en
|
|
[9:8] phy_wrlvl_rank_en
|
|
[11:10] phy_gttrn_rank_en
|
|
[13:12] phy_rdtrn_rank_en
|
|
[15:14] phy_wrtrn_rank_en
|
|
[17:16] dvfs_gttrn_en
|
|
[19:18] dvfs_wrtrn_en
|
|
[21:20] periodic_gttrn_en
|
|
[23:22] periodic_wrtrn_en
|
|
(TRM EXTREMELY HIGH) */
|
|
#define DDRPHY_DQSDUTY_CON2 0x0B88 /* DQS Rise-Duty rank1 DS0 —
|
|
duty-cycle monitor for DCM/DCA
|
|
(our old "UctShadow" guess wrong)
|
|
(TRM HIGH) */
|
|
|
|
/* -------------------------------------------------------------------
|
|
* CORRECTION 2026-04-15 LATE EVENING:
|
|
* The 'CAL_RD_VWML0' etc. names above apply to DDRPHY_OPB + small
|
|
* offsets. d328's accesses are at DDRPHY_OPB + 0x8000 + small,
|
|
* which is an UNDOCUMENTED sub-block of the DDRPHY space.
|
|
* Writing 0xF000F000 to a TRM-documented READ-ONLY register
|
|
* would be a no-op — contradicting the blob's actual behaviour —
|
|
* so those names DO NOT apply here. The `PHY_CTL_110` etc.
|
|
* heuristic labels (in the block above) are the safe fallback.
|
|
*
|
|
* Semantic re-interpretation of FUN_0000d328 (train_phy_block):
|
|
* Writes 0x30003 to CAL_CON5 (+0x160):
|
|
* bit[0] wrtrn_cyc_mode=1 (low-freq edge mode)
|
|
* bit[1] wrtrn_cyc_en=1 (write training cycle delay enabled)
|
|
* bits[17:16] are in the RESERVED range of CAL_CON5 — no-op there.
|
|
* So d328 enables write-training cycle mode, waits for handshake,
|
|
* then clears (writes 0x30000 ≈ bits[17:16] — clears the [1:0] bits
|
|
* effectively).
|
|
*
|
|
* NOT "DVFS gate training" as initial sibling hypothesis; d328 is
|
|
* actually WRITE TRAINING setup/teardown (configuring the cycle
|
|
* mode, not the master scheduler).
|
|
* ------------------------------------------------------------------- */
|