diff options
Diffstat (limited to 'embassy-mcxa/src/clocks/config.rs')
| -rw-r--r-- | embassy-mcxa/src/clocks/config.rs | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/embassy-mcxa/src/clocks/config.rs b/embassy-mcxa/src/clocks/config.rs new file mode 100644 index 000000000..0563b8917 --- /dev/null +++ b/embassy-mcxa/src/clocks/config.rs | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | //! Clock Configuration | ||
| 2 | //! | ||
| 3 | //! This module holds configuration types used for the system clocks. For | ||
| 4 | //! configuration of individual peripherals, see [`super::periph_helpers`]. | ||
| 5 | |||
| 6 | use super::PoweredClock; | ||
| 7 | |||
| 8 | /// This type represents a divider in the range 1..=256. | ||
| 9 | /// | ||
| 10 | /// At a hardware level, this is an 8-bit register from 0..=255, | ||
| 11 | /// which adds one. | ||
| 12 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
| 13 | pub struct Div8(pub(super) u8); | ||
| 14 | |||
| 15 | impl Div8 { | ||
| 16 | /// Store a "raw" divisor value that will divide the source by | ||
| 17 | /// `(n + 1)`, e.g. `Div8::from_raw(0)` will divide the source | ||
| 18 | /// by 1, and `Div8::from_raw(255)` will divide the source by | ||
| 19 | /// 256. | ||
| 20 | pub const fn from_raw(n: u8) -> Self { | ||
| 21 | Self(n) | ||
| 22 | } | ||
| 23 | |||
| 24 | /// Divide by one, or no division | ||
| 25 | pub const fn no_div() -> Self { | ||
| 26 | Self(0) | ||
| 27 | } | ||
| 28 | |||
| 29 | /// Store a specific divisor value that will divide the source | ||
| 30 | /// by `n`. e.g. `Div8::from_divisor(1)` will divide the source | ||
| 31 | /// by 1, and `Div8::from_divisor(256)` will divide the source | ||
| 32 | /// by 256. | ||
| 33 | /// | ||
| 34 | /// Will return `None` if `n` is not in the range `1..=256`. | ||
| 35 | /// Consider [`Self::from_raw`] for an infallible version. | ||
| 36 | pub const fn from_divisor(n: u16) -> Option<Self> { | ||
| 37 | let Some(n) = n.checked_sub(1) else { | ||
| 38 | return None; | ||
| 39 | }; | ||
| 40 | if n > (u8::MAX as u16) { | ||
| 41 | return None; | ||
| 42 | } | ||
| 43 | Some(Self(n as u8)) | ||
| 44 | } | ||
| 45 | |||
| 46 | /// Convert into "raw" bits form | ||
| 47 | #[inline(always)] | ||
| 48 | pub const fn into_bits(self) -> u8 { | ||
| 49 | self.0 | ||
| 50 | } | ||
| 51 | |||
| 52 | /// Convert into "divisor" form, as a u32 for convenient frequency math | ||
| 53 | #[inline(always)] | ||
| 54 | pub const fn into_divisor(self) -> u32 { | ||
| 55 | self.0 as u32 + 1 | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | /// ```text | ||
| 60 | /// ┌─────────────────────────────────────────────────────────┐ | ||
| 61 | /// │ │ | ||
| 62 | /// │ ┌───────────┐ clk_out ┌─────────┐ │ | ||
| 63 | /// XTAL ──────┼──▷│ System │───────────▷│ │ clk_in │ | ||
| 64 | /// │ │ OSC │ clkout_byp │ MUX │──────────────────┼──────▷ | ||
| 65 | /// EXTAL ──────┼──▷│ │───────────▷│ │ │ | ||
| 66 | /// │ └───────────┘ └─────────┘ │ | ||
| 67 | /// │ │ | ||
| 68 | /// │ ┌───────────┐ fro_hf_root ┌────┐ fro_hf │ | ||
| 69 | /// │ │ FRO180 ├───────┬─────▷│ CG │─────────────────────┼──────▷ | ||
| 70 | /// │ │ │ │ ├────┤ clk_45m │ | ||
| 71 | /// │ │ │ └─────▷│ CG │─────────────────────┼──────▷ | ||
| 72 | /// │ └───────────┘ └────┘ │ | ||
| 73 | /// │ ┌───────────┐ fro_12m_root ┌────┐ fro_12m │ | ||
| 74 | /// │ │ FRO12M │────────┬─────▷│ CG │────────────────────┼──────▷ | ||
| 75 | /// │ │ │ │ ├────┤ clk_1m │ | ||
| 76 | /// │ │ │ └─────▷│1/12│────────────────────┼──────▷ | ||
| 77 | /// │ └───────────┘ └────┘ │ | ||
| 78 | /// │ │ | ||
| 79 | /// │ ┌──────────┐ │ | ||
| 80 | /// │ │000 │ │ | ||
| 81 | /// │ clk_in │ │ │ | ||
| 82 | /// │ ───────────────▷│001 │ │ | ||
| 83 | /// │ fro_12m │ │ │ | ||
| 84 | /// │ ───────────────▷│010 │ │ | ||
| 85 | /// │ fro_hf_root │ │ │ | ||
| 86 | /// │ ───────────────▷│011 │ main_clk │ | ||
| 87 | /// │ │ │───────────────────────────┼──────▷ | ||
| 88 | /// clk_16k ──────┼─────────────────▷│100 │ │ | ||
| 89 | /// │ none │ │ │ | ||
| 90 | /// │ ───────────────▷│101 │ │ | ||
| 91 | /// │ pll1_clk │ │ │ | ||
| 92 | /// │ ───────────────▷│110 │ │ | ||
| 93 | /// │ none │ │ │ | ||
| 94 | /// │ ───────────────▷│111 │ │ | ||
| 95 | /// │ └──────────┘ │ | ||
| 96 | /// │ ▲ │ | ||
| 97 | /// │ │ │ | ||
| 98 | /// │ SCG SCS │ | ||
| 99 | /// │ SCG-Lite │ | ||
| 100 | /// └─────────────────────────────────────────────────────────┘ | ||
| 101 | /// | ||
| 102 | /// | ||
| 103 | /// clk_in ┌─────┐ | ||
| 104 | /// ───────────────▷│00 │ | ||
| 105 | /// clk_45m │ │ | ||
| 106 | /// ───────────────▷│01 │ ┌───────────┐ pll1_clk | ||
| 107 | /// none │ │─────▷│ SPLL │───────────────▷ | ||
| 108 | /// ───────────────▷│10 │ └───────────┘ | ||
| 109 | /// fro_12m │ │ | ||
| 110 | /// ───────────────▷│11 │ | ||
| 111 | /// └─────┘ | ||
| 112 | /// ``` | ||
| 113 | #[non_exhaustive] | ||
| 114 | pub struct ClocksConfig { | ||
| 115 | /// FIRC, FRO180, 45/60/90/180M clock source | ||
| 116 | pub firc: Option<FircConfig>, | ||
| 117 | /// SIRC, FRO12M, clk_12m clock source | ||
| 118 | // NOTE: I don't think we *can* disable the SIRC? | ||
| 119 | pub sirc: SircConfig, | ||
| 120 | /// FRO16K clock source | ||
| 121 | pub fro16k: Option<Fro16KConfig>, | ||
| 122 | } | ||
| 123 | |||
| 124 | // FIRC/FRO180M | ||
| 125 | |||
| 126 | /// ```text | ||
| 127 | /// ┌───────────┐ fro_hf_root ┌────┐ fro_hf | ||
| 128 | /// │ FRO180M ├───────┬─────▷│GATE│──────────▷ | ||
| 129 | /// │ │ │ ├────┤ clk_45m | ||
| 130 | /// │ │ └─────▷│GATE│──────────▷ | ||
| 131 | /// └───────────┘ └────┘ | ||
| 132 | /// ``` | ||
| 133 | #[non_exhaustive] | ||
| 134 | pub struct FircConfig { | ||
| 135 | /// Selected clock frequency | ||
| 136 | pub frequency: FircFreqSel, | ||
| 137 | /// Selected power state of the clock | ||
| 138 | pub power: PoweredClock, | ||
| 139 | /// Is the "fro_hf" gated clock enabled? | ||
| 140 | pub fro_hf_enabled: bool, | ||
| 141 | /// Is the "clk_45m" gated clock enabled? | ||
| 142 | pub clk_45m_enabled: bool, | ||
| 143 | /// Is the "fro_hf_div" clock enabled? Requires `fro_hf`! | ||
| 144 | pub fro_hf_div: Option<Div8>, | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Selected FIRC frequency | ||
| 148 | pub enum FircFreqSel { | ||
| 149 | /// 45MHz Output | ||
| 150 | Mhz45, | ||
| 151 | /// 60MHz Output | ||
| 152 | Mhz60, | ||
| 153 | /// 90MHz Output | ||
| 154 | Mhz90, | ||
| 155 | /// 180MHz Output | ||
| 156 | Mhz180, | ||
| 157 | } | ||
| 158 | |||
| 159 | // SIRC/FRO12M | ||
| 160 | |||
| 161 | /// ```text | ||
| 162 | /// ┌───────────┐ fro_12m_root ┌────┐ fro_12m | ||
| 163 | /// │ FRO12M │────────┬─────▷│ CG │──────────▷ | ||
| 164 | /// │ │ │ ├────┤ clk_1m | ||
| 165 | /// │ │ └─────▷│1/12│──────────▷ | ||
| 166 | /// └───────────┘ └────┘ | ||
| 167 | /// ``` | ||
| 168 | #[non_exhaustive] | ||
| 169 | pub struct SircConfig { | ||
| 170 | pub power: PoweredClock, | ||
| 171 | // peripheral output, aka sirc_12mhz | ||
| 172 | pub fro_12m_enabled: bool, | ||
| 173 | /// Is the "fro_lf_div" clock enabled? Requires `fro_12m`! | ||
| 174 | pub fro_lf_div: Option<Div8>, | ||
| 175 | } | ||
| 176 | |||
| 177 | #[non_exhaustive] | ||
| 178 | pub struct Fro16KConfig { | ||
| 179 | pub vsys_domain_active: bool, | ||
| 180 | pub vdd_core_domain_active: bool, | ||
| 181 | } | ||
| 182 | |||
| 183 | impl Default for ClocksConfig { | ||
| 184 | fn default() -> Self { | ||
| 185 | Self { | ||
| 186 | firc: Some(FircConfig { | ||
| 187 | frequency: FircFreqSel::Mhz45, | ||
| 188 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 189 | fro_hf_enabled: true, | ||
| 190 | clk_45m_enabled: true, | ||
| 191 | fro_hf_div: None, | ||
| 192 | }), | ||
| 193 | sirc: SircConfig { | ||
| 194 | power: PoweredClock::AlwaysEnabled, | ||
| 195 | fro_12m_enabled: true, | ||
| 196 | fro_lf_div: None, | ||
| 197 | }, | ||
| 198 | fro16k: Some(Fro16KConfig { | ||
| 199 | vsys_domain_active: true, | ||
| 200 | vdd_core_domain_active: true, | ||
| 201 | }), | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
