aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa/src/clocks/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mcxa/src/clocks/mod.rs')
-rw-r--r--embassy-mcxa/src/clocks/mod.rs318
1 files changed, 302 insertions, 16 deletions
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs
index b41a1ba46..98f7075eb 100644
--- a/embassy-mcxa/src/clocks/mod.rs
+++ b/embassy-mcxa/src/clocks/mod.rs
@@ -88,6 +88,7 @@ pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
88 operator.configure_sirc_clocks()?; 88 operator.configure_sirc_clocks()?;
89 operator.configure_fro16k_clocks()?; 89 operator.configure_fro16k_clocks()?;
90 operator.configure_sosc()?; 90 operator.configure_sosc()?;
91 operator.configure_spll()?;
91 92
92 // For now, just use FIRC as the main/cpu clock, which should already be 93 // For now, just use FIRC as the main/cpu clock, which should already be
93 // the case on reset 94 // the case on reset
@@ -825,7 +826,7 @@ impl ClockOperator<'_> {
825 Ok(()) 826 Ok(())
826 } 827 }
827 828
828 /// Configure the FRO16K/clk_16k clock family 829 /// Configure the ROSC/FRO16K/clk_16k clock family
829 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> { 830 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> {
830 let Some(fro16k) = self.config.fro16k.as_ref() else { 831 let Some(fro16k) = self.config.fro16k.as_ref() else {
831 return Ok(()); 832 return Ok(());
@@ -866,21 +867,30 @@ impl ClockOperator<'_> {
866 Ok(()) 867 Ok(())
867 } 868 }
868 869
870 fn ensure_ldo_active(&mut self) {
871 // TODO: Config for the LDO? For now, just enable
872 // using the default settings:
873 // LDOBYPASS: 0/not bypassed
874 // VOUT_SEL: 0b100: 1.1v
875 // LDOEN: 0/Disabled
876 let already_enabled = {
877 let ldocsr = self.scg0.ldocsr().read();
878 ldocsr.ldoen().is_enabled() && ldocsr.vout_ok().is_enabled()
879 };
880 if !already_enabled {
881 self.scg0.ldocsr().modify(|_r, w| w.ldoen().enabled());
882 while self.scg0.ldocsr().read().vout_ok().is_disabled() {}
883 }
884 }
885
869 /// Configure the SOSC/clk_in oscillator 886 /// Configure the SOSC/clk_in oscillator
870 fn configure_sosc(&mut self) -> Result<(), ClockError> { 887 fn configure_sosc(&mut self) -> Result<(), ClockError> {
871 let Some(parts) = self.config.sosc.as_ref() else { 888 let Some(parts) = self.config.sosc.as_ref() else {
872 return Ok(()); 889 return Ok(());
873 }; 890 };
874 891
875 let scg0 = unsafe { pac::Scg0::steal() }; 892 // Enable (and wait for) LDO to be active
876 893 self.ensure_ldo_active();
877 // TODO: Config for the LDO? For now, if we have Sosc, just enable
878 // using the default settings:
879 // LDOBYPASS: 0/not bypassed
880 // VOUT_SEL: 0b100: 1.1v
881 // LDOEN: 0/Disabled
882 scg0.ldocsr().modify(|_r, w| w.ldoen().enabled());
883 while scg0.ldocsr().read().vout_ok().is_disabled() {}
884 894
885 // TODO: something something pins? This seems to work when the pins are 895 // TODO: something something pins? This seems to work when the pins are
886 // not enabled, even if GPIO hasn't been initialized at all yet. 896 // not enabled, even if GPIO hasn't been initialized at all yet.
@@ -920,14 +930,14 @@ impl ClockOperator<'_> {
920 }; 930 };
921 931
922 // Set source/erefs and range 932 // Set source/erefs and range
923 scg0.sosccfg().modify(|_r, w| { 933 self.scg0.sosccfg().modify(|_r, w| {
924 w.erefs().variant(eref); 934 w.erefs().variant(eref);
925 w.range().variant(range); 935 w.range().variant(range);
926 w 936 w
927 }); 937 });
928 938
929 // Disable lock 939 // Disable lock
930 scg0.sosccsr().modify(|_r, w| w.lk().clear_bit()); 940 self.scg0.sosccsr().modify(|_r, w| w.lk().clear_bit());
931 941
932 // TODO: We could enable the SOSC clock monitor. There are some things to 942 // TODO: We could enable the SOSC clock monitor. There are some things to
933 // figure out first: 943 // figure out first:
@@ -938,7 +948,7 @@ impl ClockOperator<'_> {
938 // * We need to decide if we need an interrupt or a reset if the monitor trips 948 // * We need to decide if we need an interrupt or a reset if the monitor trips
939 949
940 // Apply remaining config 950 // Apply remaining config
941 scg0.sosccsr().modify(|_r, w| { 951 self.scg0.sosccsr().modify(|_r, w| {
942 // For now, just disable the monitor. See above. 952 // For now, just disable the monitor. See above.
943 w.sosccm().disabled(); 953 w.sosccm().disabled();
944 954
@@ -957,8 +967,8 @@ impl ClockOperator<'_> {
957 }); 967 });
958 968
959 // Wait for SOSC to be valid, check for errors 969 // Wait for SOSC to be valid, check for errors
960 while !scg0.sosccsr().read().soscvld().bit_is_set() {} 970 while !self.scg0.sosccsr().read().soscvld().bit_is_set() {}
961 if scg0.sosccsr().read().soscerr().is_enabled_and_error() { 971 if self.scg0.sosccsr().read().soscerr().is_enabled_and_error() {
962 return Err(ClockError::BadConfig { 972 return Err(ClockError::BadConfig {
963 clock: "clk_in", 973 clock: "clk_in",
964 reason: "soscerr is set", 974 reason: "soscerr is set",
@@ -966,7 +976,7 @@ impl ClockOperator<'_> {
966 } 976 }
967 977
968 // Re-lock the sosc 978 // Re-lock the sosc
969 scg0.sosccsr().modify(|_r, w| w.lk().set_bit()); 979 self.scg0.sosccsr().modify(|_r, w| w.lk().set_bit());
970 980
971 self.clocks.clk_in = Some(Clock { 981 self.clocks.clk_in = Some(Clock {
972 frequency: freq, 982 frequency: freq,
@@ -975,6 +985,282 @@ impl ClockOperator<'_> {
975 985
976 Ok(()) 986 Ok(())
977 } 987 }
988
989 fn configure_spll(&mut self) -> Result<(), ClockError> {
990 // # Vocab
991 //
992 // | Name | Meaning |
993 // | :--- | :--- |
994 // | Fin | Frequency of clkin |
995 // | clkout | Output clock of the PLL |
996 // | Fout | Frequency of clkout (depends on mode) |
997 // | clkref | PLL Reference clock, the input clock to the PFD |
998 // | Fref | Frequency of clkref, Fref = Fin / N |
999 // | Fcco | Frequency of the output clock of the CCO, Fcco = M * Fref |
1000 // | N | Predivider value |
1001 // | M | Feedback divider value |
1002 // | P | Postdivider value |
1003 // | Tpon | PLL start-up time |
1004
1005 let Some(cfg) = self.config.spll.as_ref() else {
1006 return Ok(());
1007 };
1008
1009 let res = match cfg.source {
1010 config::SpllSource::Sosc => self
1011 .clocks
1012 .clk_in
1013 .as_ref()
1014 .map(|c| (c, pac::scg0::spllctrl::Source::Sosc))
1015 .ok_or("sosc not active"),
1016 config::SpllSource::Firc => self
1017 .clocks
1018 .clk_45m
1019 .as_ref()
1020 .map(|c| (c, pac::scg0::spllctrl::Source::Firc))
1021 .ok_or("firc not active"),
1022 config::SpllSource::Sirc => self
1023 .clocks
1024 .fro_12m
1025 .as_ref()
1026 .map(|c| (c, pac::scg0::spllctrl::Source::Sirc))
1027 .ok_or("sirc not active"),
1028 };
1029 let (clk, variant) = res.map_err(|s| ClockError::BadConfig {
1030 clock: "spll",
1031 reason: s,
1032 })?;
1033 if !clk.power.meets_requirement_of(&cfg.power) {
1034 return Err(ClockError::BadConfig { clock: "spll", reason: "needs low power source" });
1035 }
1036
1037 // Bandwidth calc
1038 //
1039 // > In normal applications, you must calculate the bandwidth manually by using the feedback divider M (ranging from 1 to 216-1),
1040 // > Equation 1, and Equation 2. The PLL is automatically stable in such case. In normal applications, SPLLCTRL[BANDDIRECT] must
1041 // > be 0; in this case, the bandwidth changes as a function of M.
1042 let f_in = clk.frequency;
1043 let bp_pre: bool;
1044 let bp_post: bool;
1045 let bp_post2: bool;
1046 let m: u16;
1047 let p: Option<u8>;
1048 let n: Option<u8>;
1049
1050 // Calculate both Fout and Fcco so we can ensure they don't overflow
1051 // and are in range
1052 let fout: Option<u32>;
1053 let fcco: Option<u32>;
1054
1055 match cfg.mode {
1056 // Fout = M x Fin
1057 config::SpllMode::Mode1a { m_mult } => {
1058 bp_pre = true;
1059 bp_post = true;
1060 bp_post2 = false;
1061 m = m_mult;
1062 p = None;
1063 n = None;
1064 fcco = f_in.checked_mul(m_mult as u32);
1065 fout = fcco;
1066 }
1067 // if !bypass_p2_div: Fout = (M / (2 x P)) x Fin
1068 // if bypass_p2_div: Fout = (M / P ) x Fin
1069 config::SpllMode::Mode1b {
1070 m_mult,
1071 p_div,
1072 bypass_p2_div,
1073 } => {
1074 bp_pre = true;
1075 bp_post = false;
1076 bp_post2 = bypass_p2_div;
1077 m = m_mult;
1078 p = Some(p_div);
1079 n = None;
1080 let mut div = p_div as u32;
1081 if !bypass_p2_div {
1082 div *= 2;
1083 }
1084 fcco = f_in.checked_mul(m_mult as u32);
1085 fout = (f_in / div).checked_mul(m_mult as u32);
1086 }
1087 // Fout = (M / N) x Fin
1088 config::SpllMode::Mode1c { m_mult, n_div } => {
1089 bp_pre = false;
1090 bp_post = true;
1091 bp_post2 = false;
1092 m = m_mult;
1093 p = None;
1094 n = Some(n_div);
1095 fcco = (f_in / (n_div as u32)).checked_mul(m_mult as u32);
1096 fout = fcco;
1097 }
1098 // if !bypass_p2_div: Fout = (M / (N x 2 x P)) x Fin
1099 // if bypass_p2_div: Fout = (M / ( N x P )) x Fin
1100 config::SpllMode::Mode1d {
1101 m_mult,
1102 n_div,
1103 p_div,
1104 bypass_p2_div,
1105 } => {
1106 bp_pre = false;
1107 bp_post = false;
1108 bp_post2 = bypass_p2_div;
1109 m = m_mult;
1110 p = Some(p_div);
1111 n = Some(n_div);
1112 // This can't overflow: u8 x u8 (x 2) always fits in u32
1113 let mut div = (p_div as u32) * (n_div as u32);
1114 if !bypass_p2_div {
1115 div *= 2;
1116 }
1117 fcco = (f_in / (n_div as u32)).checked_mul(m_mult as u32);
1118 fout = (f_in / div).checked_mul(m_mult as u32);
1119 }
1120 };
1121 let fcco = fcco.ok_or(ClockError::BadConfig {
1122 clock: "spll",
1123 reason: "fcco invalid",
1124 })?;
1125 let fout = fout.ok_or(ClockError::BadConfig {
1126 clock: "spll",
1127 reason: "fout invalid",
1128 })?;
1129 // Fcco: 275MHz to 550MHz
1130 if !(275_000_000..=550_000_000).contains(&fcco) {
1131 return Err(ClockError::BadConfig {
1132 clock: "spll",
1133 reason: "fcco invalid",
1134 });
1135 }
1136 // Fout: 4.3MHz to 2x Max CPU Frequency
1137
1138 // TODO: Different for different CPUs?
1139 const CPU_MAX_FREQ: u32 = 180_000_000;
1140 if !(4_300_000..=(2 * CPU_MAX_FREQ)).contains(&fout) {
1141 return Err(ClockError::BadConfig {
1142 clock: "spll",
1143 reason: "fout invalid",
1144 });
1145 }
1146
1147 // TODO:
1148 assert!(clk.frequency != 0);
1149 assert!(m >= 1);
1150 if let Some(p) = p.as_ref() {
1151 assert!(*p >= 1);
1152 }
1153 if let Some(n) = n.as_ref() {
1154 assert!(*n >= 1);
1155 }
1156
1157 // A = floor(m / 4) + 1
1158 let selp_a = (m / 4) + 1;
1159 // SELP = A if A < 31
1160 // = 31 if A >= 31
1161 let selp = selp_a.min(31);
1162
1163 // A = 1 if M >= 8000
1164 // = floor(8000 / M) if 8000 > M >= 122
1165 // = 2 x floor(M / 4) / 3 if 122 > M >= 1
1166 let seli_a = if m >= 8000 {
1167 1
1168 } else if m >= 122 {
1169 8000 / m
1170 } else {
1171 (2 * (m / 4)) / 3
1172 };
1173 // SELI = A if A < 63
1174 // = 63 if A >= 63
1175 let seli = seli_a.min(63);
1176 // SELR must be 0.
1177 let selr = 0;
1178
1179 self.scg0.spllctrl().modify(|_r, w| {
1180 w.source().variant(variant);
1181 unsafe {
1182 w.selp().bits(selp as u8);
1183 w.seli().bits(seli as u8);
1184 w.selr().bits(selr);
1185 }
1186 w
1187 });
1188
1189 if let Some(n) = n {
1190 self.scg0.spllndiv().modify(|_r, w| unsafe { w.ndiv().bits(n) });
1191 }
1192 if let Some(p) = p {
1193 self.scg0.spllpdiv().modify(|_r, w| unsafe { w.pdiv().bits(p) });
1194 }
1195 self.scg0.spllmdiv().modify(|_r, w| unsafe { w.mdiv().bits(m) });
1196
1197 self.scg0.spllctrl().modify(|_r, w| {
1198 w.bypassprediv().bit(bp_pre);
1199 w.bypasspostdiv().bit(bp_post);
1200 w.bypasspostdiv2().bit(bp_post2);
1201
1202 // TODO: support FRM?
1203 w.frm().disabled();
1204
1205 w
1206 });
1207
1208 // Unlock
1209 self.scg0.spllcsr().modify(|_r, w| w.lk().write_enabled());
1210
1211 // TODO: Support clock monitors?
1212 // self.scg0.spllcsr().modify(|_r, w| w.spllcm().?);
1213
1214 self.scg0.trim_lock().write(|w| unsafe {
1215 w.trim_lock_key().bits(0x5a5a);
1216 w.trim_unlock().not_locked()
1217 });
1218
1219 // SPLLLOCK_CNFG: The lock time programmed in this register must be
1220 // equal to meet the PLL 500μs lock time plus the 300 refclk count startup.
1221 //
1222 // LOCK_TIME = 500μs/T ref + 300, F ref = F in /N (input frequency divided by pre-divider ratio).
1223 //
1224 // 500us is 1/2000th of a second, therefore Fref / 2000 is the number of cycles in 500us.
1225 let f_ref = if let Some(n) = n { f_in / (n as u32) } else { f_in };
1226 let lock_time = f_ref.div_ceil(2000) + 300;
1227 self.scg0
1228 .splllock_cnfg()
1229 .write(|w| unsafe { w.lock_time().bits(lock_time) });
1230
1231 // TODO: Support Spread spectrum?
1232
1233 self.scg0.spllcsr().modify(|_r, w| {
1234 w.spllclken().enabled();
1235 w.spllpwren().enabled();
1236 w.spllsten().bit(matches!(cfg.power, PoweredClock::AlwaysEnabled));
1237 w
1238 });
1239
1240 // Wait for SPLL to set up
1241 loop {
1242 let csr = self.scg0.spllcsr().read();
1243 if csr.spll_lock().is_enabled_and_valid() {
1244 if csr.spllerr().is_enabled_and_error() {
1245 return Err(ClockError::BadConfig {
1246 clock: "spll",
1247 reason: "spllerr is set",
1248 });
1249 }
1250 break;
1251 }
1252 }
1253
1254 // Re-lock SPLL CSR
1255 self.scg0.spllcsr().modify(|_r, w| w.lk().write_disabled());
1256
1257 self.clocks.pll1_clk = Some(Clock {
1258 frequency: fout,
1259 power: cfg.power,
1260 });
1261
1262 Ok(())
1263 }
978} 1264}
979 1265
980// 1266//