mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
start to lay in code rework for booting on real chips
This commit is contained in:
parent
05d2f3d6a9
commit
a781b2e15d
1 changed files with 203 additions and 38 deletions
|
|
@ -2,8 +2,22 @@ use cramium_hal::iox::{Iox, IoxDir, IoxEnable, IoxFunction, IoxPort};
|
|||
use cramium_hal::udma;
|
||||
use utralib::generated::*;
|
||||
|
||||
// Notes about the reset vector location
|
||||
// This can be set using fuses in the IFR (also called 'info') region
|
||||
// The offset is an 8-bit value, which is shifted into a final location
|
||||
// according to the following formula:
|
||||
//
|
||||
// let short_offset: u8 = OFFSET;
|
||||
// let phys_offset: u32 = 0x6000_0000 + short_offset << 14;
|
||||
//
|
||||
// The RV32-IV IFR fuse location is at row 6, byte 8.
|
||||
// Each row is 256 bits wide.
|
||||
// This puts the byte-address hex offset at (6 * 256 + 8 * 8) / 8 = 0xC8
|
||||
// within the IFR region. Total IFR region size is 0x200.
|
||||
|
||||
pub const RAM_SIZE: usize = utralib::generated::HW_SRAM_MEM_LEN;
|
||||
pub const RAM_BASE: usize = utralib::generated::HW_SRAM_MEM;
|
||||
pub const FLASH_BASE: usize = utralib::generated::HW_RERAM_MEM;
|
||||
|
||||
// Locate the hard-wired IFRAM allocations for UDMA
|
||||
pub const UART_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 4096;
|
||||
|
|
@ -14,7 +28,7 @@ pub const SPIM_RAM_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRA
|
|||
pub const SPIM_FLASH_IFRAM_ADDR: usize = utralib::HW_IFRAM0_MEM + utralib::HW_IFRAM0_MEM_LEN - 4 * 4096;
|
||||
|
||||
// location of kernel, as offset from the base of ReRAM. This needs to match up with what is in link.x.
|
||||
pub const KERNEL_OFFSET: usize = 0x28000;
|
||||
pub const KERNEL_OFFSET: usize = 0x4_0000;
|
||||
|
||||
#[cfg(feature = "cramium-soc")]
|
||||
pub fn early_init() {
|
||||
|
|
@ -26,44 +40,78 @@ pub fn early_init() {
|
|||
//
|
||||
// Not all design changes have a rhyme or reason at this stage -- sometimes "it just works,
|
||||
// don't futz with it" is actually the answer that goes to production.
|
||||
|
||||
/*
|
||||
// "actual SoC" parameters -- swap the comment here when silicon comes back
|
||||
// not making it a "feature" because this is a one-way gate, I don't see
|
||||
// any reason why we'd go back to using the emulator board if we have silicon.
|
||||
use utralib::utra::sysctrl;
|
||||
unsafe {
|
||||
(0x400400a0 as *mut u32).write_volatile(0x1F598); // F
|
||||
crate::println!("F: {:08x}", ((0x400400a0 as *const u32).read_volatile()));
|
||||
let poke_array: [(u32, u32, bool); 12] = [
|
||||
(0x400400a4, 0x2812, false), // MN
|
||||
(0x400400a8, 0x3301, false), // Q
|
||||
(0x40040090, 0x0032, true), // setpll
|
||||
(0x40040014, 0x7f7f, false), // fclk
|
||||
(0x40040018, 0x7f7f, false), // aclk
|
||||
(0x4004001c, 0x3f3f, false), // hclk
|
||||
(0x40040020, 0x1f1f, false), // iclk
|
||||
(0x40040024, 0x0f0f, false), // pclk
|
||||
(0x40040010, 0x0001, false), // sel0
|
||||
(0x4004002c, 0x0032, true), // setcgu
|
||||
(0x40040060, 0x0003, false), // aclk gates
|
||||
(0x40040064, 0x0003, false), // hclk gates
|
||||
];
|
||||
for &(addr, dat, is_u32) in poke_array.iter() {
|
||||
let rbk = if is_u32 {
|
||||
(addr as *mut u32).write_volatile(dat);
|
||||
(addr as *const u32).read_volatile()
|
||||
} else {
|
||||
(addr as *mut u16).write_volatile(dat as u16);
|
||||
(addr as *const u16).read_volatile() as u32
|
||||
};
|
||||
if dat != rbk {
|
||||
crate::println!("{:08x}(w) != {:08x}(r)", dat, rbk);
|
||||
} else {
|
||||
crate::println!("{:08x} ok", dat);
|
||||
// this is MANDATORY for any chip stapbility in real silicon, as the initial
|
||||
// clocks are too unstable to do anything otherwise. However, for the simulation
|
||||
// environment, this can (should?) be dropped
|
||||
let daric_cgu = sysctrl::HW_SYSCTRL_BASE as *mut u32;
|
||||
daric_cgu.add(sysctrl::SFR_CGUSEL1.offset()).write_volatile(1); // 0: RC, 1: XTAL
|
||||
daric_cgu.add(sysctrl::SFR_CGUFSCR.offset()).write_volatile(48); // external crystal is 48MHz
|
||||
|
||||
daric_cgu.add(sysctrl::SFR_CGUSET.offset()).write_volatile(0x32);
|
||||
|
||||
let duart = utra::duart::HW_DUART_BASE as *mut u32;
|
||||
duart.add(utra::duart::SFR_CR.offset()).write_volatile(0);
|
||||
duart.add(utra::duart::SFR_ETUC.offset()).write_volatile(24);
|
||||
duart.add(utra::duart::SFR_CR.offset()).write_volatile(1);
|
||||
}
|
||||
// this block is mandatory in all cases to get clocks set into some consistent, expected mode
|
||||
unsafe {
|
||||
let daric_cgu = sysctrl::HW_SYSCTRL_BASE as *mut u32;
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_0.offset()).write_volatile(0x7f7f);
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_1.offset()).write_volatile(0x7f7f);
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_2.offset()).write_volatile(0x3f3f);
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_3.offset()).write_volatile(0x1f1f);
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_4.offset()).write_volatile(0x0f0f);
|
||||
daric_cgu.add(utra::sysctrl::SFR_ACLKGR.offset()).write_volatile(0xFF);
|
||||
daric_cgu.add(utra::sysctrl::SFR_HCLKGR.offset()).write_volatile(0xFF);
|
||||
daric_cgu.add(utra::sysctrl::SFR_ICLKGR.offset()).write_volatile(0xFF);
|
||||
daric_cgu.add(utra::sysctrl::SFR_PCLKGR.offset()).write_volatile(0xFF);
|
||||
daric_cgu.add(utra::sysctrl::SFR_CGUSET.offset()).write_volatile(0x32);
|
||||
|
||||
let duart = utra::duart::HW_DUART_BASE as *mut u32;
|
||||
// enable DUART
|
||||
duart.add(utra::duart::SFR_CR.offset()).write_volatile(1);
|
||||
}
|
||||
// unsafe, direct-writes to address offsets are used here instead of the UTRA abstraction
|
||||
// because there are some quirks in the early boot path that make the system more stable
|
||||
// if all register accesses are in-lined.
|
||||
#[cfg(feature = "boot-delay")]
|
||||
unsafe {
|
||||
// this block should immediately follow the CGU setup
|
||||
let duart = utra::duart::HW_DUART_BASE as *mut u32;
|
||||
// ~2 second delay for debugger to attach
|
||||
let msg = b"boot\r";
|
||||
for j in 0..20_000 {
|
||||
// variable count of .'s to create a sense of motion on the console
|
||||
for _ in 0..j & 0x7 {
|
||||
while duart.add(utra::duart::SFR_SR.offset()).read_volatile() != 0 {}
|
||||
duart.add(utra::duart::SFR_TXD.offset()).write_volatile('.' as char as u32);
|
||||
}
|
||||
for &b in msg {
|
||||
while duart.add(utra::duart::SFR_SR.offset()).read_volatile() != 0 {}
|
||||
duart.add(utra::duart::SFR_TXD.offset()).write_volatile(b as char as u32);
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
#[cfg(feature = "sram-margin")]
|
||||
unsafe {
|
||||
// set SRAM delay to max - opens up timing margin as much a possible, supposedly?
|
||||
let sram_ctl = utra::coresub_sramtrm::HW_CORESUB_SRAMTRM_BASE as *mut u32;
|
||||
let waitcycles = 3;
|
||||
sram_ctl.add(utra::coresub_sramtrm::SFR_SRAM0.offset()).write_volatile(
|
||||
(sram_ctl.add(utra::coresub_sramtrm::SFR_SRAM0.offset()).read_volatile() & !0x18)
|
||||
| ((waitcycles << 3) & 0x18),
|
||||
);
|
||||
sram_ctl.add(utra::coresub_sramtrm::SFR_SRAM1.offset()).write_volatile(
|
||||
(sram_ctl.add(utra::coresub_sramtrm::SFR_SRAM1.offset()).read_volatile() & !0x18)
|
||||
| ((waitcycles << 3) & 0x18),
|
||||
);
|
||||
}
|
||||
// SoC emulator board parameters (deals with MMCM instead of PLL)
|
||||
// Remove this once we feel confident we're sticking with SoC hardware.
|
||||
/*
|
||||
unsafe {
|
||||
let poke_array: [(u32, u32, bool); 9] = [
|
||||
(0x40040030, 0x0001, true), // cgusel1
|
||||
|
|
@ -90,7 +138,7 @@ pub fn early_init() {
|
|||
crate::println!("{:08x} ok", dat);
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
// Configure the UDMA UART. This UART's settings will be used as the initial console UART.
|
||||
// This is configured in the loader so that the log crate does not have a dependency
|
||||
|
|
@ -125,7 +173,7 @@ pub fn early_init() {
|
|||
);
|
||||
|
||||
let baudrate: u32 = 115200;
|
||||
let freq: u32 = 100_000_000;
|
||||
let freq: u32 = 45_882_000;
|
||||
|
||||
// the address of the UART buffer is "hard-allocated" at an offset one page from the top of
|
||||
// IFRAM0. This is a convention that must be respected by the UDMA UART library implementation
|
||||
|
|
@ -154,7 +202,7 @@ pub fn early_init() {
|
|||
// do a PL230/PIO test. Toggles PB15 (PIO0) with an LFSR sequence.
|
||||
let mut pl230 = xous_pl230::Pl230::new();
|
||||
xous_pl230::pl230_tests::units::basic_tests(&mut pl230);
|
||||
xous_pl230::pl230_tests::units::pio_test(&mut pl230);
|
||||
// xous_pl230::pl230_tests::units::pio_test(&mut pl230);
|
||||
|
||||
const BANNER: &'static str = "\n\rKeep pressing keys to continue boot...\r\n";
|
||||
udma_uart.write(BANNER.as_bytes());
|
||||
|
|
@ -232,3 +280,120 @@ fn test_duart() {
|
|||
|
||||
#[cfg(feature = "platform-tests")]
|
||||
pub fn platform_tests() { test_duart(); }
|
||||
|
||||
pub unsafe fn init_clock_asic(freq_hz: u32) {
|
||||
let daric_cgu = sysctrl::HW_SYSCTRL_BASE as *mut u32;
|
||||
|
||||
const F_MHZ: u32 = 1_000_000;
|
||||
const FREQ_0: u32 = 16 * F_MHZ;
|
||||
|
||||
const TBL_Q: [u16; 7] = [
|
||||
// keep later DIV even number as possible
|
||||
0x7777, // 16-32 MHz
|
||||
0x7737, // 32-64
|
||||
0x3733, // 64-128
|
||||
0x3313, // 128-256
|
||||
0x3311, // 256-512 // keep ~ 100MHz
|
||||
0x3301, // 512-1024
|
||||
0x3301, /* 1024-1500
|
||||
* 0x1303, // 256-512
|
||||
* 0x0103, // 512-1024
|
||||
* 0x0001, // 1024-2048 */
|
||||
];
|
||||
const TBL_MUL: [u32; 7] = [
|
||||
64, // 16-32 MHz
|
||||
32, // 32-64
|
||||
16, // 64-128
|
||||
8, // 128-256
|
||||
4, // 256-512
|
||||
2, // 512-1024
|
||||
2, // 1024-2048
|
||||
];
|
||||
const M: u32 = 24 - 1;
|
||||
|
||||
report_api(0xc0c0_0000);
|
||||
let f16_mhz_log2 = (freq_hz / FREQ_0).ilog2() as usize;
|
||||
report_api(f16_mhz_log2 as u32);
|
||||
let n_fxp24: u64 = (((freq_hz as u64) << 24) * TBL_MUL[f16_mhz_log2] as u64) / (2 * F_MHZ as u64);
|
||||
report_api(n_fxp24 as u32);
|
||||
report_api((n_fxp24 >> 32) as u32);
|
||||
let n_frac: u32 = (n_fxp24 & 0x00ffffff) as u32;
|
||||
report_api(n_frac);
|
||||
let pllmn = ((M << 12) & 0x0001F000) | ((n_fxp24 >> 24) & 0x00000fff) as u32;
|
||||
report_api(pllmn);
|
||||
let pllf = n_frac | (if 0 == n_frac { 0 } else { 1 << 24 });
|
||||
report_api(pllf);
|
||||
let pllq = TBL_Q[f16_mhz_log2] as u32;
|
||||
report_api(pllq);
|
||||
|
||||
daric_cgu.add(sysctrl::SFR_CGUSEL1.offset()).write_volatile(1); // 0: RC, 1: XTAL
|
||||
daric_cgu.add(sysctrl::SFR_CGUFSCR.offset()).write_volatile(48); // external crystal is 48MHz
|
||||
daric_cgu.add(sysctrl::SFR_CGUSET.offset()).write_volatile(0x32);
|
||||
|
||||
if freq_hz < 1_000_000 {
|
||||
daric_cgu.add(sysctrl::SFR_IPCOSC.offset()).write_volatile(freq_hz);
|
||||
daric_cgu.add(sysctrl::SFR_IPCARIPFLOW.offset()).write_volatile(0x32); // commit, must write 32
|
||||
}
|
||||
// switch to OSC
|
||||
daric_cgu.add(sysctrl::SFR_CGUSEL0.offset()).write_volatile(0); // clktop sel, 0:clksys, 1:clkpll0
|
||||
daric_cgu.add(sysctrl::SFR_CGUSET.offset()).write_volatile(0x32); // commit
|
||||
|
||||
if 0 == freq_hz {
|
||||
// do nothing
|
||||
} else {
|
||||
// PD PLL
|
||||
daric_cgu
|
||||
.add(sysctrl::SFR_IPCLPEN.offset())
|
||||
.write_volatile(daric_cgu.add(sysctrl::SFR_IPCLPEN.offset()).read_volatile() | 0x02);
|
||||
daric_cgu.add(sysctrl::SFR_IPCARIPFLOW.offset()).write_volatile(0x32); // commit, must write 32
|
||||
|
||||
// delay
|
||||
for _ in 0..1024 {
|
||||
unsafe { core::arch::asm!("nop") };
|
||||
}
|
||||
for _ in 0..4 {
|
||||
report_api(0xc0c0_dddd);
|
||||
}
|
||||
|
||||
// printf ("%s(%4" PRIu32 "MHz) M = 24, N = %4lu.%08lu, Q = %2lu\n",
|
||||
// __FUNCTION__, freqHz / 1000000, (uint32_t)(n_fxp24 >>
|
||||
// 24).write_volatile((uint32_t)((uint64_t)(n_fxp24 & 0x00ffffff) * 100000000/(1UL
|
||||
// <<24)).write_volatile(TBL_MUL[f16MHzLog2]);
|
||||
daric_cgu.add(sysctrl::SFR_IPCPLLMN.offset()).write_volatile(pllmn); // 0x1F598; // ??
|
||||
daric_cgu.add(sysctrl::SFR_IPCPLLF.offset()).write_volatile(pllf); // ??
|
||||
daric_cgu.add(sysctrl::SFR_IPCPLLQ.offset()).write_volatile(pllq); // ?? TODO select DIV for VCO freq
|
||||
|
||||
// VCO bias CPP bias CPI bias
|
||||
// 1 2 3
|
||||
// DARIC_IPC->ipc = (3 << 6) | (5 << 3) | (5);
|
||||
daric_cgu.add(sysctrl::SFR_IPCCR.offset()).write_volatile((1 << 6) | (2 << 3) | (3));
|
||||
daric_cgu.add(sysctrl::SFR_IPCARIPFLOW.offset()).write_volatile(0x32); // commit, must write 32
|
||||
|
||||
daric_cgu
|
||||
.add(sysctrl::SFR_IPCLPEN.offset())
|
||||
.write_volatile(daric_cgu.add(sysctrl::SFR_IPCLPEN.offset()).read_volatile() & !0x02);
|
||||
daric_cgu.add(sysctrl::SFR_IPCARIPFLOW.offset()).write_volatile(0x32); // commit, must write 32
|
||||
|
||||
// delay
|
||||
for _ in 0..1024 {
|
||||
unsafe { core::arch::asm!("nop") };
|
||||
}
|
||||
for _ in 0..4 {
|
||||
report_api(0xc0c0_eeee);
|
||||
}
|
||||
// printf("read reg a0 : %08" PRIx32"\n", *((volatile uint32_t* )0x400400a0));
|
||||
// printf("read reg a4 : %04" PRIx16"\n", *((volatile uint16_t* )0x400400a4));
|
||||
// printf("read reg a8 : %04" PRIx16"\n", *((volatile uint16_t* )0x400400a8));
|
||||
|
||||
// TODO wait/poll lock status?
|
||||
daric_cgu.add(sysctrl::SFR_CGUSEL0.offset()).write_volatile(1); // clktop sel, 0:clksys, 1:clkpll0
|
||||
daric_cgu.add(sysctrl::SFR_CGUSET.offset()).write_volatile(0x32); // commit
|
||||
|
||||
report_api(0xc0c0_ffff);
|
||||
// printf (" MN: 0x%05x, F: 0x%06x, Q: 0x%04x\n",
|
||||
// DARIC_IPC->pll_mn, DARIC_IPC->pll_f, DARIC_IPC->pll_q);
|
||||
// printf (" LPEN: 0x%01x, OSC: 0x%04x, BIAS: 0x%04x,\n",
|
||||
// DARIC_IPC->lpen, DARIC_IPC->osc, DARIC_IPC->ipc);
|
||||
}
|
||||
report_api(0xc0c0_0007);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue