continue DDR regs

This commit is contained in:
2025-07-30 01:23:06 +02:00
parent 6be08c439b
commit d1c7aba6f7

View File

@@ -1,12 +1,154 @@
use arbitrary_int::{u11, u12, u3, u4, u5, u6, u7};
pub const DDRC_BASE_ADDR: usize = 0xF800_6000;
#[bitbybit::bitenum(u2)]
#[derive(Debug, PartialEq, Eq)]
pub enum DataBusWidth {
_32Bit = 0b00,
_16Bit = 0b01,
}
#[bitbybit::bitenum(u1, exhaustive = true)]
#[derive(Debug, PartialEq, Eq)]
pub enum SoftReset {
Reset = 0,
Active = 1,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct DdrcControl {
#[bit(16, rw)]
disable_auto_refresh: bool,
#[bit(15, rw)]
disable_active_bypass: bool,
#[bit(14, rw)]
disable_read_bypass: bool,
#[bits(7..=13, rw)]
read_write_idle_gap: u7,
#[bits(4..=6, rw)]
burst8_refresh: u3,
#[bits(2..=3, rw)]
data_bus_width: Option<DataBusWidth>,
#[bit(1, rw)]
power_down_enable: bool,
#[bit(0, rw)]
soft_reset: SoftReset,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct TwoRankConfig {
#[bits(14..=18, rw)]
addrmap_cs_bit0: u5,
/// tREFI - Average time between refreshes, in multiples of 32 clocks.
#[bits(0..=11, rw)]
rfc_nom_x32: u12,
}
/// Queue control for the low priority and high priority read queues.
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct LprHprQueueControl {
#[bits(22..=25, rw)]
xact_run_length: u4,
#[bits(11..=21, rw)]
max_starve_x32: u11,
#[bits(0..=10, rw)]
min_non_critical_x32: u11,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct WriteQueueControl {
#[bits(15..=25, rw)]
max_starve_x32: u11,
#[bits(11..=14, rw)]
xact_run_length: u4,
#[bits(0..=10, rw)]
min_non_critical_x32: u11,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct DramParamReg0 {
/// Minimum time to wait after coming out of self refresh before doing anything. This must be
/// bigger than all the constraints that exist.
#[bits(14..=20, rw)]
post_selfref_gap_x32: u7,
/// tRFC(min) - Minimum time from refresh to refresh or activate in clock
/// cycles.
#[bits(6..=13, rw)]
t_rfc_min: u8,
/// tRC - Min time between activates to the same bank.
#[bits(0..=5, rw)]
t_rc: u6,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct DramParamReg1 {
#[bits(28..=31, rw)]
t_cke: u4,
#[bits(22..=26, rw)]
t_ras_min: u5,
#[bits(16..=21, rw)]
t_ras_max: u6,
#[bits(10..=15, rw)]
t_faw: u6,
#[bits(5..=9, rw)]
powerdown_to_x32: u5,
#[bits(0..=4, rw)]
wr2pre: u5,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct DramParamReg2 {
#[bits(28..=31, rw)]
t_rcd: u4,
#[bits(23..=27, rw)]
rd2pre: u5,
#[bits(20..=22, rw)]
pad_pd: u3,
#[bits(15..=19, rw)]
t_xp: u5,
#[bits(10..=14, rw)]
wr2rd: u5,
#[bits(5..=9, rw)]
rd2wr: u5,
#[bits(0..=4, rw)]
write_latency: u5,
}
#[bitbybit::bitfield(u32, default = 0x0)]
pub struct DramParamReg3 {
#[bit(30, rw)]
disable_pad_pd: bool,
#[bits(24..=28, rw)]
read_latency: u5,
#[bit(23, rw)]
enable_dfi_dram_clk_disable: bool,
/// 0: DDR2 or DDR3. 1: LPDDR2.
#[bit(22, rw)]
mobile: bool,
/// Must be set to 0.
#[bit(21, rw)]
sdram: bool,
#[bits(16..=20, rw)]
refresh_to_x32: u5,
#[bits(12..=15, rw)]
t_rp: u4,
#[bits(8..=11, rw)]
refresh_margin: u4,
#[bits(5..=7, rw)]
t_rrd: u3,
#[bits(2..=4, rw)]
t_ccd: u3
}
#[derive(derive_mmio::Mmio)] #[derive(derive_mmio::Mmio)]
#[repr(C)] #[repr(C)]
pub struct DdrController { pub struct DdrController {
ddrc_ctrl: u32, ddrc_ctrl: DdrcControl,
two_rank_cfg: u32, two_rank_cfg: TwoRankConfig,
hpr_reg: u32, hpr_queue_ctrl: LprHprQueueControl,
lpr_reg: u32, lpr_queue_ctrl: LprHprQueueControl,
wr_reg: u32, wr_reg: WriteQueueControl,
dram_param_reg0: u32, dram_param_reg0: DramParamReg0,
dram_param_reg1: u32, dram_param_reg1: u32,
dram_param_reg2: u32, dram_param_reg2: u32,
dram_param_reg3: u32, dram_param_reg3: u32,
@@ -29,8 +171,12 @@ pub struct DdrController {
ctrl_reg2: u32, ctrl_reg2: u32,
ctrl_reg3: u32, ctrl_reg3: u32,
ctrl_reg4: u32, ctrl_reg4: u32,
_reserved0: [u32; 0x2],
ctrl_reg5: u32, ctrl_reg5: u32,
ctrl_reg6: u32, ctrl_reg6: u32,
_reserved1: [u32; 0x8],
che_refresh_timer_01: u32, che_refresh_timer_01: u32,
che_t_zq: u32, che_t_zq: u32,
che_t_zq_short_interval_reg: u32, che_t_zq_short_interval_reg: u32,
@@ -38,7 +184,9 @@ pub struct DdrController {
reg_2c: u32, reg_2c: u32,
reg_2d: u32, reg_2d: u32,
dfi_timing: u32, dfi_timing: u32,
_reserved2: [u32; 0x2],
che_corr_control: u32, che_corr_control: u32,
che_corr_ecc_log: u32,
che_corr_ecc_addr: u32, che_corr_ecc_addr: u32,
che_corr_ecc_data_31_0: u32, che_corr_ecc_data_31_0: u32,
che_corr_ecc_data_63_32: u32, che_corr_ecc_data_63_32: u32,
@@ -48,51 +196,52 @@ pub struct DdrController {
che_uncorr_ecc_data_31_0: u32, che_uncorr_ecc_data_31_0: u32,
che_uncorr_ecc_data_63_32: u32, che_uncorr_ecc_data_63_32: u32,
che_uncorr_ecc_data_71_64: u32, che_uncorr_ecc_data_71_64: u32,
che_ecc_stats_reg: u32, che_ecc_stats: u32,
ecc_scrub: u32, ecc_scrub: u32,
che_ecc_corr_bit_mask_31_0: u32, che_ecc_corr_bit_mask_31_0: u32,
che_ecc_corr_bit_mask_63_32: u32, che_ecc_corr_bit_mask_63_32: u32,
_reserved3: [u32; 0x5],
phy_receiver_enable: u32, phy_receiver_enable: u32,
phy_config_0: u32, phy_config: [u32; 4],
phy_config_1: u32, _reserved4: u32,
phy_config_2: u32, phy_init_ratio: [u32; 4],
phy_config_3: u32, _reserved5: u32,
phy_init_ratio_0: u32, phy_rd_dqs_cfg: [u32; 4],
phy_init_ratio_1: u32, _reserved6: u32,
phy_init_ratio_2: u32, phy_wr_dqs_cfg: [u32; 4],
phy_init_ratio_3: u32, _reserved7: u32,
phy_rd_dqs_cfg_0: u32, phy_we_cfg_0: [u32; 4],
phy_rd_dqs_cfg_1: u32, _reserved8: u32,
phy_rd_dqs_cfg_2: u32, wr_data_slave: [u32; 4],
phy_rd_dqs_cfg_3: u32,
phy_wr_dqs_cfg_0: u32, _reserved9: u32,
phy_wr_dqs_cfg_1: u32,
phy_wr_dqs_cfg_2: u32,
phy_wr_dqs_cfg_3: u32,
phy_we_cfg_1: u32,
phy_we_cfg_2: u32,
phy_we_cfg_3: u32,
wr_data_slave_0: u32,
wr_data_slave_1: u32,
wr_data_slave_2: u32,
wr_data_slave_3: u32,
reg_64: u32, reg_64: u32,
reg_65: u32, reg_65: u32,
_reserved10: [u32; 3],
reg69_6a0: u32, reg69_6a0: u32,
reg69_6a1: u32, reg69_6a1: u32,
_reserved11: u32,
reg69_6d2: u32, reg69_6d2: u32,
reg69_6d3: u32, reg69_6d3: u32,
reg69_710: u32, reg69_710: u32,
reg6e_711: u32, reg6e_711: u32,
reg6e_712: u32, reg6e_712: u32,
reg6e_713: u32, reg6e_713: u32,
_reserved12: u32,
phy_dll_status_0: u32, phy_dll_status_0: u32,
phy_dll_status_1: u32, phy_dll_status_1: u32,
phy_dll_status_2: u32, phy_dll_status_2: u32,
phy_dll_status_3: u32, phy_dll_status_3: u32,
_reserved13: u32,
dll_lock_status: u32, dll_lock_status: u32,
phy_control_status: u32, phy_control_status: u32,
phy_control_status_2: u32, phy_control_status_2: u32,
_reserved14: [u32; 0x5],
axi_id: u32, axi_id: u32,
page_mask: u32, page_mask: u32,
axi_priority_wr_port_0: u32, axi_priority_wr_port_0: u32,
@@ -103,6 +252,9 @@ pub struct DdrController {
axi_priority_rd_port_1: u32, axi_priority_rd_port_1: u32,
axi_priority_rd_port_2: u32, axi_priority_rd_port_2: u32,
axi_priority_rd_port_3: u32, axi_priority_rd_port_3: u32,
_reserved15: [u32; 0x1B],
excl_access_cfg_0: u32, excl_access_cfg_0: u32,
excl_access_cfg_1: u32, excl_access_cfg_1: u32,
excl_access_cfg_2: u32, excl_access_cfg_2: u32,
@@ -114,5 +266,17 @@ pub struct DdrController {
lpddr_ctrl_3: u32, lpddr_ctrl_3: u32,
} }
static_assertions::const_assert_eq!(core::mem::size_of::<DdrController>(), 0x2B8); static_assertions::const_assert_eq!(core::mem::size_of::<DdrController>(), 0x2B8);
impl DdrController {
/// Create a new DDR MMIO instance for the DDR controller at address [DDRC_BASE_ADDR].
///
/// # Safety
///
/// This API can be used to potentially create a driver to the same peripheral structure
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
/// interfere with each other.
pub const unsafe fn new_mmio_fixed() -> MmioDdrController<'static> {
unsafe { Self::new_mmio_at(DDRC_BASE_ADDR) }
}
}