#[cfg(feature = "log")]
use super::println;
use core::ptr::{read_volatile, write_volatile};
const VERBOSE: bool = false;
pub const RAM_BASE: usize = 0x40000000;
const CCU: usize = 0x0200_1000;
const PLL_CPU_CTRL: usize = CCU + 0x0000;
const PLL_DDR_CTRL: usize = CCU + 0x0010;
const MBUS_CLK: usize = CCU + 0x0540;
const DRAM_CLK: usize = CCU + 0x0800;
const DRAM_BGR: usize = CCU + 0x080c;
const SYS_CFG: usize = 0x0300_0000; const SYS_LDO_CTRL_REG: usize = SYS_CFG + 0x0150;
const RES_CAL_CTRL_REG: usize = SYS_CFG + 0x0160;
const RES240_CTRL_REG: usize = SYS_CFG + 0x0168;
const ZQ_VALUE: usize = SYS_CFG + 0x0172;
const BAR_BASE: usize = 0x0700_0000; const SOME_STATUS: usize = BAR_BASE + 0x05d4;
const FOO_BASE: usize = 0x0701_0000; const ANALOG_SYS_PWROFF_GATING_REG: usize = FOO_BASE + 0x0254;
const SOME_OTHER: usize = FOO_BASE + 0x0250;
const SID_INFO: usize = SYS_CFG + 0x2228;
const MSI_MEMC_BASE: usize = 0x0310_2000;
const MC_WORK_MODE_RANK0_1: usize = MSI_MEMC_BASE;
const MC_WORK_MODE_RANK0_2: usize = MSI_MEMC_BASE + 0x0004;
const UNKNOWN1: usize = MSI_MEMC_BASE + 0x0008; const UNKNOWN7: usize = MSI_MEMC_BASE + 0x000c; const UNKNOWN12: usize = MSI_MEMC_BASE + 0x0014;
const DRAM_MASTER_CTL1: usize = MSI_MEMC_BASE + 0x0020;
const DRAM_MASTER_CTL2: usize = MSI_MEMC_BASE + 0x0024;
const DRAM_MASTER_CTL3: usize = MSI_MEMC_BASE + 0x0028;
const PHY_AC_MAP1: usize = 0x3102500;
const PHY_AC_MAP2: usize = 0x3102504;
const PHY_AC_MAP3: usize = 0x3102508;
const PHY_AC_MAP4: usize = 0x310250c;
const PIR: usize = MSI_MEMC_BASE + 0x1000; const UNKNOWN15: usize = MSI_MEMC_BASE + 0x1004; const MCTL_CLK: usize = MSI_MEMC_BASE + 0x100c; const PGSR0: usize = MSI_MEMC_BASE + 0x1010;
const STATR_X: usize = MSI_MEMC_BASE + 0x1018;
const DRAM_MR0: usize = MSI_MEMC_BASE + 0x1030; const DRAM_MR1: usize = MSI_MEMC_BASE + 0x1034; const DRAM_MR2: usize = MSI_MEMC_BASE + 0x1038; const DRAM_MR3: usize = MSI_MEMC_BASE + 0x103c; const DRAM_ODTX: usize = MSI_MEMC_BASE + 0x102c;
const PTR3: usize = MSI_MEMC_BASE + 0x1050; const PTR4: usize = MSI_MEMC_BASE + 0x1054; const DRAMTMG0: usize = MSI_MEMC_BASE + 0x1058; const DRAMTMG1: usize = MSI_MEMC_BASE + 0x105c; const DRAMTMG2: usize = MSI_MEMC_BASE + 0x1060; const DRAMTMG3: usize = MSI_MEMC_BASE + 0x1064; const DRAMTMG4: usize = MSI_MEMC_BASE + 0x1068; const DRAMTMG5: usize = MSI_MEMC_BASE + 0x106c; const DRAMTMG8: usize = MSI_MEMC_BASE + 0x1078; const UNKNOWN8: usize = MSI_MEMC_BASE + 0x107c; const PITMG0: usize = MSI_MEMC_BASE + 0x1080; const UNKNOWN13: usize = MSI_MEMC_BASE + 0x108c; const RFSHTMG: usize = MSI_MEMC_BASE + 0x1090; const RFSHCTL1: usize = MSI_MEMC_BASE + 0x1094;
const UNKNOWN10: usize = MSI_MEMC_BASE + 0x109c; const UNKNOWN11: usize = MSI_MEMC_BASE + 0x10a0; const UNKNOWN16: usize = MSI_MEMC_BASE + 0x10c0;
const PGCR0: usize = MSI_MEMC_BASE + 0x1100;
const MRCTRL0: usize = MSI_MEMC_BASE + 0x1108; const UNKNOWN14: usize = MSI_MEMC_BASE + 0x110c;
const IOCVR0: usize = MSI_MEMC_BASE + 0x1110; const IOCVR1: usize = MSI_MEMC_BASE + 0x1114;
const DQS_GATING_X: usize = MSI_MEMC_BASE + 0x111c;
const UNKNOWN9: usize = MSI_MEMC_BASE + 0x1120; const ZQ_CFG: usize = MSI_MEMC_BASE + 0x1140; const UNDOC1: usize = MSI_MEMC_BASE + 0x1208;
const DAT00IOCR: usize = MSI_MEMC_BASE + 0x1310; const DX0GCR0: usize = MSI_MEMC_BASE + 0x1344; const UNKNOWN4: usize = MSI_MEMC_BASE + 0x1348; const DX1GCR0: usize = MSI_MEMC_BASE + 0x13c4; const DAT01IOCR: usize = MSI_MEMC_BASE + 0x1390;
const UNKNOWN5: usize = MSI_MEMC_BASE + 0x13c8;
const MC_WORK_MODE_RANK1_1: usize = MSI_MEMC_BASE + 0x10_0000;
const MC_WORK_MODE_RANK1_2: usize = MSI_MEMC_BASE + 0x10_0004;
#[repr(C)]
pub struct dram_parameters {
pub dram_clk: u32,
pub dram_type: u32,
pub dram_zq: u32,
pub dram_odt_en: u32,
pub dram_para1: u32,
pub dram_para2: u32,
pub dram_mr0: u32,
pub dram_mr1: u32,
pub dram_mr2: u32,
pub dram_mr3: u32,
pub dram_tpr0: u32,
pub dram_tpr1: u32,
pub dram_tpr2: u32,
pub dram_tpr3: u32,
pub dram_tpr4: u32,
pub dram_tpr5: u32,
pub dram_tpr6: u32,
pub dram_tpr7: u32,
pub dram_tpr8: u32,
pub dram_tpr9: u32,
pub dram_tpr10: u32,
pub dram_tpr11: u32,
pub dram_tpr12: u32,
pub dram_tpr13: u32,
}
fn readl(reg: usize) -> u32 {
unsafe { read_volatile(reg as *mut u32) }
}
fn writel(reg: usize, val: u32) {
unsafe {
write_volatile(reg as *mut u32, val);
}
}
fn sdelay(micros: usize) {
let millis = micros * 1000;
unsafe {
for _ in 0..millis {
core::arch::asm!("nop")
}
}
}
fn get_pmu_exists() -> bool {
return false;
}
fn memcpy_self(dst: &mut [u32; 22], src: &[u32; 22], len: usize) {
dst[..len].copy_from_slice(&src[..len]);
}
static mut PHY_CFG0: [u32; 22] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
static mut PHY_CFG1: [u32; 22] = [
1, 9, 3, 7, 8, 18, 4, 13, 5, 6, 10, 2, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22,
];
static mut PHY_CFG2: [u32; 22] = [
4, 9, 3, 7, 8, 18, 1, 13, 2, 6, 10, 5, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22,
];
static mut PHY_CFG3: [u32; 22] = [
1, 7, 8, 12, 10, 18, 4, 13, 5, 6, 3, 2, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22,
];
static mut PHY_CFG4: [u32; 22] = [
4, 12, 10, 7, 8, 18, 1, 13, 2, 6, 3, 5, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22,
];
static mut PHY_CFG5: [u32; 22] = [
13, 2, 7, 9, 12, 19, 5, 1, 6, 3, 4, 8, 10, 0, 0, 0, 21, 22, 18, 17, 11, 20,
];
static mut PHY_CFG6: [u32; 22] = [
3, 10, 7, 13, 9, 11, 1, 2, 4, 6, 8, 5, 12, 0, 0, 0, 20, 1, 0, 21, 22, 17,
];
static mut PHY_CFG7: [u32; 22] = [
3, 2, 4, 7, 9, 1, 17, 12, 18, 14, 13, 8, 15, 6, 10, 5, 19, 22, 16, 21, 20, 11,
];
unsafe fn mctl_phy_ac_remapping(para: &mut dram_parameters) {
let fuse = (readl(SID_INFO) >> 8) & 0x4;
if (para.dram_tpr13 >> 18) & 0x3 > 0 {
memcpy_self(&mut PHY_CFG0, &mut PHY_CFG7, 22);
} else {
match fuse {
8 => memcpy_self(&mut PHY_CFG0, &mut PHY_CFG2, 22),
9 => memcpy_self(&mut PHY_CFG0, &mut PHY_CFG3, 22),
10 => memcpy_self(&mut PHY_CFG0, &mut PHY_CFG5, 22),
11 => memcpy_self(&mut PHY_CFG0, &mut PHY_CFG4, 22),
13 | 14 => {}
12 | _ => memcpy_self(&mut PHY_CFG0, &mut PHY_CFG1, 22),
}
}
if para.dram_type == 2 {
if fuse == 15 {
return;
}
memcpy_self(&mut PHY_CFG0, &mut PHY_CFG6, 22);
}
if para.dram_type == 2 || para.dram_type == 3 {
let val = (PHY_CFG0[4] << 25)
| (PHY_CFG0[3] << 20)
| (PHY_CFG0[2] << 15)
| (PHY_CFG0[1] << 10)
| (PHY_CFG0[0] << 5);
writel(PHY_AC_MAP1, val as u32);
let val = (PHY_CFG0[10] << 25)
| (PHY_CFG0[9] << 20)
| (PHY_CFG0[8] << 15)
| (PHY_CFG0[7] << 10)
| (PHY_CFG0[6] << 5)
| PHY_CFG0[5];
writel(PHY_AC_MAP2, val as u32);
let val = (PHY_CFG0[15] << 20)
| (PHY_CFG0[14] << 15)
| (PHY_CFG0[13] << 10)
| (PHY_CFG0[12] << 5)
| PHY_CFG0[11];
writel(PHY_AC_MAP3, val as u32);
let val = (PHY_CFG0[21] << 25)
| (PHY_CFG0[20] << 20)
| (PHY_CFG0[19] << 15)
| (PHY_CFG0[18] << 10)
| (PHY_CFG0[17] << 5)
| PHY_CFG0[16];
writel(PHY_AC_MAP4, val as u32);
let val = (PHY_CFG0[4] << 25)
| (PHY_CFG0[3] << 20)
| (PHY_CFG0[2] << 15)
| (PHY_CFG0[1] << 10)
| (PHY_CFG0[0] << 5)
| 1;
writel(PHY_AC_MAP1, val as u32);
}
}
fn dram_vol_set(dram_para: &mut dram_parameters) {
let _ = dram_para;
let vol = 25; let mut reg = readl(SYS_LDO_CTRL_REG);
reg &= !(0xff00);
reg |= vol << 8;
reg &= !(0x200000);
writel(SYS_LDO_CTRL_REG, reg);
sdelay(1);
}
fn set_ddr_voltage(val: usize) -> usize {
val
}
fn handler_super_standby() {}
fn dram_enable_all_master() {
writel(DRAM_MASTER_CTL1, 0xffffffff);
writel(DRAM_MASTER_CTL2, 0xff);
writel(DRAM_MASTER_CTL3, 0xffff);
sdelay(10);
}
fn dram_disable_all_master() {
writel(DRAM_MASTER_CTL1, 1);
writel(DRAM_MASTER_CTL2, 0);
writel(DRAM_MASTER_CTL3, 0);
sdelay(10);
}
fn ccm_set_pll_ddr_clk(para: &mut dram_parameters) -> u32 {
let clk = if para.dram_tpr13 & (1 << 6) != 0 {
para.dram_tpr9
} else {
para.dram_clk
};
let n = (clk * 2) / 24;
let mut val = readl(PLL_DDR_CTRL);
val &= 0xfff800fc; val |= (n - 1) << 8; val |= 0xc0000000; writel(PLL_DDR_CTRL, val);
val &= 0xdfffffff; val |= 0xc0000000; writel(PLL_DDR_CTRL, val);
val |= 0xe0000000; writel(PLL_DDR_CTRL, val);
while readl(PLL_DDR_CTRL) == 0 {}
sdelay(20);
let val = readl(PLL_CPU_CTRL);
writel(PLL_CPU_CTRL, val | 0x08000000);
let mut val = readl(DRAM_CLK);
val &= 0xfcfffcfc; val |= 0x80000000; writel(DRAM_CLK, val);
n * 24
}
fn mctl_sys_init(para: &mut dram_parameters) {
let val = readl(MBUS_CLK);
writel(MBUS_CLK, val & 0xbfffffff);
let mut val = readl(DRAM_BGR);
val &= 0xfffffffe;
writel(DRAM_BGR, val);
val &= 0xfffefffe;
writel(DRAM_BGR, val);
let mut val = readl(DRAM_CLK);
writel(DRAM_CLK, val & 0xbfffffff);
val &= 0x7fffffff;
writel(DRAM_CLK, val);
val |= 0x08000000;
writel(DRAM_CLK, val);
sdelay(10);
para.dram_clk = ccm_set_pll_ddr_clk(para) >> 1;
sdelay(100);
dram_disable_all_master();
let val = readl(DRAM_BGR);
writel(DRAM_BGR, val | 0x00010000);
let val = readl(MBUS_CLK);
writel(MBUS_CLK, val | 0x40000000);
let val = readl(DRAM_CLK);
writel(DRAM_CLK, val | 0x40000000);
sdelay(5);
let val = readl(DRAM_BGR);
writel(DRAM_BGR, val | 0x0000001);
let mut val = readl(DRAM_CLK);
val |= 0x80000000;
writel(DRAM_CLK, val);
val |= 0x88000000;
writel(DRAM_CLK, val);
sdelay(5);
writel(MCTL_CLK, 0x00008000);
sdelay(10);
}
fn mctl_vrefzq_init(para: &mut dram_parameters) {
if (para.dram_tpr13 & (1 << 17)) == 0 {
let val = readl(IOCVR0) & 0x80808080;
writel(IOCVR0, val | para.dram_tpr5 as u32);
if (para.dram_tpr13 & (1 << 16)) == 0 {
let val = readl(IOCVR1) & 0xffffff80;
writel(IOCVR1, val | para.dram_tpr6 as u32 & 0x7f);
}
}
}
fn mctl_com_init(para: &mut dram_parameters) {
let mut val = readl(UNKNOWN1) & 0xffffc0ff;
val |= 0x2000;
writel(UNKNOWN1, val);
let mut val = readl(MC_WORK_MODE_RANK0_1) & 0xff000fff;
val |= (para.dram_type & 0x7) << 16; val |= (!para.dram_para2 & 0x1) << 12; if para.dram_type != 6 && para.dram_type != 7 {
val |= ((para.dram_tpr13 >> 5) & 0x1) << 19; val |= 0x400000;
} else {
val |= 0x480000; }
writel(MC_WORK_MODE_RANK0_1, val);
let val = para.dram_para2;
let rank = if (val & 0x100) != 0 && (val >> 12) & 0xf != 1 {
2
} else {
1
};
for i in 0..rank {
let ptr = MC_WORK_MODE_RANK0_1 + i * 4;
let mut val = readl(ptr) & 0xfffff000;
val |= (para.dram_para2 >> 12) & 0x3; val |= ((para.dram_para1 >> (i * 16 + 12)) << 2) & 0x4; val |= (((para.dram_para1 >> (i * 16 + 4)) - 1) << 4) & 0xff;
val |= match (para.dram_para1 >> i * 16) & 0xf {
8 => 0xa00,
4 => 0x900,
2 => 0x800,
1 => 0x700,
_ => 0x600,
};
writel(ptr, val);
}
let val = match readl(MC_WORK_MODE_RANK0_1) & 0x1 {
0 => 0x201,
_ => 0x303,
};
writel(UNKNOWN9, val);
if para.dram_para2 & (1 << 0) > 0 {
writel(DX1GCR0, 0);
}
if para.dram_tpr4 > 0 {
let mut val = readl(MC_WORK_MODE_RANK0_1);
val |= (para.dram_tpr4 << 25) & 0x06000000;
writel(MC_WORK_MODE_RANK0_1, val);
let mut val = readl(MC_WORK_MODE_RANK0_2);
val |= ((para.dram_tpr4 >> 2) << 12) & 0x001ff000;
writel(MC_WORK_MODE_RANK0_2, val);
}
}
fn auto_cal_timing(time: u32, freq: u32) -> u32 {
let t = time * freq;
let what = if (t % 1000) != 0 { 1 } else { 0 };
(t / 1000) + what
}
fn auto_set_timing_para(para: &mut dram_parameters) {
let dfreq = para.dram_clk;
let dtype = para.dram_type;
let tpr13 = para.dram_tpr13;
let mut tccd: u32 = 0; let mut trrd: u32 = 0; let mut trcd: u32 = 0; let mut trc: u32 = 0; let mut tfaw: u32 = 0; let mut tras: u32 = 0; let mut trp: u32 = 0; let mut twtr: u32 = 0; let mut twr: u32 = 0; let mut trtp: u32; let mut txp: u32 = 0; let mut trefi: u32 = 0; let mut trfc: u32 = 0;
if para.dram_tpr13 & 0x2 != 0 {
tfaw = (para.dram_tpr0 >> 15) & 0x3f; trrd = (para.dram_tpr0 >> 11) & 0xf; trcd = (para.dram_tpr0 >> 6) & 0x1f; trc = (para.dram_tpr0 >> 0) & 0x3f;
txp = (para.dram_tpr1 >> 23) & 0x1f; twtr = (para.dram_tpr1 >> 20) & 0x7;
trp = (para.dram_tpr1 >> 6) & 0x1f; tras = (para.dram_tpr1 >> 0) & 0x3f;
trfc = (para.dram_tpr2 >> 12) & 0x1ff; trefi = (para.dram_tpr2 >> 0) & 0xfff; } else {
let frq2 = dfreq >> 1; match dtype {
3 => {
trfc = auto_cal_timing(350, frq2);
trefi = auto_cal_timing(7800, frq2) / 32 + 1; twr = auto_cal_timing(8, frq2);
twtr = if twr < 2 { 2 } else { twr + 2 }; trcd = auto_cal_timing(15, frq2);
twr = if trcd < 2 { 2 } else { trcd };
if dfreq <= 800 {
tfaw = auto_cal_timing(50, frq2);
let trrdc = auto_cal_timing(10, frq2);
trrd = if trrd < 2 { 2 } else { trrdc };
trc = auto_cal_timing(53, frq2);
tras = auto_cal_timing(38, frq2);
txp = trrd; trp = trcd; }
}
_ => {}
}
tccd = 2;
trtp = 4; para.dram_tpr0 = (trc << 0) | (trcd << 6) | (trrd << 11) | (tfaw << 15) | (tccd << 21);
para.dram_tpr1 =
(tras << 0) | (trp << 6) | (twr << 11) | (trtp << 15) | (twtr << 20) | (txp << 23);
para.dram_tpr2 = (trefi << 0) | (trfc << 12);
}
let tcksrx: u32; let tckesr: u32; let trd2wr: u32; let trasmax: u32; let twtp: u32; let tcke: u32; let tmod: u32; let tmrd: u32; let tmrw: u32; let t_rdata_en: u32; let tcl: u32; let wr_latency: u32; let tcwl: u32; let mr3: u32; let mr2: u32; let mr1: u32; let mr0: u32;
let twr2rd: u32; let tdinit3: u32; let tdinit2: u32; let tdinit1: u32; let tdinit0: u32;
let dmr1 = para.dram_mr1;
match dtype {
3 =>
{
trasmax = dfreq / 30;
if dfreq <= 800 {
mr0 = 0x1c70;
tcl = 6;
wr_latency = 2;
tcwl = 4;
mr2 = 24;
} else {
mr0 = 0x1e14;
tcl = 7;
wr_latency = 3;
tcwl = 5;
mr2 = 32;
}
twtp = tcwl + 2 + twtr as u32;
twr2rd = tcwl + twtr as u32;
tdinit0 = 500 * dfreq + 1; tdinit1 = 360 * dfreq / 1000 + 1; tdinit2 = 200 * dfreq + 1; tdinit3 = 1 * dfreq + 1;
mr1 = dmr1;
t_rdata_en = tcwl; tcksrx = 5;
tckesr = 4;
trd2wr = if ((tpr13 >> 2) & 0x03) == 0x01 || dfreq < 912 {
5
} else {
6
};
tcke = 3; tmod = 12;
tmrd = 4;
tmrw = 0;
mr3 = 0;
}
_ =>
{
twr2rd = 8; tcksrx = 4; tckesr = 3; trd2wr = 4; trasmax = 27; twtp = 12; tcke = 2; tmod = 6; tmrd = 2; tmrw = 0; tcwl = 3; tcl = 3; wr_latency = 1; t_rdata_en = 1; mr3 = 0; mr2 = 0; mr1 = 0; mr0 = 0; tdinit3 = 0; tdinit2 = 0; tdinit1 = 0; tdinit0 = 0; }
}
trtp = 4;
if (para.dram_mr0 & 0xffff0000) == 0 {
para.dram_mr0 = mr0
};
if (para.dram_mr1 & 0xffff0000) == 0 {
para.dram_mr1 = mr1
};
if (para.dram_mr2 & 0xffff0000) == 0 {
para.dram_mr2 = mr2
};
if (para.dram_mr3 & 0xffff0000) == 0 {
para.dram_mr3 = mr3
};
writel(DRAM_MR0, para.dram_mr0);
writel(DRAM_MR1, para.dram_mr1);
writel(DRAM_MR2, para.dram_mr2);
writel(DRAM_MR3, para.dram_mr3);
writel(DRAM_ODTX, (para.dram_odt_en >> 4) & 0x3);
let mut val: u32;
val = (twtp << 24) | (tfaw << 16) as u32 | (trasmax << 8) | (tras << 0) as u32;
writel(DRAMTMG0, val);
val = (txp << 16) as u32 | (trtp << 8) as u32 | (trc << 0) as u32;
writel(DRAMTMG1, val);
val = (tcwl << 24) | (tcl << 16) as u32 | (trd2wr << 8) | (twr2rd << 0);
writel(DRAMTMG2, val);
val = (tmrw << 16) | (tmrd << 12) | (tmod << 0);
writel(DRAMTMG3, val);
val = (trcd << 24) as u32 | (tccd << 16) as u32 | (trrd << 8) as u32 | (trp << 0) as u32;
writel(DRAMTMG4, val);
val = (tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0);
writel(DRAMTMG5, val);
val = readl(DRAMTMG8);
val &= 0x0fff0000;
val |= if para.dram_clk < 800 {
0xf0006600
} else {
0xf0007600
};
val |= 0x10;
writel(DRAMTMG8, val);
val = (0x2 << 24) | (t_rdata_en << 16) | (0x1 << 8) | (wr_latency << 0);
writel(PITMG0, val);
writel(PTR3, (tdinit0 << 0) | (tdinit1 << 20));
writel(PTR4, (tdinit2 << 0) | (tdinit3 << 20));
writel(RFSHTMG, (trefi << 16) | (trfc << 0));
writel(RFSHCTL1, 0x0fff0000 & (trefi << 15));
}
fn eye_delay_compensation(para: &mut dram_parameters) {
let mut val: u32;
for i in 0..9 {
let ptr = DAT00IOCR + i * 4;
val = readl(ptr);
val |= (para.dram_tpr11 << 9) & 0x1e00;
val |= (para.dram_tpr12 << 1) & 0x001e;
writel(ptr, val);
}
for i in 0..9 {
let ptr = DAT01IOCR + i * 4;
val = readl(ptr);
val |= ((para.dram_tpr11 >> 4) << 9) & 0x1e00;
val |= ((para.dram_tpr12 >> 4) << 1) & 0x001e;
writel(ptr, val);
}
val = readl(PGCR0);
writel(PGCR0, val & 0xfbffffff);
val = readl(0x3103334);
val |= ((para.dram_tpr11 >> 16) << 9) & 0x1e00;
val |= ((para.dram_tpr12 >> 16) << 1) & 0x001e;
writel(0x3103334, val);
val = readl(0x3103338);
val |= ((para.dram_tpr11 >> 16) << 9) & 0x1e00;
val |= ((para.dram_tpr12 >> 16) << 1) & 0x001e;
writel(0x3103338, val);
val = readl(0x31033b4);
val |= ((para.dram_tpr11 >> 20) << 9) & 0x1e00;
val |= ((para.dram_tpr12 >> 20) << 1) & 0x001e;
writel(0x31033b4, val);
val = readl(0x31033b8);
val |= ((para.dram_tpr11 >> 20) << 9) & 0x1e00;
val |= ((para.dram_tpr12 >> 20) << 1) & 0x001e;
writel(0x31033b8, val);
val = readl(0x310333c);
val |= ((para.dram_tpr11 >> 16) << 25) & 0x1e000000;
writel(0x310333c, val);
val = readl(0x31033bc);
val |= ((para.dram_tpr11 >> 20) << 25) & 0x1e000000;
writel(0x31033bc, val);
val = readl(PGCR0);
writel(PGCR0, val | 0x04000000);
sdelay(1);
for i in 0..15 {
let ptr = 0x3103240 + i * 4;
val = readl(ptr);
val |= ((para.dram_tpr10 >> 4) << 8) & 0x0f00;
writel(ptr, val);
}
for i in 0..6 {
let ptr = 0x3103228 + i * 4;
val = readl(ptr);
val |= ((para.dram_tpr10 >> 4) << 8) & 0x0f00;
writel(ptr, val);
}
let val = readl(0x3103218);
writel(0x3103218, val | (para.dram_tpr10 << 8) & 0x0f00);
let val = readl(0x310321c);
writel(0x310321c, val | (para.dram_tpr10 << 8) & 0x0f00);
let val = readl(0x3103280);
writel(0x3103280, val | ((para.dram_tpr10 >> 12) << 8) & 0x0f00);
}
fn mctl_channel_init(para: &mut dram_parameters) -> Result<(), &'static str> {
let dqs_gating_mode = (para.dram_tpr13 >> 2) & 0x3;
let mut val;
val = readl(UNKNOWN7) & 0xfffff000;
val |= (para.dram_clk >> 1) - 1;
writel(UNKNOWN7, val);
val = readl(MRCTRL0) & 0xfffff0ff;
writel(MRCTRL0, val | 0x300);
val = readl(DX0GCR0) & 0xffffffcf;
val |= ((!para.dram_odt_en) << 5) & 0x20;
if para.dram_clk > 672 {
val &= 0xffff09f1;
val |= 0x00000400;
} else {
val &= 0xffff0ff1;
}
writel(DX0GCR0, val);
val = readl(DX1GCR0) & 0xffffffcf;
val |= ((!para.dram_odt_en) << 5) & 0x20;
if para.dram_clk > 672 {
val &= 0xffff09f1;
val |= 0x00000400;
} else {
val &= 0xffff0ff1;
}
writel(DX1GCR0, val);
val = readl(UNDOC1);
writel(UNDOC1, val | 0x2);
eye_delay_compensation(para);
val = readl(MRCTRL0);
const PLL_SSCG_X: usize = 0x31030bc;
match dqs_gating_mode {
1 => {
val &= !(0xc0); writel(MRCTRL0, val);
let val = readl(PLL_SSCG_X);
writel(PLL_SSCG_X, val & 0xfffffef8);
}
2 => {
val &= !(0xc0); val |= 0x80;
writel(MRCTRL0, val);
let mut val = readl(PLL_SSCG_X);
val &= 0xfffffef8;
val |= ((para.dram_tpr13 >> 16) & 0x1f) - 2;
val |= 0x100;
writel(PLL_SSCG_X, val);
let val = readl(DQS_GATING_X) & 0x7fffffff;
writel(DQS_GATING_X, val | 0x08000000);
}
_ => {
val &= !(0x40); writel(MRCTRL0, val);
sdelay(10);
let val = readl(MRCTRL0);
writel(MRCTRL0, val | 0xc0);
}
}
val = readl(UNKNOWN16);
val &= 0xf0000000;
val |= if para.dram_para2 & (1 << 12) > 0 {
0x03000001
} else {
0x01000007
}; writel(UNKNOWN16, val);
if readl(SOME_STATUS) & (1 << 16) > 0 {
val = readl(SOME_OTHER);
writel(SOME_OTHER, val & 0xfffffffd);
sdelay(10);
}
val = readl(ZQ_CFG) & 0xfc000000;
val |= para.dram_zq & 0x00ffffff;
val |= 0x02000000;
writel(ZQ_CFG, val);
val = if dqs_gating_mode == 1 {
writel(PIR, 0x52); writel(PIR, 0x53);
while (readl(PGSR0) & 0x1) == 0 {} sdelay(10);
if para.dram_type == 3 {
0x5a0
}
else {
0x520
}
} else {
if (readl(SOME_STATUS) & (1 << 16)) == 0 {
if para.dram_type == 3 {
0x1f2
}
else {
0x172
}
} else {
0x62
}
};
writel(PIR, val); writel(PIR, val | 1); sdelay(10);
while (readl(PGSR0) & 0x1) == 0 {}
if readl(SOME_STATUS) & (1 << 16) > 0 {
val = readl(UNKNOWN14);
val &= 0xf9ffffff;
val |= 0x04000000;
writel(UNKNOWN14, val);
sdelay(10);
val = readl(UNKNOWN15);
writel(UNKNOWN15, val | 0x1);
while (readl(STATR_X) & 0x7) != 0x3 {}
val = readl(SOME_OTHER);
writel(SOME_OTHER, val & 0xfffffffe);
sdelay(10);
val = readl(UNKNOWN15);
writel(UNKNOWN15, val & 0xfffffffe);
while (readl(STATR_X) & 0x7) != 0x1 {}
sdelay(15);
if dqs_gating_mode == 1 {
val = readl(MRCTRL0);
val &= 0xffffff3f;
writel(MRCTRL0, val);
val = readl(UNKNOWN14);
val &= 0xf9ffffff;
val |= 0x02000000;
writel(UNKNOWN14, val);
sdelay(1);
writel(PIR, 0x401);
while (readl(PGSR0) & 0x1) == 0 {}
}
}
val = readl(PGSR0);
if ((val >> 20) & 0xff != 0) && (val & 0x100000) != 0 {
return Err("ZQ calibration error, check external 240 ohm resistor.");
}
while (readl(STATR_X) & 0x1) == 0 {}
val = readl(UNKNOWN13);
writel(UNKNOWN13, val | 0x80000000);
sdelay(10);
val = readl(UNKNOWN13);
writel(UNKNOWN13, val & 0x7fffffff);
sdelay(10);
val = readl(UNKNOWN12);
writel(UNKNOWN12, val | 0x80000000);
sdelay(10);
val = readl(UNKNOWN14);
writel(UNKNOWN14, val & 0xf9ffffff);
if dqs_gating_mode == 1 {
val = readl(DQS_GATING_X);
val &= 0xffffff3f;
val |= 0x00000040;
writel(DQS_GATING_X, val);
}
Ok(())
}
fn mctl_core_init(para: &mut dram_parameters) -> Result<(), &'static str> {
mctl_sys_init(para);
mctl_vrefzq_init(para);
mctl_com_init(para);
unsafe {
mctl_phy_ac_remapping(para);
}
auto_set_timing_para(para);
mctl_channel_init(para)
}
fn dramc_get_dram_size() -> u32 {
let low = readl(MC_WORK_MODE_RANK0_1);
let mut temp = (low >> 8) & 0xf; temp += (low >> 4) & 0xf; temp += (low >> 2) & 0x3; temp -= 14; let size0 = 1 << temp;
temp = low & 0x3; if temp == 0 {
return size0;
}
let high = readl(MC_WORK_MODE_RANK0_2);
temp = high & 0x3;
if temp == 0 {
return 2 * size0;
}
temp = (high >> 8) & 0xf; temp += (high >> 4) & 0xf; temp += (high >> 2) & 0x3; temp -= 14; let size1 = 1 << temp;
return size0 + size1; }
fn dqs_gate_detect(para: &mut dram_parameters) -> Result<&'static str, &'static str> {
if readl(PGSR0) & (1 << 22) != 0 {
let dx0 = (readl(UNKNOWN4) >> 24) & 0x3;
let dx1 = (readl(UNKNOWN5) >> 24) & 0x3;
if dx0 == 2 {
let mut rval = para.dram_para2;
rval &= 0xffff0ff0;
if dx0 != dx1 {
rval |= 0x1;
para.dram_para2 = rval;
return Ok("[AUTO DEBUG] single rank and half DQ!");
}
para.dram_para2 = rval;
return Ok("single rank, full DQ");
} else if dx0 == 0 {
let mut rval = para.dram_para2;
rval &= 0xfffffff0; rval |= 0x00001001; para.dram_para2 = rval;
return Ok("dual rank, half DQ!");
} else {
if para.dram_tpr13 & (1 << 29) != 0 {
}
return Err("dqs gate detect");
}
} else {
let mut rval = para.dram_para2;
rval &= 0xfffffff0;
rval |= 0x00001000;
para.dram_para2 = rval;
return Ok("dual rank, full DQ");
}
}
fn dramc_simple_wr_test(mem_mb: u32, len: u32) -> Result<(), &'static str> {
let offs: usize = (mem_mb as usize >> 1) << 18; let patt1: u32 = 0x01234567;
let patt2: u32 = 0xfedcba98;
for i in 0..len {
let addr = RAM_BASE + 4 * i as usize;
writel(addr, patt1 + i);
writel(addr + offs, patt2 + i);
}
for i in 0..len {
let addr = RAM_BASE + 4 * i as usize;
let val = readl(addr);
let exp = patt1 + i;
if val != exp {
return Err("base");
}
let val = readl(addr + offs);
let exp = patt2 + i;
if val != exp {
return Err("offs");
}
}
Ok(())
}
fn auto_scan_dram_size(para: &mut dram_parameters) -> Result<(), &'static str> {
mctl_core_init(para)?;
for i in 0..64 {
let ptr = RAM_BASE + 4 * i;
let val = if i & 1 > 0 { ptr } else { !ptr };
writel(ptr, val as u32);
}
let maxrank = if para.dram_para2 & 0xf000 == 0 { 1 } else { 2 };
let mut mc_work_mode = MC_WORK_MODE_RANK0_1;
let mut offs = 0;
fn scan_for_addr_wrap() -> u32 {
for i in 11..17 {
let mut done = true;
for j in 0..64 {
let ptr = RAM_BASE + j * 4;
let chk = ptr + (1 << (i + 11));
let exp = if j & 1 != 0 { ptr } else { !ptr };
if readl(chk) != exp as u32 {
done = false;
break;
}
}
if done {
return i;
}
}
return 16;
}
fn scan_for_addr_wrap2() -> u32 {
for i in 9..15 {
let mut done = true;
for j in 0..64 {
let ptr = RAM_BASE + j * 4;
let chk = ptr + (1 << i);
let exp = if j & 1 != 0 { ptr } else { !ptr };
if readl(chk) != exp as u32 {
done = false;
break;
}
}
if done {
return i;
}
}
return 13;
}
for rank in 0..maxrank {
let mut rval = readl(mc_work_mode);
rval &= 0xfffff0f3;
rval |= 0x000006f0;
writel(mc_work_mode, rval);
while readl(mc_work_mode) != rval {}
let i = scan_for_addr_wrap();
if VERBOSE {
#[cfg(feature = "log")]
println!("rank {} row = {}", rank, i).ok();
}
let shft = 4 + offs;
rval = para.dram_para1;
rval &= !(0xff << shft);
rval |= i << shft;
para.dram_para1 = rval;
if rank == 1 {
rval = readl(MC_WORK_MODE_RANK0_1);
rval &= 0xfffff003;
rval |= 0x000006a4;
writel(MC_WORK_MODE_RANK0_1, rval);
}
rval = readl(mc_work_mode);
rval &= 0xfffff003;
rval |= 0x000006a4;
writel(mc_work_mode, rval);
while readl(mc_work_mode) != rval {}
let mut j = 0;
for i in 0..63 {
let chk = RAM_BASE + (1 << 22) + i * 4;
let ptr = RAM_BASE + i * 4;
let exp = (if i & 1 != 0 { ptr } else { !ptr }) as u32;
if readl(chk) != exp {
j = 1;
break;
}
}
let banks = (j + 1) << 2; if VERBOSE {
#[cfg(feature = "log")]
println!("rank {} bank = {}", rank, banks).ok();
#[cfg(not(feature = "log"))]
let _ = banks;
}
let shft = 12 + offs;
rval = para.dram_para1;
rval &= !(0xf << shft);
rval |= j << shft;
para.dram_para1 = rval;
if rank == 1 {
rval = readl(MC_WORK_MODE_RANK0_1);
rval &= 0xfffff003;
rval |= 0x00000aa0;
writel(MC_WORK_MODE_RANK0_1, rval);
}
rval = readl(mc_work_mode);
rval &= 0xfffff003;
rval |= 0x00000aa0;
writel(mc_work_mode, rval);
while readl(mc_work_mode) != rval {}
let i = scan_for_addr_wrap2();
let pgsize = if i == 9 { 0 } else { 1 << (i - 10) };
if VERBOSE {
#[cfg(feature = "log")]
println!("rank {} page size = {}KB", rank, pgsize).ok();
}
let shft = offs;
rval = para.dram_para1;
rval &= !(0xf << shft);
rval |= pgsize << shft;
para.dram_para1 = rval;
{
rval = readl(MC_WORK_MODE_RANK1_1); rval &= 0xfffff003;
rval |= 0x000006f0;
writel(MC_WORK_MODE_RANK1_1, rval);
rval = readl(MC_WORK_MODE_RANK1_2); rval &= 0xfffff003;
rval |= 0x000006f0;
writel(MC_WORK_MODE_RANK1_2, rval);
}
if rank != maxrank {
if rank == 1 {
rval = readl(MC_WORK_MODE_RANK1_1); rval &= 0xfffff003;
rval |= 0x000006f0;
writel(MC_WORK_MODE_RANK1_1, rval);
rval = readl(MC_WORK_MODE_RANK1_2); rval &= 0xfffff003;
rval |= 0x000006f0;
writel(MC_WORK_MODE_RANK1_2, rval);
}
offs += 16; mc_work_mode += 4; }
}
Ok(())
}
fn auto_scan_dram_rank_width(para: &mut dram_parameters) -> Result<(), &'static str> {
let s1 = para.dram_tpr13;
let s2 = para.dram_para1;
para.dram_para1 = 0x00b000b0;
para.dram_para2 = (para.dram_para2 & 0xfffffff0) | 0x1000;
para.dram_tpr13 = (s1 & 0xfffffff7) | 0x5;
mctl_core_init(para)?;
if readl(PGSR0) & (1 << 20) != 0 {
return Err("auto scan rank/width");
}
dqs_gate_detect(para)?;
para.dram_tpr13 = s1;
para.dram_para1 = s2;
Ok(())
}
fn auto_scan_dram_config(para: &mut dram_parameters) -> Result<(), &'static str> {
if para.dram_tpr13 & (1 << 14) == 0 {
auto_scan_dram_rank_width(para)?
}
if para.dram_tpr13 & (1 << 0) == 0 {
auto_scan_dram_size(para)?
}
if (para.dram_tpr13 & (1 << 15)) == 0 {
para.dram_tpr13 |= 0x6003;
}
Ok(())
}
pub fn init_dram(para: &mut dram_parameters) -> usize {
if para.dram_tpr13 & (1 << 16) > 0 {
if VERBOSE {
#[cfg(feature = "log")]
println!("DRAM only has internal ZQ.").ok();
}
writel(RES_CAL_CTRL_REG, readl(RES_CAL_CTRL_REG) | 0x100);
writel(RES240_CTRL_REG, 0);
sdelay(10);
} else {
writel(ANALOG_SYS_PWROFF_GATING_REG, 0); writel(RES_CAL_CTRL_REG, readl(RES_CAL_CTRL_REG) & !0x003);
sdelay(10);
writel(RES_CAL_CTRL_REG, readl(RES_CAL_CTRL_REG) & !0x108);
sdelay(10);
writel(RES_CAL_CTRL_REG, readl(RES_CAL_CTRL_REG) | 0x001);
sdelay(20);
if VERBOSE {
let zq_val = readl(ZQ_VALUE);
#[cfg(feature = "log")]
println!("ZQ: {}", zq_val).ok();
#[cfg(not(feature = "log"))]
let _ = zq_val;
}
}
let rc = get_pmu_exists();
if VERBOSE {
#[cfg(feature = "log")]
println!("PMU exists? {}", rc).ok();
}
if !rc {
dram_vol_set(para);
} else {
if para.dram_type == 2 {
set_ddr_voltage(1800);
} else if para.dram_type == 3 {
set_ddr_voltage(1500);
}
}
if (para.dram_tpr13 & 0x1) == 0 {
if let Err(msg) = auto_scan_dram_config(para) {
#[cfg(feature = "log")]
println!("config fail {}", msg).ok();
#[cfg(not(feature = "log"))]
let _ = msg;
return 0;
}
}
let dtype = match para.dram_type {
2 => "DDR2",
3 => "DDR3",
_ => "",
};
#[cfg(feature = "log")]
println!("{}@{}MHz", dtype, para.dram_clk).ok();
#[cfg(not(feature = "log"))]
let _ = dtype;
if VERBOSE {
if (para.dram_odt_en & 0x1) == 0 {
#[cfg(feature = "log")]
println!("ODT off").ok();
} else {
#[cfg(feature = "log")]
println!("ZQ: {}", para.dram_zq).ok();
}
}
if VERBOSE {
if (para.dram_mr1 & 0x44) == 0 {
#[cfg(feature = "log")]
println!("ODT off").ok();
} else {
#[cfg(feature = "log")]
println!("ODT: {}", para.dram_mr1).ok();
}
}
if let Err(msg) = mctl_core_init(para) {
#[cfg(feature = "log")]
println!("init error {}", msg).ok();
#[cfg(not(feature = "log"))]
let _ = msg;
return 0;
};
let mut rc: u32 = para.dram_para2;
if rc != 0 {
rc = (rc & 0x7fff0000) >> 16;
} else {
rc = dramc_get_dram_size();
para.dram_para2 = (para.dram_para2 & 0xffff) | rc << 16;
}
let mem_size = rc;
if VERBOSE {
#[cfg(feature = "log")]
println!("DRAM: {}M", mem_size).ok();
}
if para.dram_tpr13 & (1 << 30) != 0 {
let rc = readl(para.dram_tpr8 as usize);
writel(UNKNOWN11, if rc == 0 { 0x10000200 } else { rc });
writel(UNKNOWN10, 0x40a);
writel(UNKNOWN15, readl(UNKNOWN15) | 1);
} else {
writel(UNKNOWN11, readl(UNKNOWN11) & 0xffff0000);
writel(UNKNOWN15, readl(UNKNOWN15) & (!0x1));
}
rc = readl(PGCR0) & !(0xf000);
if (para.dram_tpr13 & 0x200) == 0 {
if para.dram_type != 6 {
writel(PGCR0, rc);
}
} else {
writel(PGCR0, rc | 0x5000);
}
writel(ZQ_CFG, readl(ZQ_CFG) | (1 << 31));
if para.dram_tpr13 & (1 << 8) != 0 {
writel(0x31030b8, readl(ZQ_CFG) | 0x300);
}
let mut rc = readl(MRCTRL0);
if para.dram_tpr13 & (1 << 16) != 0 {
rc &= 0xffffdfff;
} else {
rc |= 0x00002000;
}
writel(MRCTRL0, rc);
if para.dram_type == 7 {
let rc = readl(UNKNOWN8) & 0xfff0ffff;
writel(UNKNOWN8, rc | 0x0001000);
}
dram_enable_all_master();
let len = 4096; if para.dram_tpr13 & (1 << 28) != 0 {
rc = readl(SOME_STATUS);
if rc & (1 << 16) != 0 {
return 0;
}
if let Err(msg) = dramc_simple_wr_test(mem_size, len) {
#[cfg(feature = "log")]
println!("test fail {}", msg).ok();
#[cfg(not(feature = "log"))]
let _ = msg;
return 0;
}
#[cfg(feature = "log")]
println!("test OK").ok();
}
handler_super_standby();
mem_size as usize
}
pub fn init() -> usize {
#[rustfmt::skip]
let mut dram_para: dram_parameters = dram_parameters {
dram_clk: 792,
dram_type: 0x0000_0003,
dram_zq: 0x007b_7bfb,
dram_odt_en: 0x0000_0001,
#[cfg(feature="nezha")]
dram_para1: 0x0000_10f2,
#[cfg(feature="lichee")]
dram_para1: 0x0000_10d2,
dram_para2: 0x0000_0000,
dram_mr0: 0x0000_1c70,
dram_mr1: 0x0000_0042,
#[cfg(feature="nezha")]
dram_mr2: 0x0000_0000,
#[cfg(feature="lichee")]
dram_mr2: 0x0000_0018,
dram_mr3: 0x0000_0000,
dram_tpr0: 0x004a_2195,
dram_tpr1: 0x0242_3190,
dram_tpr2: 0x0008_b061,
dram_tpr3: 0xb478_7896,
dram_tpr4: 0x0000_0000,
dram_tpr5: 0x4848_4848,
dram_tpr6: 0x0000_0048,
dram_tpr7: 0x1620_121e,
dram_tpr8: 0x0000_0000,
dram_tpr9: 0x0000_0000,
dram_tpr10: 0x0000_0000,
#[cfg(feature="nezha")]
dram_tpr11: 0x0076_0000,
#[cfg(feature="lichee")]
dram_tpr11: 0x0087_0000,
#[cfg(feature="nezha")]
dram_tpr12: 0x0000_0035,
#[cfg(feature="lichee")]
dram_tpr12: 0x0000_0024,
#[cfg(feature="nezha")]
dram_tpr13: 0x3405_0101,
#[cfg(feature="lichee")]
dram_tpr13: 0x3405_0100,
};
return init_dram(&mut dram_para);
}