From ed0226cd00448c93a026a0768752b802655ed6ba Mon Sep 17 00:00:00 2001 From: Zhouqi Jiang Date: Wed, 6 Nov 2024 16:41:14 +0800 Subject: [PATCH] ccu: rearrange clock type traits, split into ClockReset, ClockGate and ClockConfig, add MBUS clock type Signed-off-by: Zhouqi Jiang --- allwinner-hal/src/ccu.rs | 393 ++++++++++++++++++++++++-------------- allwinner-hal/src/uart.rs | 8 +- 2 files changed, 250 insertions(+), 151 deletions(-) diff --git a/allwinner-hal/src/ccu.rs b/allwinner-hal/src/ccu.rs index 43db661..96a0204 100644 --- a/allwinner-hal/src/ccu.rs +++ b/allwinner-hal/src/ccu.rs @@ -787,153 +787,6 @@ impl SpiBusGating { } } -/// Peripheral that can be clock gated by CCU. -pub trait ClockGate { - /// Assert reset signal. - unsafe fn assert_reset(ccu: &ccu::RegisterBlock); - /// Deassert reset signal. - unsafe fn deassert_reset(ccu: &ccu::RegisterBlock); - /// Free this peripheral by provided `ccu`. - #[inline] - unsafe fn free(ccu: &ccu::RegisterBlock) { - // by default, asserting reset signal. - Self::assert_reset(ccu); - } - /// Reset this peripheral without reconfiguring clocks (if applicable). - #[inline] - unsafe fn reset(ccu: &ccu::RegisterBlock) { - Self::assert_reset(ccu); - Self::deassert_reset(ccu); - } -} - -/// Peripheral whose clock can be configurated by CCU. -pub trait ClockConfig { - /// Type of clock source. - type Source; - /// Configure peripheral clock. - /// - /// Value `factor_m` should be in 0 ..= 15. - unsafe fn configure( - ccu: &ccu::RegisterBlock, - source: Self::Source, - factor_m: u8, - factor_n: FactorN, - ); - /// Reconfigure peripheral clock by applying clock parameters while asserting reset. - #[inline] - unsafe fn reconfigure( - ccu: &ccu::RegisterBlock, - source: Self::Source, - factor_m: u8, - factor_n: FactorN, - ) where - Self: ClockGate, - { - Self::assert_reset(ccu); - Self::configure(ccu, source, factor_m, factor_n); - Self::deassert_reset(ccu); - } -} - -// TODO: a more proper abstraction considering the PLL source behind peripheral clock - -/// Dynamic Random-Access Memory (DRAM) clock gate. -pub struct DRAM; - -impl ClockGate for DRAM { - #[inline] - unsafe fn assert_reset(ccu: &ccu::RegisterBlock) { - ccu.dram_bgr - .write(ccu.dram_bgr.read().gate_mask().assert_reset()); - } - #[inline] - unsafe fn deassert_reset(ccu: &ccu::RegisterBlock) { - ccu.dram_bgr - .write(ccu.dram_bgr.read().gate_pass().deassert_reset()); - } -} - -impl ClockConfig for DRAM { - type Source = DramClockSource; - - #[inline] - unsafe fn configure( - ccu: &ccu::RegisterBlock, - source: Self::Source, - factor_m: u8, - factor_n: FactorN, - ) { - let dram_clk = ccu.dram_clock.read(); - ccu.dram_clock.write( - dram_clk - .set_clock_source(source) - .set_factor_m(factor_m) - .set_factor_n(factor_n), - ) - } -} - -/// Universal Asynchronous Receiver-Transmitter clock gate. -/// -/// UART peripheral should be indexed by type parameter `IDX`. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct UART; - -impl ClockGate for UART { - #[inline] - unsafe fn assert_reset(ccu: &ccu::RegisterBlock) { - let uart_bgr = ccu.uart_bgr.read(); - ccu.uart_bgr - .write(uart_bgr.gate_mask::().assert_reset::()); - } - - #[inline] - unsafe fn deassert_reset(ccu: &ccu::RegisterBlock) { - let uart_bgr = ccu.uart_bgr.read(); - ccu.uart_bgr - .write(uart_bgr.gate_pass::().deassert_reset::()); - } -} - -/// Serial Peripheral Interface clock gate. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct SPI; - -impl ClockGate for SPI { - #[inline] - unsafe fn assert_reset(ccu: &ccu::RegisterBlock) { - let spi_bgr = ccu.spi_bgr.read(); - ccu.spi_bgr - .write(spi_bgr.gate_mask::().assert_reset::()); - } - #[inline] - unsafe fn deassert_reset(ccu: &ccu::RegisterBlock) { - let spi_bgr = ccu.spi_bgr.read(); - ccu.spi_bgr - .write(spi_bgr.gate_pass::().deassert_reset::()); - } -} - -impl ClockConfig for SPI { - type Source = SpiClockSource; - - unsafe fn configure( - ccu: &ccu::RegisterBlock, - source: Self::Source, - factor_m: u8, - factor_n: FactorN, - ) { - let spi_clk = ccu.spi_clk[I].read(); - ccu.spi_clk[I].write( - spi_clk - .set_clock_source(source) - .set_factor_m(factor_m) - .set_factor_n(factor_n), - ) - } -} - /// SMHC Clock register. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1061,6 +914,252 @@ impl SmhcBusGating { } } +/// Peripheral that have clock reset feature in CCU. +pub trait ClockReset { + /// Assert reset signal. + unsafe fn assert_reset_only(ccu: &ccu::RegisterBlock); + /// Deassert reset signal. + unsafe fn deassert_reset_only(ccu: &ccu::RegisterBlock); +} + +/// Peripheral that can be clock gated by CCU. +pub trait ClockGate: ClockReset { + /// Unmask clock gate. + unsafe fn unmask_gate_only(ccu: &ccu::RegisterBlock); + /// Mask clock gate. + unsafe fn mask_gate_only(ccu: &ccu::RegisterBlock); + /// Assert reset signal and mask the clock gate. + unsafe fn disable_in(ccu: &ccu::RegisterBlock); + /// Deassert reset signal and unmask the clock gate. + unsafe fn enable_in(ccu: &ccu::RegisterBlock); + /// Reset this peripheral without reconfiguring clocks (if applicable). + #[inline] + unsafe fn reset(ccu: &ccu::RegisterBlock) { + // assert reset and then deassert reset. + Self::disable_in(ccu); + Self::enable_in(ccu); + } + /// Free this peripheral by provided `ccu`. + #[inline] + unsafe fn free(ccu: &ccu::RegisterBlock) { + // by default, asserting reset signal and mask clock gate. + Self::disable_in(ccu); + } +} + +/// Peripheral whose clock can be configurated by CCU. +pub trait ClockConfig { + /// Type of clock source. + type Source; + /// Configure peripheral clock. + /// + /// Value `factor_m` should be in 0 ..= 15. + unsafe fn configure( + ccu: &ccu::RegisterBlock, + source: Self::Source, + factor_m: u8, + factor_n: FactorN, + ); + /// Reconfigure peripheral clock by applying clock parameters while asserting reset. + #[inline] + unsafe fn reconfigure( + ccu: &ccu::RegisterBlock, + source: Self::Source, + factor_m: u8, + factor_n: FactorN, + ) where + Self: ClockGate, + { + Self::disable_in(ccu); + Self::configure(ccu, source, factor_m, factor_n); + Self::enable_in(ccu); + } + /// Reconfigure this clock with dependency to a resettable clock type `T`. + #[inline] + unsafe fn reconfigure_with( + ccu: &ccu::RegisterBlock, + dependency: T, + before_configure: F, + after_configure: G, + ) where + Self: ClockGate, + F: FnOnce(&ccu::RegisterBlock) -> (Self::Source, u8, FactorN), + G: FnOnce(&ccu::RegisterBlock), + { + let _ = dependency; // does not use value, the type T is used instead + T::assert_reset_only(ccu); + Self::disable_in(ccu); + let (source, factor_m, factor_n) = before_configure(ccu); + Self::configure(ccu, source, factor_m, factor_n); + after_configure(ccu); + Self::deassert_reset_only(ccu); + T::deassert_reset_only(ccu); + Self::unmask_gate_only(ccu); + } +} + +// TODO: a more proper abstraction considering the PLL source behind peripheral clock + +/// Dynamic Random-Access Memory (DRAM) clock type. +pub struct DRAM; + +impl ClockReset for DRAM { + #[inline] + unsafe fn deassert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.deassert_reset()); + } + #[inline] + unsafe fn assert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.assert_reset()); + } +} + +impl ClockGate for DRAM { + #[inline] + unsafe fn unmask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.gate_pass()); + } + #[inline] + unsafe fn mask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.gate_mask()); + } + #[inline] + unsafe fn disable_in(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.gate_mask().assert_reset()); + } + #[inline] + unsafe fn enable_in(ccu: &ccu::RegisterBlock) { + ccu.dram_bgr.modify(|v| v.gate_pass().deassert_reset()); + } +} + +impl ClockConfig for DRAM { + type Source = DramClockSource; + + #[inline] + unsafe fn configure( + ccu: &ccu::RegisterBlock, + source: Self::Source, + factor_m: u8, + factor_n: FactorN, + ) { + let dram_clk = ccu.dram_clock.read(); + ccu.dram_clock.write( + dram_clk + .set_clock_source(source) + .set_factor_m(factor_m) + .set_factor_n(factor_n), + ) + } +} + +/// MCTL Bus (MBUS) clock type. +pub struct MBUS; + +impl ClockReset for MBUS { + #[inline] + unsafe fn assert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.mbus_clock.modify(|v| v.assert_reset()); + } + #[inline] + unsafe fn deassert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.mbus_clock.modify(|v| v.deassert_reset()); + } +} + +/// Universal Asynchronous Receiver-Transmitter clock type. +/// +/// UART peripheral should be indexed by type parameter `IDX`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct UART; + +impl ClockReset for UART { + #[inline] + unsafe fn assert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr.modify(|v| v.assert_reset::()); + } + #[inline] + unsafe fn deassert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr.modify(|v| v.deassert_reset::()); + } +} + +impl ClockGate for UART { + #[inline] + unsafe fn unmask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr.modify(|v| v.gate_pass::()); + } + #[inline] + unsafe fn mask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr.modify(|v| v.gate_mask::()); + } + #[inline] + unsafe fn disable_in(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr + .modify(|v| v.gate_mask::().assert_reset::()); + } + #[inline] + unsafe fn enable_in(ccu: &ccu::RegisterBlock) { + ccu.uart_bgr + .modify(|v| v.gate_pass::().deassert_reset::()); + } +} + +/// Serial Peripheral Interface clock type. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct SPI; + +impl ClockReset for SPI { + #[inline] + unsafe fn assert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr.modify(|v| v.assert_reset::()); + } + #[inline] + unsafe fn deassert_reset_only(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr.modify(|v| v.deassert_reset::()); + } +} + +impl ClockGate for SPI { + #[inline] + unsafe fn unmask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr.modify(|v| v.gate_pass::()); + } + #[inline] + unsafe fn mask_gate_only(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr.modify(|v| v.gate_mask::()); + } + #[inline] + unsafe fn disable_in(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr + .modify(|v| v.gate_mask::().assert_reset::()); + } + #[inline] + unsafe fn enable_in(ccu: &ccu::RegisterBlock) { + ccu.spi_bgr + .modify(|v| v.gate_pass::().deassert_reset::()); + } +} + +impl ClockConfig for SPI { + type Source = SpiClockSource; + + unsafe fn configure( + ccu: &ccu::RegisterBlock, + source: Self::Source, + factor_m: u8, + factor_n: FactorN, + ) { + let spi_clk = ccu.spi_clk[I].read(); + ccu.spi_clk[I].write( + spi_clk + .set_clock_source(source) + .set_factor_m(factor_m) + .set_factor_n(factor_n), + ) + } +} + #[cfg(test)] mod tests { use super::{ diff --git a/allwinner-hal/src/uart.rs b/allwinner-hal/src/uart.rs index 1c3561c..5e80eca 100644 --- a/allwinner-hal/src/uart.rs +++ b/allwinner-hal/src/uart.rs @@ -108,7 +108,7 @@ impl, const I: usize, PADS: Pads> Serial, const I: usize, PADS: Pads> Serial (UART, PADS) { // clock is closed for self.clock_gate is dropped - unsafe { PADS::ClockGate::free(ccu) }; + unsafe { PADS::Clock::free(ccu) }; (self.uart, self.pads) } } @@ -196,7 +196,7 @@ pub struct ReceiveHalf> { /// Valid serial pads. pub trait Pads { - type ClockGate: ccu::ClockGate; + type Clock: ccu::ClockGate + ccu::ClockReset; } /// Valid transmit pin for UART peripheral. @@ -248,7 +248,7 @@ where T: Transmit, R: Receive, { - type ClockGate = ccu::UART; + type Clock = ccu::UART; } impl, const I: usize, PADS: Pads> embedded_io::ErrorType