diff options
Diffstat (limited to 'embassy-mcxa/src/clocks/mod.rs')
| -rw-r--r-- | embassy-mcxa/src/clocks/mod.rs | 83 |
1 files changed, 76 insertions, 7 deletions
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs index 98f7075eb..866e78bf2 100644 --- a/embassy-mcxa/src/clocks/mod.rs +++ b/embassy-mcxa/src/clocks/mod.rs | |||
| @@ -200,6 +200,9 @@ pub struct Clocks { | |||
| 200 | 200 | ||
| 201 | /// `pll1_clk` is the output of the main system PLL, `pll1`. | 201 | /// `pll1_clk` is the output of the main system PLL, `pll1`. |
| 202 | pub pll1_clk: Option<Clock>, | 202 | pub pll1_clk: Option<Clock>, |
| 203 | |||
| 204 | /// `pll1_clk_div` is a configurable frequency clock, sourced from `pll1_clk` | ||
| 205 | pub pll1_clk_div: Option<Clock>, | ||
| 203 | } | 206 | } |
| 204 | 207 | ||
| 205 | /// `ClockError` is the main error returned when configuring or checking clock state | 208 | /// `ClockError` is the main error returned when configuring or checking clock state |
| @@ -548,13 +551,37 @@ impl Clocks { | |||
| 548 | } | 551 | } |
| 549 | 552 | ||
| 550 | /// Ensure the `pll1_clk` clock is active and valid at the given power state. | 553 | /// Ensure the `pll1_clk` clock is active and valid at the given power state. |
| 551 | pub fn ensure_pll1_clk_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | 554 | pub fn ensure_pll1_clk_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { |
| 552 | Err(ClockError::NotImplemented { clock: "pll1_clk" }) | 555 | let Some(clk) = self.pll1_clk.as_ref() else { |
| 556 | return Err(ClockError::BadConfig { | ||
| 557 | clock: "spll", | ||
| 558 | reason: "required but not active", | ||
| 559 | }); | ||
| 560 | }; | ||
| 561 | if !clk.power.meets_requirement_of(at_level) { | ||
| 562 | return Err(ClockError::BadConfig { | ||
| 563 | clock: "spll", | ||
| 564 | reason: "not low power active", | ||
| 565 | }); | ||
| 566 | } | ||
| 567 | Ok(clk.frequency) | ||
| 553 | } | 568 | } |
| 554 | 569 | ||
| 555 | /// Ensure the `pll1_clk_div` clock is active and valid at the given power state. | 570 | /// Ensure the `pll1_clk_div` clock is active and valid at the given power state. |
| 556 | pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { | 571 | pub fn ensure_pll1_clk_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { |
| 557 | Err(ClockError::NotImplemented { clock: "pll1_clk_div" }) | 572 | let Some(clk) = self.pll1_clk_div.as_ref() else { |
| 573 | return Err(ClockError::BadConfig { | ||
| 574 | clock: "spll", | ||
| 575 | reason: "required but not active", | ||
| 576 | }); | ||
| 577 | }; | ||
| 578 | if !clk.power.meets_requirement_of(at_level) { | ||
| 579 | return Err(ClockError::BadConfig { | ||
| 580 | clock: "spll", | ||
| 581 | reason: "not low power active", | ||
| 582 | }); | ||
| 583 | } | ||
| 584 | Ok(clk.frequency) | ||
| 558 | } | 585 | } |
| 559 | 586 | ||
| 560 | /// Ensure the `CPU_CLK` or `SYSTEM_CLK` is active | 587 | /// Ensure the `CPU_CLK` or `SYSTEM_CLK` is active |
| @@ -1031,7 +1058,10 @@ impl ClockOperator<'_> { | |||
| 1031 | reason: s, | 1058 | reason: s, |
| 1032 | })?; | 1059 | })?; |
| 1033 | if !clk.power.meets_requirement_of(&cfg.power) { | 1060 | if !clk.power.meets_requirement_of(&cfg.power) { |
| 1034 | return Err(ClockError::BadConfig { clock: "spll", reason: "needs low power source" }); | 1061 | return Err(ClockError::BadConfig { |
| 1062 | clock: "spll", | ||
| 1063 | reason: "needs low power source", | ||
| 1064 | }); | ||
| 1035 | } | 1065 | } |
| 1036 | 1066 | ||
| 1037 | // Bandwidth calc | 1067 | // Bandwidth calc |
| @@ -1118,9 +1148,20 @@ impl ClockOperator<'_> { | |||
| 1118 | fout = (f_in / div).checked_mul(m_mult as u32); | 1148 | fout = (f_in / div).checked_mul(m_mult as u32); |
| 1119 | } | 1149 | } |
| 1120 | }; | 1150 | }; |
| 1151 | |||
| 1152 | defmt::debug!("f_in: {:?}", f_in); | ||
| 1153 | defmt::debug!("bp_pre: {:?}", bp_pre); | ||
| 1154 | defmt::debug!("bp_post: {:?}", bp_post); | ||
| 1155 | defmt::debug!("bp_post2: {:?}", bp_post2); | ||
| 1156 | defmt::debug!("m: {:?}", m); | ||
| 1157 | defmt::debug!("p: {:?}", p); | ||
| 1158 | defmt::debug!("n: {:?}", n); | ||
| 1159 | defmt::debug!("fout: {:?}", fout); | ||
| 1160 | defmt::debug!("fcco: {:?}", fcco); | ||
| 1161 | |||
| 1121 | let fcco = fcco.ok_or(ClockError::BadConfig { | 1162 | let fcco = fcco.ok_or(ClockError::BadConfig { |
| 1122 | clock: "spll", | 1163 | clock: "spll", |
| 1123 | reason: "fcco invalid", | 1164 | reason: "fcco invalid1", |
| 1124 | })?; | 1165 | })?; |
| 1125 | let fout = fout.ok_or(ClockError::BadConfig { | 1166 | let fout = fout.ok_or(ClockError::BadConfig { |
| 1126 | clock: "spll", | 1167 | clock: "spll", |
| @@ -1130,7 +1171,7 @@ impl ClockOperator<'_> { | |||
| 1130 | if !(275_000_000..=550_000_000).contains(&fcco) { | 1171 | if !(275_000_000..=550_000_000).contains(&fcco) { |
| 1131 | return Err(ClockError::BadConfig { | 1172 | return Err(ClockError::BadConfig { |
| 1132 | clock: "spll", | 1173 | clock: "spll", |
| 1133 | reason: "fcco invalid", | 1174 | reason: "fcco invalid2", |
| 1134 | }); | 1175 | }); |
| 1135 | } | 1176 | } |
| 1136 | // Fout: 4.3MHz to 2x Max CPU Frequency | 1177 | // Fout: 4.3MHz to 2x Max CPU Frequency |
| @@ -1149,6 +1190,7 @@ impl ClockOperator<'_> { | |||
| 1149 | assert!(m >= 1); | 1190 | assert!(m >= 1); |
| 1150 | if let Some(p) = p.as_ref() { | 1191 | if let Some(p) = p.as_ref() { |
| 1151 | assert!(*p >= 1); | 1192 | assert!(*p >= 1); |
| 1193 | assert!(*p <= 31); | ||
| 1152 | } | 1194 | } |
| 1153 | if let Some(n) = n.as_ref() { | 1195 | if let Some(n) = n.as_ref() { |
| 1154 | assert!(*n >= 1); | 1196 | assert!(*n >= 1); |
| @@ -1254,11 +1296,38 @@ impl ClockOperator<'_> { | |||
| 1254 | // Re-lock SPLL CSR | 1296 | // Re-lock SPLL CSR |
| 1255 | self.scg0.spllcsr().modify(|_r, w| w.lk().write_disabled()); | 1297 | self.scg0.spllcsr().modify(|_r, w| w.lk().write_disabled()); |
| 1256 | 1298 | ||
| 1299 | // Store clock state | ||
| 1257 | self.clocks.pll1_clk = Some(Clock { | 1300 | self.clocks.pll1_clk = Some(Clock { |
| 1258 | frequency: fout, | 1301 | frequency: fout, |
| 1259 | power: cfg.power, | 1302 | power: cfg.power, |
| 1260 | }); | 1303 | }); |
| 1261 | 1304 | ||
| 1305 | // Do we enable the `pll1_clk_div` output? | ||
| 1306 | if let Some(d) = cfg.pll1_clk_div.as_ref() { | ||
| 1307 | // Halt and reset the div; then set our desired div. | ||
| 1308 | self.syscon.pll1clkdiv().write(|w| { | ||
| 1309 | w.halt().halt(); | ||
| 1310 | w.reset().asserted(); | ||
| 1311 | unsafe { w.div().bits(d.into_bits()) }; | ||
| 1312 | w | ||
| 1313 | }); | ||
| 1314 | // Then unhalt it, and reset it | ||
| 1315 | self.syscon.pll1clkdiv().write(|w| { | ||
| 1316 | w.halt().run(); | ||
| 1317 | w.reset().released(); | ||
| 1318 | w | ||
| 1319 | }); | ||
| 1320 | |||
| 1321 | // Wait for clock to stabilize | ||
| 1322 | while self.syscon.pll1clkdiv().read().unstab().is_ongoing() {} | ||
| 1323 | |||
| 1324 | // Store off the clock info | ||
| 1325 | self.clocks.pll1_clk_div = Some(Clock { | ||
| 1326 | frequency: fout / d.into_divisor(), | ||
| 1327 | power: cfg.power, | ||
| 1328 | }); | ||
| 1329 | } | ||
| 1330 | |||
| 1262 | Ok(()) | 1331 | Ok(()) |
| 1263 | } | 1332 | } |
| 1264 | } | 1333 | } |
