/* ddr_cadence.h * * Generic Cadence DDR controller driver interface (controller register * programming, the Memory Test Controller engine, and the LPDDR4 mode- * register write protocol). The PHY, PLL, clock and training are SoC * specific and stay in the platform HAL, which composes these calls. * * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfBoot. * * wolfBoot is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfBoot is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #ifndef DDR_CADENCE_H #define DDR_CADENCE_H #include /* Controller CSR window. Default is the PolarFire SoC DDRC APB base; a * different Cadence-based SoC can override it at build time. */ #ifndef DDR_CADENCE_CTRL_BASE #define DDR_CADENCE_CTRL_BASE 0x20080000UL #endif #define DDRC_REG(off) (*(volatile uint32_t*)(DDR_CADENCE_CTRL_BASE + (off))) static inline void ddrc_mb(void) { __asm__ volatile("fence iorw, iorw" ::: "memory"); } /* MTC address mode and timeout return code (the data/address pattern * selectors are passed through opaquely). */ #define DDR_CADENCE_MTC_ADD_RANDOM 0x01U #define DDR_CADENCE_MTC_TIMEOUT_ERROR 0x02U /* DDR Controller Register Offsets * * From HSS mss_ddr_sgmii_regs.h: * MC_BASE2 @ DDRCFG_BASE + 0x4000 = 0x20084000 (controller registers) * DFI_BASE @ DDRCFG_BASE + 0x10000 = 0x20090000 (DFI interface) */ /* MC_BASE2 registers (DDRCFG_BASE + 0x4000) * * BUG FIX (Phase 3.6): the previous offsets in this block were taken from * an incomplete/incorrect mapping and many were WRONG vs the actual IP * layout, so setup_controller has been writing values to scrambled * register addresses for some time. Examples of the wrong offsets: * MC_CFG_CL was 0x74 (actually CFG_XP) * MC_CFG_STARTUP_DELAY was 0x80 (actually CFG_CL) * MC_INIT_ZQ_CAL_START was 0xDC (actually CFG_MEM_BANKBITS) * MC_CFG_AUTO_ZQ_CAL_EN was 0xE0 (actually CFG_ODT_RD_MAP_CS0) * * The offsets below are verified against the HSS register struct * `DDR_CSR_APB_MC_BASE2_TypeDef` in mss_ddr_sgmii_regs.h. */ #define MC_BASE2 0x4000 /* MC_BASE2 controller register offsets (verified against HSS * mss_ddr_sgmii_regs.h DDR_CSR_APB_MC_BASE2_TypeDef). */ #define MC_CTRLR_SOFT_RESET_N (MC_BASE2 + 0x0) #define MC_CFG_LOOKAHEAD_PCH (MC_BASE2 + 0x8) #define MC_CFG_LOOKAHEAD_ACT (MC_BASE2 + 0xc) #define MC_INIT_AUTOINIT_DISABLE (MC_BASE2 + 0x10) #define MC_INIT_FORCE_RESET (MC_BASE2 + 0x14) #define MC_INIT_GEARDOWN_EN (MC_BASE2 + 0x18) #define MC_INIT_DISABLE_CKE (MC_BASE2 + 0x1c) #define MC_INIT_CS (MC_BASE2 + 0x20) #define MC_INIT_PRECHARGE_ALL (MC_BASE2 + 0x24) #define MC_INIT_REFRESH (MC_BASE2 + 0x28) #define MC_INIT_ZQ_CAL_REQ (MC_BASE2 + 0x2c) #define MC_INIT_ACK (MC_BASE2 + 0x30) #define MC_CFG_BL (MC_BASE2 + 0x34) #define MC_CTRLR_INIT (MC_BASE2 + 0x38) #define MC_CTRLR_INIT_DONE (MC_BASE2 + 0x3c) #define MC_CFG_AUTO_REF_EN (MC_BASE2 + 0x40) #define MC_CFG_RAS (MC_BASE2 + 0x44) #define MC_CFG_RCD (MC_BASE2 + 0x48) #define MC_CFG_RRD (MC_BASE2 + 0x4c) #define MC_CFG_RP (MC_BASE2 + 0x50) #define MC_CFG_RC (MC_BASE2 + 0x54) #define MC_CFG_FAW (MC_BASE2 + 0x58) #define MC_CFG_RFC (MC_BASE2 + 0x5c) #define MC_CFG_RTP (MC_BASE2 + 0x60) #define MC_CFG_WR (MC_BASE2 + 0x64) #define MC_CFG_WTR (MC_BASE2 + 0x68) #define MC_CFG_PASR (MC_BASE2 + 0x70) #define MC_CFG_XP (MC_BASE2 + 0x74) #define MC_CFG_XSR (MC_BASE2 + 0x78) #define MC_CFG_CL (MC_BASE2 + 0x80) #define MC_CFG_READ_TO_WRITE (MC_BASE2 + 0x88) #define MC_CFG_WRITE_TO_WRITE (MC_BASE2 + 0x8c) #define MC_CFG_READ_TO_READ (MC_BASE2 + 0x90) #define MC_CFG_WRITE_TO_READ (MC_BASE2 + 0x94) #define MC_CFG_READ_TO_WRITE_ODT (MC_BASE2 + 0x98) #define MC_CFG_WRITE_TO_WRITE_ODT (MC_BASE2 + 0x9c) #define MC_CFG_READ_TO_READ_ODT (MC_BASE2 + 0xa0) #define MC_CFG_WRITE_TO_READ_ODT (MC_BASE2 + 0xa4) #define MC_CFG_MIN_READ_IDLE (MC_BASE2 + 0xa8) #define MC_CFG_MRD (MC_BASE2 + 0xac) #define MC_CFG_BT (MC_BASE2 + 0xb0) #define MC_CFG_DS (MC_BASE2 + 0xb4) #define MC_CFG_QOFF (MC_BASE2 + 0xb8) #define MC_CFG_RTT (MC_BASE2 + 0xc4) #define MC_CFG_DLL_DISABLE (MC_BASE2 + 0xc8) #define MC_CFG_REF_PER (MC_BASE2 + 0xcc) #define MC_CFG_STARTUP_DELAY (MC_BASE2 + 0xd0) #define MC_CFG_MEM_COLBITS (MC_BASE2 + 0xd4) #define MC_CFG_MEM_ROWBITS (MC_BASE2 + 0xd8) #define MC_CFG_MEM_BANKBITS (MC_BASE2 + 0xdc) #define MC_CFG_ODT_RD_MAP_CS0 (MC_BASE2 + 0xe0) #define MC_CFG_ODT_RD_MAP_CS1 (MC_BASE2 + 0xe4) #define MC_CFG_ODT_RD_MAP_CS2 (MC_BASE2 + 0xe8) #define MC_CFG_ODT_RD_MAP_CS3 (MC_BASE2 + 0xec) #define MC_CFG_ODT_RD_MAP_CS4 (MC_BASE2 + 0xf0) #define MC_CFG_ODT_RD_MAP_CS5 (MC_BASE2 + 0xf4) #define MC_CFG_ODT_RD_MAP_CS6 (MC_BASE2 + 0xf8) #define MC_CFG_ODT_RD_MAP_CS7 (MC_BASE2 + 0xfc) #define MC_CFG_ODT_WR_MAP_CS0 (MC_BASE2 + 0x120) #define MC_CFG_ODT_WR_MAP_CS1 (MC_BASE2 + 0x124) #define MC_CFG_ODT_WR_MAP_CS2 (MC_BASE2 + 0x128) #define MC_CFG_ODT_WR_MAP_CS3 (MC_BASE2 + 0x12c) #define MC_CFG_ODT_WR_MAP_CS4 (MC_BASE2 + 0x130) #define MC_CFG_ODT_WR_MAP_CS5 (MC_BASE2 + 0x134) #define MC_CFG_ODT_WR_MAP_CS6 (MC_BASE2 + 0x138) #define MC_CFG_ODT_WR_MAP_CS7 (MC_BASE2 + 0x13c) #define MC_CFG_ODT_RD_TURN_ON (MC_BASE2 + 0x160) #define MC_CFG_ODT_WR_TURN_ON (MC_BASE2 + 0x164) #define MC_CFG_ODT_RD_TURN_OFF (MC_BASE2 + 0x168) #define MC_CFG_ODT_WR_TURN_OFF (MC_BASE2 + 0x16c) #define MC_CFG_EMR3 (MC_BASE2 + 0x178) #define MC_CFG_TWO_T (MC_BASE2 + 0x17c) #define MC_CFG_TWO_T_SEL_CYCLE (MC_BASE2 + 0x180) #define MC_CFG_REGDIMM (MC_BASE2 + 0x184) #define MC_CFG_MOD (MC_BASE2 + 0x188) #define MC_CFG_XS (MC_BASE2 + 0x18c) #define MC_CFG_XSDLL (MC_BASE2 + 0x190) #define MC_CFG_XPR (MC_BASE2 + 0x194) #define MC_CFG_AL_MODE (MC_BASE2 + 0x198) #define MC_CFG_CWL (MC_BASE2 + 0x19c) #define MC_CFG_BL_MODE (MC_BASE2 + 0x1a0) #define MC_CFG_TDQS (MC_BASE2 + 0x1a4) #define MC_CFG_RTT_WR (MC_BASE2 + 0x1a8) #define MC_CFG_LP_ASR (MC_BASE2 + 0x1ac) #define MC_CFG_AUTO_SR (MC_BASE2 + 0x1b0) #define MC_CFG_SRT (MC_BASE2 + 0x1b4) #define MC_CFG_ADDR_MIRROR (MC_BASE2 + 0x1b8) #define MC_CFG_ZQ_CAL_TYPE (MC_BASE2 + 0x1bc) #define MC_CFG_ZQ_CAL_PER (MC_BASE2 + 0x1c0) #define MC_CFG_AUTO_ZQ_CAL_EN (MC_BASE2 + 0x1c4) #define MC_CFG_MEMORY_TYPE (MC_BASE2 + 0x1c8) #define MC_CFG_ONLY_SRANK_CMDS (MC_BASE2 + 0x1cc) #define MC_CFG_NUM_RANKS (MC_BASE2 + 0x1d0) #define MC_CFG_QUAD_RANK (MC_BASE2 + 0x1d4) #define MC_CFG_EARLY_RANK_TO_WR_START (MC_BASE2 + 0x1dc) #define MC_CFG_EARLY_RANK_TO_RD_START (MC_BASE2 + 0x1e0) #define MC_CFG_PASR_BANK (MC_BASE2 + 0x1e4) #define MC_CFG_PASR_SEG (MC_BASE2 + 0x1e8) #define MC_INIT_MRR_MODE (MC_BASE2 + 0x1ec) #define MC_INIT_MR_W_REQ (MC_BASE2 + 0x1f0) #define MC_INIT_MR_ADDR (MC_BASE2 + 0x1f4) #define MC_INIT_MR_WR_DATA (MC_BASE2 + 0x1f8) #define MC_INIT_MR_WR_MASK (MC_BASE2 + 0x1fc) #define MC_INIT_NOP (MC_BASE2 + 0x200) #define MC_CFG_INIT_DURATION (MC_BASE2 + 0x204) #define MC_CFG_ZQINIT_CAL_DURATION (MC_BASE2 + 0x208) #define MC_CFG_ZQ_CAL_L_DURATION (MC_BASE2 + 0x20c) #define MC_CFG_ZQ_CAL_S_DURATION (MC_BASE2 + 0x210) #define MC_CFG_ZQ_CAL_R_DURATION (MC_BASE2 + 0x214) #define MC_CFG_MRR (MC_BASE2 + 0x218) #define MC_CFG_MRW (MC_BASE2 + 0x21c) #define MC_CFG_ODT_POWERDOWN (MC_BASE2 + 0x220) #define MC_CFG_WL (MC_BASE2 + 0x224) #define MC_CFG_RL (MC_BASE2 + 0x228) #define MC_CFG_CAL_READ_PERIOD (MC_BASE2 + 0x22c) #define MC_CFG_NUM_CAL_READS (MC_BASE2 + 0x230) #define MC_INIT_POWER_DOWN (MC_BASE2 + 0x23c) #define MC_INIT_FORCE_WRITE (MC_BASE2 + 0x244) #define MC_INIT_FORCE_WRITE_CS (MC_BASE2 + 0x248) #define MC_CFG_CTRLR_INIT_DISABLE (MC_BASE2 + 0x24c) #define MC_INIT_RDIMM_COMPLETE (MC_BASE2 + 0x258) #define MC_CFG_RDIMM_LAT (MC_BASE2 + 0x25c) #define MC_CFG_RDIMM_BSIDE_INVERT (MC_BASE2 + 0x260) #define MC_CFG_LRDIMM (MC_BASE2 + 0x264) #define MC_INIT_MEMORY_RESET_MASK (MC_BASE2 + 0x268) #define MC_CFG_RD_PREAMB_TOGGLE (MC_BASE2 + 0x26c) #define MC_CFG_RD_POSTAMBLE (MC_BASE2 + 0x270) #define MC_CFG_PU_CAL (MC_BASE2 + 0x274) #define MC_CFG_DQ_ODT (MC_BASE2 + 0x278) #define MC_CFG_CA_ODT (MC_BASE2 + 0x27c) #define MC_CFG_ZQLATCH_DURATION (MC_BASE2 + 0x280) #define MC_INIT_CAL_SELECT (MC_BASE2 + 0x284) #define MC_INIT_CAL_L_R_REQ (MC_BASE2 + 0x288) #define MC_INIT_CAL_L_B_SIZE (MC_BASE2 + 0x28c) #define MC_INIT_RWFIFO (MC_BASE2 + 0x2a0) #define MC_INIT_RD_DQCAL (MC_BASE2 + 0x2a4) #define MC_INIT_START_DQSOSC (MC_BASE2 + 0x2a8) #define MC_INIT_STOP_DQSOSC (MC_BASE2 + 0x2ac) #define MC_INIT_ZQ_CAL_START (MC_BASE2 + 0x2b0) #define MC_CFG_WR_POSTAMBLE (MC_BASE2 + 0x2b4) #define MC_INIT_CAL_L_ADDR_0 (MC_BASE2 + 0x2bc) #define MC_INIT_CAL_L_ADDR_1 (MC_BASE2 + 0x2c0) #define MC_CFG_CTRLUPD_TRIG (MC_BASE2 + 0x2c4) #define MC_CFG_CTRLUPD_START_DELAY (MC_BASE2 + 0x2c8) #define MC_CFG_DFI_T_CTRLUPD_MAX (MC_BASE2 + 0x2cc) #define MC_CFG_CTRLR_BUSY_SEL (MC_BASE2 + 0x2d0) #define MC_CFG_CTRLR_BUSY_VALUE (MC_BASE2 + 0x2d4) #define MC_CFG_CTRLR_BUSY_TURN_OFF_DELAY (MC_BASE2 + 0x2d8) #define MC_CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW (MC_BASE2 + 0x2dc) #define MC_CFG_CTRLR_BUSY_RESTART_HOLDOFF (MC_BASE2 + 0x2e0) #define MC_CFG_PARITY_RDIMM_DELAY (MC_BASE2 + 0x2e4) #define MC_CFG_CTRLR_BUSY_ENABLE (MC_BASE2 + 0x2e8) #define MC_CFG_ASYNC_ODT (MC_BASE2 + 0x2ec) #define MC_CFG_ZQ_CAL_DURATION (MC_BASE2 + 0x2f0) #define MC_CFG_MRRI (MC_BASE2 + 0x2f4) #define MC_INIT_ODT_FORCE_EN (MC_BASE2 + 0x2f8) #define MC_INIT_ODT_FORCE_RANK (MC_BASE2 + 0x2fc) #define MC_CFG_PHYUPD_ACK_DELAY (MC_BASE2 + 0x300) #define MC_CFG_MIRROR_X16_BG0_BG1 (MC_BASE2 + 0x304) #define MC_INIT_PDA_MR_W_REQ (MC_BASE2 + 0x308) #define MC_INIT_PDA_NIBBLE_SELECT (MC_BASE2 + 0x30c) #define MC_CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH (MC_BASE2 + 0x310) #define MC_CFG_CKSRE (MC_BASE2 + 0x314) #define MC_CFG_CKSRX (MC_BASE2 + 0x318) #define MC_CFG_RCD_STAB (MC_BASE2 + 0x31c) #define MC_CFG_DFI_T_CTRL_DELAY (MC_BASE2 + 0x320) #define MC_CFG_DFI_T_DRAM_CLK_ENABLE (MC_BASE2 + 0x324) #define MC_CFG_IDLE_TIME_TO_SELF_REFRESH (MC_BASE2 + 0x328) #define MC_CFG_IDLE_TIME_TO_POWER_DOWN (MC_BASE2 + 0x32c) #define MC_CFG_BURST_RW_REFRESH_HOLDOFF (MC_BASE2 + 0x330) #define MC_CFG_BG_INTERLEAVE (MC_BASE2 + 0x384) #define MC_CFG_REFRESH_DURING_PHY_TRAINING (MC_BASE2 + 0x3fc) /* Backward-compat aliases for legacy short names used in run_training */ #define MC_CTRLR_SOFT_RESET MC_CTRLR_SOFT_RESET_N #define MC_AUTOINIT_DISABLE MC_INIT_AUTOINIT_DISABLE /* DFI registers (DDRCFG_BASE + 0x10000) */ #define DFI_BASE 0x10000 #define MC_DFI_RDDATA_EN (DFI_BASE + 0x00) #define MC_DFI_PHY_RDLAT (DFI_BASE + 0x04) #define MC_DFI_PHY_WRLAT (DFI_BASE + 0x08) #define MC_DFI_PHYUPD_EN (DFI_BASE + 0x0C) #define MC_DFI_INIT_COMPLETE (DFI_BASE + 0x34) #define MC_DFI_INIT_START (DFI_BASE + 0x50) /* Memory Test Controller (MTC) registers - at DDRCFG_BASE + 0x4400 */ #define MTC_BASE 0x4400 #define MT_EN (MTC_BASE + 0x00) #define MT_EN_SINGLE (MTC_BASE + 0x04) #define MT_STOP_ON_ERROR (MTC_BASE + 0x08) #define MT_DATA_PATTERN (MTC_BASE + 0x14) #define MT_ADDR_PATTERN (MTC_BASE + 0x18) #define MT_ADDR_BITS (MTC_BASE + 0x20) #define MT_ERROR_STS (MTC_BASE + 0x24) #define MT_DONE_ACK (MTC_BASE + 0x28) #define MT_START_ADDR_0 (MTC_BASE + 0xB4) #define MT_START_ADDR_1 (MTC_BASE + 0xB8) #define MT_ERROR_MASK_0 (MTC_BASE + 0xBC) #define MT_ERROR_MASK_1 (MTC_BASE + 0xC0) #define MT_ERROR_MASK_2 (MTC_BASE + 0xC4) #define MT_ERROR_MASK_3 (MTC_BASE + 0xC8) #define MT_ERROR_MASK_4 (MTC_BASE + 0xCC) /* One controller CSR write: offset (from DDR_CADENCE_CTRL_BASE) and value. * The platform builds a const table from its board config and hands it to * ddr_cadence_controller_setup(). */ typedef struct { uint32_t off; uint32_t val; } ddr_cadence_reg_t; /* Microsecond delay, provided by the platform (the generic driver has no * timer of its own). */ void ddr_cadence_udelay(uint32_t us); /* Program the controller CSRs from the platform's register table. */ void ddr_cadence_controller_setup(const ddr_cadence_reg_t *regs, unsigned int count); /* Single-shot Memory Test Controller run. Returns 0 on pass, 1 on data * error, DDR_CADENCE_MTC_TIMEOUT_ERROR on timeout. */ uint8_t ddr_cadence_mtc_test(uint8_t mask, uint64_t start_address, uint32_t size, uint8_t data_pattern, uint8_t add_pattern); /* LPDDR4 mode-register writes. Return 0 on ACK, 1 on no-ACK. */ uint32_t ddr_cadence_mr_masked_write(uint32_t address); uint32_t ddr_cadence_mr_unmasked_write(uint32_t address, uint32_t data); uint32_t ddr_cadence_mr_masked_write_x10(uint32_t address); #endif /* DDR_CADENCE_H */