continue DDR regs
This commit is contained in:
@@ -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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user