From 5e4f842e67d60a6ebddaf2348cff7cc6f023d28c Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 30 Sep 2025 15:15:21 -0700 Subject: [PATCH 1/5] stm32h7-startup: move pre_init into assembly. Our pre-init routine contains things that need to happen before anything touches RAM. This is not reliably possible from a Rust function, since the compiler may elect to set up a stack frame (and, in our case, definitely does so today). This commit moves it into straight assembly language, ensuring that we have control over the use of RAM. As a pleasant side effect, this also makes it really hard to accidentally put Rust code before it. This is not sufficient, by itself, to eliminate use of RAM early in boot, since the ancient version of cortex-m-rt that we're using has a bug here. But I'll tackle that in a follow-on commit. --- drv/stm32h7-startup/src/lib.rs | 124 +++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/drv/stm32h7-startup/src/lib.rs b/drv/stm32h7-startup/src/lib.rs index 03041e761..3b85828b4 100644 --- a/drv/stm32h7-startup/src/lib.rs +++ b/drv/stm32h7-startup/src/lib.rs @@ -4,64 +4,84 @@ #![no_std] -use cortex_m_rt::pre_init; - #[cfg(feature = "h743")] use stm32h7::stm32h743 as device; #[cfg(feature = "h753")] use stm32h7::stm32h753 as device; -#[cfg(any(feature = "h743", feature = "h753"))] -#[pre_init] -unsafe fn system_pre_init() { - // Configure the power supply to latch the LDO on and prevent further - // reconfiguration. - // - // Normally we would use Peripherals::take() to safely get a reference to - // the PWR block, but that function expects RAM to be initialized and - // writable. At this point, RAM is neither -- because the chip requires us - // to get the power supply configuration right _before it guarantees that - // RAM will work._ - // - // Another case of the cortex_m/stm32 crates being designed with simpler - // systems in mind. - - // Synthesize a pointer using a const fn (which won't hit RAM) and then - // convert it to a reference. We can have a reference to PWR because it's - // hardware, and is thus not uninitialized. - let pwr = &*device::PWR::ptr(); - // Poke CR3 to enable the LDO and prevent further writes. - pwr.cr3.modify(|_, w| w.ldoen().set_bit()); - - // Busy-wait until the ACTVOSRDY bit says that we've stabilized at VOS3. - while !pwr.csr1.read().actvosrdy().bit() { - // spin - } - - // Turn on the internal RAMs. - let rcc = &*device::RCC::ptr(); - rcc.ahb2enr.modify(|_, w| { - w.sram1en() - .set_bit() - .sram2en() - .set_bit() - .sram3en() - .set_bit() - }); - - // Okay, yay, we can use some RAMs now. - - #[cfg(any(feature = "h743", feature = "h753"))] - { - // Workaround for erratum 2.2.9 "Reading from AXI SRAM may lead to data - // read corruption" - limits AXI SRAM read concurrency. - let axi = &*device::AXI::ptr(); - axi.targ7_fn_mod - .modify(|_, w| w.read_iss_override().set_bit()); - } - - // We'll do the rest in system_init. +// System pre-init hook for establishing system properties required by Rust. +// +// This routine must run before anything touches RAM! The cortex-m-rt crate's +// Reset handler ensures this. As a result, we have to write this in raw +// assembly code, to avoid trying to push/pop a stack frame. +// +// Be very careful about reordering or removing things from this function. +core::arch::global_asm! { + ".global __pre_init", + ".type __pre_init_,%function", + ".thumb_func", + ".cfi_startproc", + "__pre_init:", + + // PWR.CR3 has a write-once feature on the LDO enable bit. The processor + // would like the power configuration to be stable before it guarantees that + // writes to RAM will succeed (reference manual 6.4.1 "System supply + // startup"). We're actually perfectly happy with the reset supply + // configuration, which is VOS3 on the LDO. So, we'll write PWR.CR3 just to + // lock it: + " movw r0, :lower16:{PWR_addr}", + " movt r0, :upper16:{PWR_addr}", + " ldr r1, [r0, #{PWR_CR3_offset}]", + " str r1, [r0, #{PWR_CR3_offset}]", + + // Technically we're supposed to ensure that we're stable at VOS3 before + // continuing; this should already be ensured before our code was allowed to + // run, but for safety's sake: + "1: ldr r1, [r0, #{PWR_CSR1_offset}]", + " tst r1, #(1 << {PWR_CSR1_ACTVOSRDY_bit})", + " beq 1b", + + // Turn on all of the smaller non-TCM non-AXI SRAMs, in case the program + // puts data there. + " movw r0, :lower16:{RCC_addr}", + " movt r0, :upper16:{RCC_addr}", + " ldr r1, [r0, #{RCC_AHB2ENR_offset}]", + " orrs r1, #((1 << {RCC_AHB2ENR_SRAM1EN_bit}) \ + | (1 << {RCC_AHB2ENR_SRAM2EN_bit}) \ + | (1 << {RCC_AHB2ENR_SRAM3EN_bit}))", + + // Apply workaround for ST erratum 2.2.9 "Reading from AXI SRAM may lead to + // data read corruption" - limits AXI SRAM read concurrency. + " movw r0, :lower16:{AXI_TARG7_FN_MOD_addr}", + " movt r0, :upper16:{AXI_TARG7_FN_MOD_addr}", + " ldr r1, [r0]", + " orrs r1, #(1 << {AXI_TARG7_FN_MOD_READ_ISS_OVERRIDE_bit})", + " str r1, [r0]", + + // Aaaaand we're done. + " bx lr", + ".cfi_endproc", + ".size __pre_init, . - __pre_init", + + PWR_addr = const 0x5802_4800, //device::PWR::ptr(), + PWR_CSR1_offset = const 0x4, // reference manual 6.8.2 + PWR_CSR1_ACTVOSRDY_bit = const 13, + PWR_CR3_offset = const 0xC, // reference manual 6.8.4 + + RCC_addr = const 0x5802_4400, //device::RCC::ptr(), + RCC_AHB2ENR_offset = const 0x0DC, // reference manual 8.7.42 + RCC_AHB2ENR_SRAM1EN_bit = const 29, // reference manual 8.7.42 + RCC_AHB2ENR_SRAM2EN_bit = const 30, // reference manual 8.7.42 + RCC_AHB2ENR_SRAM3EN_bit = const 31, // reference manual 8.7.42 + + + // The offset from the AXI block to this register is too large to do the + // same base/displacement thing as the other peripherals above, so this + // constant is the result of adding the base address from the reference + // manual (0x5100_0000) to the offset from table 6. + AXI_TARG7_FN_MOD_addr = const 0x5100_8108, + AXI_TARG7_FN_MOD_READ_ISS_OVERRIDE_bit = const 0, // same } pub struct ClockConfig { From 8a0f3fad2777873cc877c58288e26b0911e5d839 Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 30 Sep 2025 15:53:39 -0700 Subject: [PATCH 2/5] sprot-api: remove ability to return SPI errors I noticed that sprot-api depended on spi-api, which is otherwise a very STM32-specific crate (for better or worse). This turns out to be only due to the SprotError::Spi variant... which is never constructed, anywhere. So I removed it. This unblocks the upgrade to stm32h7 0.15. --- drv/sprot-api/Cargo.toml | 1 - drv/sprot-api/src/error.rs | 8 -------- 2 files changed, 9 deletions(-) diff --git a/drv/sprot-api/Cargo.toml b/drv/sprot-api/Cargo.toml index 3fa0d0e60..44fb1b9ea 100644 --- a/drv/sprot-api/Cargo.toml +++ b/drv/sprot-api/Cargo.toml @@ -23,7 +23,6 @@ counters = { path = "../../lib/counters" } derive-idol-err = { path = "../../lib/derive-idol-err" } drv-caboose = { path = "../../drv/caboose" } drv-lpc55-update-api = { path = "../../drv/lpc55-update-api" } -drv-spi-api = { path = "../../drv/spi-api" } drv-update-api = { path = "../../drv/update-api" } dumper-api = { path = "../../task/dumper-api" } ringbuf = { path = "../../lib/ringbuf" } diff --git a/drv/sprot-api/src/error.rs b/drv/sprot-api/src/error.rs index b73ed7961..ab508b874 100644 --- a/drv/sprot-api/src/error.rs +++ b/drv/sprot-api/src/error.rs @@ -8,7 +8,6 @@ use attest_api::AttestError; use derive_more::From; use drv_caboose::CabooseError; use drv_lpc55_update_api::RawCabooseError; -use drv_spi_api::SpiError; use drv_update_api::UpdateError; use dumper_api::DumperError; use hubpack::SerializedSize; @@ -37,7 +36,6 @@ use idol_runtime::RequestError; )] pub enum SprotError { Protocol(#[count(children)] SprotProtocolError), - Spi(#[count(children)] SpiError), Update(#[count(children)] UpdateError), Sprockets(#[count(children)] SprocketsError), Watchdog(#[count(children)] WatchdogError), @@ -47,7 +45,6 @@ impl From for SpError { fn from(value: SprotError) -> Self { match value { SprotError::Protocol(e) => Self::Sprot(e.into()), - SprotError::Spi(e) => Self::Spi(e.into()), SprotError::Update(e) => Self::Update(e.into()), SprotError::Sprockets(e) => Self::Sprockets(e.into()), SprotError::Watchdog(e) => Self::Watchdog(e.into()), @@ -59,7 +56,6 @@ impl From for RotError { fn from(value: SprotError) -> Self { match value { SprotError::Protocol(e) => Self::Sprot(e.into()), - SprotError::Spi(e) => Self::Spi(e.into()), SprotError::Update(e) => Self::Update(e.into()), SprotError::Sprockets(e) => Self::Sprockets(e.into()), SprotError::Watchdog(e) => Self::Watchdog(e.into()), @@ -345,10 +341,6 @@ impl From for AttestDataSprotError { Self::ProtocolDesynchronized } }, - SprotError::Spi(e1) => match e1 { - SpiError::BadTransferSize => Self::SpiBadTransferSize, - SpiError::TaskRestarted => Self::SpiTaskRestarted, - }, // We should never return these but it's safer to return an // enum just in case these come up SprotError::Update(_) => Self::UpdateError, From cecfb7c7628a6e68942770a40df348e3f126e68f Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 30 Sep 2025 16:10:42 -0700 Subject: [PATCH 3/5] hiffy: make drv-spi-api dependency optional Hiffy was unconditionally pulling in the drv-spi-api crate, which meant it needed to build on all platforms, even those for which we don't have SPI support. This is complicated by its build script, which requires SPI config. --- task/hiffy/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/task/hiffy/Cargo.toml b/task/hiffy/Cargo.toml index 0efdbf4d3..48ffc4946 100644 --- a/task/hiffy/Cargo.toml +++ b/task/hiffy/Cargo.toml @@ -10,7 +10,7 @@ drv-hash-api = { path = "../../drv/hash-api", optional = true } drv-i2c-api = { path = "../../drv/i2c-api" } drv-lpc55-gpio-api = { path = "../../drv/lpc55-gpio-api", optional = true } drv-sp-ctrl-api = { path = "../../drv/sp-ctrl-api", optional = true } -drv-spi-api = { path = "../../drv/spi-api" } +drv-spi-api = { path = "../../drv/spi-api", optional = true } drv-sprot-api = { path = "../../drv/sprot-api", optional = true } drv-stm32xx-i2c = { path = "../../drv/stm32xx-i2c", optional = true } drv-stm32xx-sys-api = { path = "../../drv/stm32xx-sys-api", optional = true } @@ -42,7 +42,7 @@ no-ipc-counters = ["idol/no-counters"] testsuite = [ "test-api" ] i2c = [] gpio = [] -spi = [] +spi = ["drv-spi-api"] send = [] send-rw = [] sprot = ["drv-sprot-api"] From 0b3109ccfe36d5013e1353b2d1620488393e4bc1 Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 30 Sep 2025 15:55:08 -0700 Subject: [PATCH 4/5] spi-api: don't silently hide config errors This build script was throwing away any failure to parse global config, which means that e.g. misspelling "DIV256" would instead get you unrelated compile errors in apparently unrelated crates, since code generation would just switch off. This appears to have been done because the lpc55 code was depending on this crate, and it of course doesn't _have_ an stm32h7 global SPI config stanza in its config TOML. I broke that dependency in an earlier commit, so now I'm making the code generation mandatory with error reporting. --- drv/spi-api/build.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drv/spi-api/build.rs b/drv/spi-api/build.rs index d0a757dd3..34ad5b261 100644 --- a/drv/spi-api/build.rs +++ b/drv/spi-api/build.rs @@ -17,21 +17,17 @@ fn main() -> Result<()> { let dest_path = out_dir.join("spi_devices.rs"); let mut file = File::create(dest_path)?; - if let Ok(global_config) = build_util::config::() { - writeln!(&mut file, "pub mod devices {{")?; - for (periph, p) in global_config.spi { - writeln!( - &mut file, - " // {periph} ({} devices)", - p.devices.len() - )?; - for (i, name) in p.devices.keys().enumerate() { - let name = name.to_uppercase(); - writeln!(&mut file, " pub const {name}: u8 = {i};")?; - } + let global_config = build_util::config::()?; + + writeln!(&mut file, "pub mod devices {{")?; + for (periph, p) in global_config.spi { + writeln!(&mut file, " // {periph} ({} devices)", p.devices.len())?; + for (i, name) in p.devices.keys().enumerate() { + let name = name.to_uppercase(); + writeln!(&mut file, " pub const {name}: u8 = {i};")?; } - writeln!(&mut file, "}}")?; } + writeln!(&mut file, "}}")?; Ok(()) } From 1d4e7f8f7d5c6e84f6e0a5af0e375abc82a4f500 Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 30 Sep 2025 15:56:50 -0700 Subject: [PATCH 5/5] Upgrade cortex-m-rt and PACs to ~2022 I noticed that our cortex-m-rt version was generating potentially invalid code in the Reset function -- setting up and tearing down a stack frame, before we've turned on RAM! This bug got fixed in the upstream cortex-m-rt crate, but we haven't upgraded in ... quite a while. This upgrades to a compromise point -- 0.15 of the stm32 pacs. Upgrading farther than that causes massive API incompatibilities, since it looks like they've comprehensively changed the svd2rust generated code. Rather than touch literally every driver in the system, I've settled on 0.15 and left 0.16 as a trap for the future. As you can see, this still required a fair amount of churn, mostly due to renamed enum variants. --- Cargo.lock | 42 +++++++++++--------------- Cargo.toml | 12 ++++---- app/cosmo/base.toml | 4 +-- app/demo-stm32h7-nucleo/app-h743.toml | 2 +- app/demo-stm32h7-nucleo/app-h753.toml | 2 +- app/gemini-bu/app.toml | 2 +- app/gimlet/base.toml | 2 +- app/gimlet/src/main.rs | 18 +++++------ app/gimletlet/base-gimletlet2.toml | 4 +-- app/grapefruit/base.toml | 4 +-- app/minibar/app.toml | 2 +- app/psc/base.toml | 2 +- app/sidecar/base.toml | 2 +- build/spi/src/lib.rs | 21 +++++++------ drv/stm32h7-hash/src/lib.rs | 16 +++++----- drv/stm32h7-spi-server-core/src/lib.rs | 12 ++++---- lib/endoscope/src/main.rs | 18 +++++------ 17 files changed, 79 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 753f99528..3f50e8bd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,9 +659,9 @@ checksum = "f9236877021b66ad90f833d8a73a7acb702b985b64c5986682d9f1f1a184f0fb" [[package]] name = "cortex-m" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd20d4ac4aa86f4f75f239d59e542ef67de87cce2c282818dc6e84155d3ea126" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal 0.2.5", "bitfield 0.13.2", @@ -671,23 +671,22 @@ dependencies = [ [[package]] name = "cortex-m-rt" -version = "0.6.15" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "454f278bf469e2de0a4d22ea019d169d8944f86957c8207a39e3f66c32be2fc6" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" dependencies = [ "cortex-m-rt-macros", - "r0", ] [[package]] name = "cortex-m-rt-macros" -version = "0.6.15" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3aa52243e26f5922fa522b0814019e0c98fc567e2756d715dce7ad7a81f49" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn 1.0.94", + "syn 2.0.98", ] [[package]] @@ -2257,7 +2256,6 @@ dependencies = [ "derive_more", "drv-caboose", "drv-lpc55-update-api", - "drv-spi-api", "drv-update-api", "dumper-api", "gateway-messages", @@ -3641,9 +3639,9 @@ dependencies = [ [[package]] name = "lpc55-pac" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1b5b32d313af526145882f5115a55177f479e9328ca667a84aaaa1ae6d65d3" +checksum = "3a4952baed9d9e7e82a6bbc87333f939b90eb41df3e6c0be5e35d0ec61005f91" dependencies = [ "cortex-m", "cortex-m-rt", @@ -4449,12 +4447,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r0" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" - [[package]] name = "radium" version = "0.7.0" @@ -5131,11 +5123,11 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stm32f3" -version = "0.13.2" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081e808e6b2114ced6a83437081ed9816c92017eda7722a7c22f80984fb5476a" +checksum = "b28b37228ef3fa47956af38c6abd756e912f244c1657f14e66d42fc8d74ea96f" dependencies = [ - "bare-metal 0.2.5", + "bare-metal 1.0.0", "cortex-m", "cortex-m-rt", "vcell", @@ -5143,11 +5135,11 @@ dependencies = [ [[package]] name = "stm32f4" -version = "0.13.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3d56009c8f32e4f208dbea17df72484154d1040a8969b75d8c73eb7b18fe8f" +checksum = "fb94729242cd1aebe6dab42a2ca0131985ae93bc3ab2751b680df724bb35528d" dependencies = [ - "bare-metal 0.2.5", + "bare-metal 1.0.0", "cortex-m", "cortex-m-rt", "vcell", @@ -5167,9 +5159,9 @@ dependencies = [ [[package]] name = "stm32h7" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0faa648e03579befdd7267ab5c669624729028001fcf3c973832f53e310a06" +checksum = "362f288cd8341e9209587b889c385f323e82fc237b60c272868965bb879bb9b1" dependencies = [ "bare-metal 1.0.0", "cortex-m", diff --git a/Cargo.toml b/Cargo.toml index 9a739c230..37f790a6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ colored = { version = "2.0", default-features = false } convert_case = { version = "0.4", default-features = false } corncobs = { version = "0.1.1", default-features = false } cortex-m = { version = "0.7", default-features = false, features = ["inline-asm"]} -cortex-m-rt = { version = "0.6.12", default-features = false } +cortex-m-rt = { version = "0.7.5", default-features = false } cortex-m-semihosting = { version = "0.5.0", default-features = false } crc = { version = "3.0.0", default-features = false } critical-section = { version = "1.1.2" } @@ -89,7 +89,7 @@ indexmap = { version = "1.4.0", default-features = false, features = ["serde-1"] indoc = { version = "2.0.3", default-features = false } itertools = { version = "0.10.5", default-features = false } leb128 = { version = "0.2.5", default-features = false } -lpc55-pac = { version = "0.4", default-features = false } +lpc55-pac = { version = "0.5", default-features = false } memchr = { version = "2.4", default-features = false } memoffset = { version = "0.6.5", default-features = false } minicbor = { version = "2.1.1", default-features = false } @@ -127,10 +127,10 @@ ssh-key = { version = "0.6.6", default-features = false, features = ["std", "p25 spin = { version = "0.9.4", default-features = false, features = ["mutex", "spin_mutex"]} ssmarshal = { version = "1.0.0", default-features = false } static_assertions = { version = "1", default-features = false } -stm32f3 = { version = "0.13.0", default-features = false } -stm32f4 = { version = "0.13.0", default-features = false } -stm32h7 = { version = "0.14", default-features = false } -stm32g0 = { version = "0.15.1", default-features = false } +stm32f3 = { version = "0.15", default-features = false } +stm32f4 = { version = "0.15", default-features = false } +stm32h7 = { version = "0.15", default-features = false } +stm32g0 = { version = "0.15", default-features = false } strsim = { version = "0.10.0", default-features = false } syn = { version = "2", default-features = false, features = ["derive", "parsing", "proc-macro", "extra-traits", "full", "printing"] } toml = { version = "0.9.6", default-features = false, features = ["parse", "display", "serde", "preserve_order"] } diff --git a/app/cosmo/base.toml b/app/cosmo/base.toml index ccc8debaf..c4b848861 100644 --- a/app/cosmo/base.toml +++ b/app/cosmo/base.toml @@ -1389,7 +1389,7 @@ input = {port = "B", pin = 14, af = 5} [config.spi.spi2.devices.spartan7_fpga] mux = "port_b" cs = [] -clock_divider = "DIV8" # 12.5 MHz +clock_divider = "Div8" # 12.5 MHz # no CS pin; we're using the SPI peripheral to send synchronized CLK + DATA # SPI_SP_TO_KSZ8463_SCK @@ -1444,7 +1444,7 @@ input = {port = "J", pin = 11, af = 5} [config.spi.spi5.devices.rot] mux = "port_j" cs = [{port = "K", pin = 1}] -clock_divider = "DIV256" +clock_divider = "Div256" ################################################################################ diff --git a/app/demo-stm32h7-nucleo/app-h743.toml b/app/demo-stm32h7-nucleo/app-h743.toml index 88c9a0a4c..302a276d1 100644 --- a/app/demo-stm32h7-nucleo/app-h743.toml +++ b/app/demo-stm32h7-nucleo/app-h743.toml @@ -185,7 +185,7 @@ input = {port = "A", pin = 6, af = 5} # miso [config.spi.spi1.devices.pins] mux = "cn7_arduino" cs = [{port = "D", pin = 14}] -clock_divider = "DIV16" +clock_divider = "Div16" [config.net] diff --git a/app/demo-stm32h7-nucleo/app-h753.toml b/app/demo-stm32h7-nucleo/app-h753.toml index 2bce2264d..096597c62 100644 --- a/app/demo-stm32h7-nucleo/app-h753.toml +++ b/app/demo-stm32h7-nucleo/app-h753.toml @@ -233,7 +233,7 @@ input = {port = "A", pin = 6, af = 5} [config.spi.spi1.devices.pins] mux = "cn7_arduino" cs = [{port = "D", pin = 14}] -clock_divider = "DIV32" +clock_divider = "Div32" [config.net] # UDP ports in sockets below are assigned in oxidecomputer/oana diff --git a/app/gemini-bu/app.toml b/app/gemini-bu/app.toml index 39d86c1ee..1e24dbfe2 100644 --- a/app/gemini-bu/app.toml +++ b/app/gemini-bu/app.toml @@ -321,4 +321,4 @@ input = {port = "E", pin = 5, af = 5} [config.spi.spi4.devices.rot] mux = "port_e" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index b7133df17..cda3165e6 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -1288,7 +1288,7 @@ input = {port = "E", pin = 5, af = 5} [config.spi.spi4.devices.rot] mux = "rot" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" # VLAN configuration [config.net.vlans.sidecar1] diff --git a/app/gimlet/src/main.rs b/app/gimlet/src/main.rs index c8bc0380b..e0fa08224 100644 --- a/app/gimlet/src/main.rs +++ b/app/gimlet/src/main.rs @@ -137,8 +137,8 @@ fn system_init() { // the prescaler. divm: 1, // VCO must tolerate an 8MHz input range: - vcosel: device::rcc::pllcfgr::PLL1VCOSEL_A::WIDEVCO, - pllrange: device::rcc::pllcfgr::PLL1RGE_A::RANGE8, + vcosel: device::rcc::pllcfgr::PLL1VCOSEL_A::WideVco, + pllrange: device::rcc::pllcfgr::PLL1RGE_A::Range8, // DIVN governs the multiplication of the VCO input frequency to produce // the intermediate frequency. We want an IF of 800MHz, or a // multiplication of 100x. @@ -148,23 +148,23 @@ fn system_init() { divn: 100 - 1, // P is the divisor from the VCO IF to the system frequency. We want // 400MHz, so: - divp: device::rcc::pll1divr::DIVP1_A::DIV2, + divp: device::rcc::pll1divr::DIVP1_A::Div2, // Q produces kernel clocks; we set it to 200MHz: divq: 4 - 1, // R is mostly used by the trace unit and we leave it fast: divr: 2 - 1, // We run the CPU at the full core rate of 400MHz: - cpu_div: device::rcc::d1cfgr::D1CPRE_A::DIV1, + cpu_div: device::rcc::d1cfgr::D1CPRE_A::Div1, // We down-shift the AHB by a factor of 2, to 200MHz, to meet its // constraints: - ahb_div: device::rcc::d1cfgr::HPRE_A::DIV2, + ahb_div: device::rcc::d1cfgr::HPRE_A::Div2, // We configure all APB for 100MHz. These are relative to the AHB // frequency. - apb1_div: device::rcc::d2cfgr::D2PPRE1_A::DIV2, - apb2_div: device::rcc::d2cfgr::D2PPRE2_A::DIV2, - apb3_div: device::rcc::d1cfgr::D1PPRE_A::DIV2, - apb4_div: device::rcc::d3cfgr::D3PPRE_A::DIV2, + apb1_div: device::rcc::d2cfgr::D2PPRE1_A::Div2, + apb2_div: device::rcc::d2cfgr::D2PPRE2_A::Div2, + apb3_div: device::rcc::d1cfgr::D1PPRE_A::Div2, + apb4_div: device::rcc::d3cfgr::D3PPRE_A::Div2, // Flash runs at 200MHz: 2WS, 2 programming cycles. See reference manual // Table 13. diff --git a/app/gimletlet/base-gimletlet2.toml b/app/gimletlet/base-gimletlet2.toml index f2d2faf17..6c8cb4057 100644 --- a/app/gimletlet/base-gimletlet2.toml +++ b/app/gimletlet/base-gimletlet2.toml @@ -176,8 +176,8 @@ input = {port = "C", pin = 11, af = 6} [config.spi.spi3.devices.spi3_header] mux = "port_c" cs = [{port = "A", pin = 15}] -clock_divider = "DIV256" # 774 kHz, works with LPC55 clock at 48MHz -# clock_divider = "DIV128" # 1.5 MHz, fails unless LPC55 clock is at 96MHz +clock_divider = "Div256" # 774 kHz, works with LPC55 clock at 48MHz +# clock_divider = "Div128" # 1.5 MHz, fails unless LPC55 clock is at 96MHz [config.spi.spi4] controller = 4 diff --git a/app/grapefruit/base.toml b/app/grapefruit/base.toml index 5157d8466..bd0d01c76 100644 --- a/app/grapefruit/base.toml +++ b/app/grapefruit/base.toml @@ -428,7 +428,7 @@ input = {port = "B", pin = 14, af = 5} # not actually used in FPGA config [config.spi.spi2.devices.spartan7_fpga] mux = "port_b" cs = [] -clock_divider = "DIV8" # 12.5 MHz +clock_divider = "Div8" # 12.5 MHz # no CS pin; we're using the SPI peripheral to send synchronized CLK + DATA [config.spi.spi4] @@ -443,7 +443,7 @@ input = {port = "E", pin = 5, af = 5} [config.spi.spi4.devices.rot] mux = "port_e" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" ################################################################################ diff --git a/app/minibar/app.toml b/app/minibar/app.toml index 2f775b85a..23b5a1075 100644 --- a/app/minibar/app.toml +++ b/app/minibar/app.toml @@ -315,7 +315,7 @@ controller = 4 [config.spi.spi4.devices.rot] mux = "rot" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" [config.spi.spi4.mux_options.rot] outputs = [ diff --git a/app/psc/base.toml b/app/psc/base.toml index cb69afe47..a06752cc4 100644 --- a/app/psc/base.toml +++ b/app/psc/base.toml @@ -526,7 +526,7 @@ input = {port = "E", pin = 5, af = 5} [config.spi.spi4.devices.rot] mux = "rot" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" # VLAN configuration [config.net.vlans.sidecar1] diff --git a/app/sidecar/base.toml b/app/sidecar/base.toml index dde8b05eb..cb5e628e7 100644 --- a/app/sidecar/base.toml +++ b/app/sidecar/base.toml @@ -1114,7 +1114,7 @@ controller = 4 [config.spi.spi4.devices.rot] mux = "rot" cs = [{port = "E", pin = 4}] -clock_divider = "DIV256" +clock_divider = "Div256" [config.spi.spi4.mux_options.rot] outputs = [ diff --git a/build/spi/src/lib.rs b/build/spi/src/lib.rs index 46ce8849f..4a39a6fef 100644 --- a/build/spi/src/lib.rs +++ b/build/spi/src/lib.rs @@ -85,23 +85,24 @@ pub struct DeviceDescriptorConfig { pub cs: Vec, } +// N.B. the names in this enum _must_ match those used in the PAC! #[derive(Copy, Clone, Debug, Deserialize)] pub enum ClockDivider { - DIV2, - DIV4, - DIV8, - DIV16, - DIV32, - DIV64, - DIV128, - DIV256, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, + Div256, } impl Default for ClockDivider { fn default() -> ClockDivider { // When this config mechanism was introduced, we had everything set at - // DIV64 for a ~1.5625 MHz SCK rate. - Self::DIV64 + // Div64 for a ~1.5625 MHz SCK rate. + Self::Div64 } } diff --git a/drv/stm32h7-hash/src/lib.rs b/drv/stm32h7-hash/src/lib.rs index fd0f59b26..083e0272f 100644 --- a/drv/stm32h7-hash/src/lib.rs +++ b/drv/stm32h7-hash/src/lib.rs @@ -318,14 +318,14 @@ impl Hash { // The hash is read out as words into little endian ARM world. // Since the bit order needs to be maintained, read as B.E. let result = [ - u32::from_be(self.reg.hash_hr0.read().bits()), - u32::from_be(self.reg.hash_hr1.read().bits()), - u32::from_be(self.reg.hash_hr2.read().bits()), - u32::from_be(self.reg.hash_hr3.read().bits()), - u32::from_be(self.reg.hash_hr4.read().bits()), - u32::from_be(self.reg.hash_hr5.read().bits()), - u32::from_be(self.reg.hash_hr6.read().bits()), - u32::from_be(self.reg.hash_hr7.read().bits()), + u32::from_be(self.reg.hash_hr[0].read().bits()), + u32::from_be(self.reg.hash_hr[1].read().bits()), + u32::from_be(self.reg.hash_hr[2].read().bits()), + u32::from_be(self.reg.hash_hr[3].read().bits()), + u32::from_be(self.reg.hash_hr[4].read().bits()), + u32::from_be(self.reg.hash_hr[5].read().bits()), + u32::from_be(self.reg.hash_hr[6].read().bits()), + u32::from_be(self.reg.hash_hr[7].read().bits()), ]; out.clone_from_slice(result.as_bytes()); Ok(()) diff --git a/drv/stm32h7-spi-server-core/src/lib.rs b/drv/stm32h7-spi-server-core/src/lib.rs index 9d7448dc9..7d65e0680 100644 --- a/drv/stm32h7-spi-server-core/src/lib.rs +++ b/drv/stm32h7-spi-server-core/src/lib.rs @@ -136,13 +136,13 @@ impl SpiServerCore { // This should correspond to '0' in the standard SPI parlance spi.initialize( - device::spi1::cfg1::MBR_A::DIV64, + device::spi1::cfg1::MBR_A::Div64, 8, - device::spi1::cfg2::COMM_A::FULLDUPLEX, - device::spi1::cfg2::LSBFRST_A::MSBFIRST, - device::spi1::cfg2::CPHA_A::FIRSTEDGE, - device::spi1::cfg2::CPOL_A::IDLELOW, - device::spi1::cfg2::SSOM_A::ASSERTED, + device::spi1::cfg2::COMM_A::FullDuplex, + device::spi1::cfg2::LSBFRST_A::Msbfirst, + device::spi1::cfg2::CPHA_A::FirstEdge, + device::spi1::cfg2::CPOL_A::IdleLow, + device::spi1::cfg2::SSOM_A::Asserted, ); // Configure all devices' CS pins to be deasserted (set). diff --git a/lib/endoscope/src/main.rs b/lib/endoscope/src/main.rs index 4b9b78938..4bd1af9e7 100644 --- a/lib/endoscope/src/main.rs +++ b/lib/endoscope/src/main.rs @@ -24,8 +24,8 @@ const CLOCK_CONFIG: ClockConfig = ClockConfig { // the prescaler. divm: 1, // VCO must tolerate an 8MHz input range: - vcosel: device::rcc::pllcfgr::PLL1VCOSEL_A::WIDEVCO, - pllrange: device::rcc::pllcfgr::PLL1RGE_A::RANGE8, + vcosel: device::rcc::pllcfgr::PLL1VCOSEL_A::WideVco, + pllrange: device::rcc::pllcfgr::PLL1RGE_A::Range8, // DIVN governs the multiplication of the VCO input frequency to produce // the intermediate frequency. We want an IF of 800MHz, or a // multiplication of 100x. @@ -35,23 +35,23 @@ const CLOCK_CONFIG: ClockConfig = ClockConfig { divn: 100 - 1, // P is the divisor from the VCO IF to the system frequency. We want // 400MHz, so: - divp: device::rcc::pll1divr::DIVP1_A::DIV2, + divp: device::rcc::pll1divr::DIVP1_A::Div2, // Q produces kernel clocks; we set it to 200MHz: divq: 4 - 1, // R is mostly used by the trace unit and we leave it fast: divr: 2 - 1, // We run the CPU at the full core rate of 400MHz: - cpu_div: device::rcc::d1cfgr::D1CPRE_A::DIV1, + cpu_div: device::rcc::d1cfgr::D1CPRE_A::Div1, // We down-shift the AHB by a factor of 2, to 200MHz, to meet its // constraints: - ahb_div: device::rcc::d1cfgr::HPRE_A::DIV2, + ahb_div: device::rcc::d1cfgr::HPRE_A::Div2, // We configure all APB for 100MHz. These are relative to the AHB // frequency. - apb1_div: device::rcc::d2cfgr::D2PPRE1_A::DIV2, - apb2_div: device::rcc::d2cfgr::D2PPRE2_A::DIV2, - apb3_div: device::rcc::d1cfgr::D1PPRE_A::DIV2, - apb4_div: device::rcc::d3cfgr::D3PPRE_A::DIV2, + apb1_div: device::rcc::d2cfgr::D2PPRE1_A::Div2, + apb2_div: device::rcc::d2cfgr::D2PPRE2_A::Div2, + apb3_div: device::rcc::d1cfgr::D1PPRE_A::Div2, + apb4_div: device::rcc::d3cfgr::D3PPRE_A::Div2, // Flash runs at 200MHz: 2WS, 2 programming cycles. See reference manual // Table 13.