1use core::cell::Cell;
8use kernel::utilities::registers::interfaces::ReadWriteable;
9use kernel::utilities::registers::interfaces::Readable;
10use kernel::utilities::registers::{register_bitfields, ReadWrite};
11use kernel::utilities::StaticRef;
12use rv32i::csr;
13
14#[repr(C)]
15pub struct PrciRegisters {
16 hfrosccfg: ReadWrite<u32, hfrosccfg::Register>,
18 hfxosccfg: ReadWrite<u32, hfxosccfg::Register>,
20 pllcfg: ReadWrite<u32, pllcfg::Register>,
22 plloutdiv: ReadWrite<u32, plloutdiv::Register>,
24 coreclkcfg: ReadWrite<u32>,
26}
27
28register_bitfields![u32,
29 hfrosccfg [
30 ready OFFSET(31) NUMBITS(1) [],
31 enable OFFSET(30) NUMBITS(1) [],
32 trim OFFSET(16) NUMBITS(5) [],
33 div OFFSET(0) NUMBITS(6) []
34 ],
35 hfxosccfg [
36 ready OFFSET(31) NUMBITS(1) [],
37 enable OFFSET(30) NUMBITS(1) []
38 ],
39 pllcfg [
40 lock OFFSET(31) NUMBITS(1) [],
41 bypass OFFSET(18) NUMBITS(1) [],
42 refsel OFFSET(17) NUMBITS(1) [],
43 sel OFFSET(16) NUMBITS(1) [],
44 pllq OFFSET(10) NUMBITS(2) [],
45 pllf OFFSET(4) NUMBITS(6) [],
46 pllr OFFSET(0) NUMBITS(3) [
47 R1 = 0
48 ]
49 ],
50 plloutdiv [
51 divby1 OFFSET(8) NUMBITS(1) [],
52 div OFFSET(0) NUMBITS(6) []
53 ]
54];
55
56pub enum ClockFrequency {
57 Freq16Mhz,
58 Freq344Mhz,
59}
60
61pub struct Prci {
62 registers: StaticRef<PrciRegisters>,
63 current_frequency: Cell<ClockFrequency>,
64}
65
66impl Prci {
67 pub const fn new(base: StaticRef<PrciRegisters>) -> Prci {
68 Prci {
69 registers: base,
70 current_frequency: Cell::new(ClockFrequency::Freq16Mhz),
71 }
72 }
73
74 pub fn switch_to_internal_clock(&self) {
75 let regs = self.registers;
76 if regs.hfrosccfg.read(hfrosccfg::enable) == 0 {
78 regs.hfrosccfg.modify(hfrosccfg::enable::SET);
79 }
80 while regs.hfrosccfg.read(hfrosccfg::ready) == 0 {}
82 regs.pllcfg
84 .modify(pllcfg::sel::CLEAR + pllcfg::bypass::CLEAR);
85 }
86
87 pub fn set_internal_clock_default(&self) {
88 let regs = self.registers;
89 regs.hfrosccfg
91 .modify(hfrosccfg::div.val(4) + hfrosccfg::trim.val(0x10));
92 }
93
94 pub fn enable_external_clock(&self) {
95 let regs = self.registers;
96 if regs.hfxosccfg.read(hfxosccfg::enable) == 0 {
98 regs.hfxosccfg.modify(hfxosccfg::enable::SET);
99 }
100 while regs.hfxosccfg.read(hfxosccfg::ready) == 0 {}
102 }
103
104 pub fn set_clock_frequency(&self, frequency: ClockFrequency) {
105 let regs = self.registers;
106 self.set_internal_clock_default();
117 self.switch_to_internal_clock();
118
119 self.enable_external_clock();
121
122 match frequency {
123 ClockFrequency::Freq16Mhz => {
124 regs.pllcfg
127 .modify(pllcfg::bypass::SET + pllcfg::refsel::SET);
128 regs.plloutdiv
130 .modify(plloutdiv::divby1.val(1) + plloutdiv::div.val(0));
131 regs.pllcfg.modify(pllcfg::sel::SET);
133 }
134 ClockFrequency::Freq344Mhz => {
135 regs.pllcfg.modify(
139 pllcfg::bypass::CLEAR
140 + pllcfg::refsel::SET
141 + pllcfg::pllr.val(1)
142 + pllcfg::pllf.val(42)
143 + pllcfg::pllq.val(1),
144 );
145 regs.plloutdiv
147 .modify(plloutdiv::divby1.val(1) + plloutdiv::div.val(0));
148
149 let start = csr::CSR.mcycle.get();
153 while csr::CSR.mcycle.get() - start < 2200 {}
154 while regs.pllcfg.read(pllcfg::lock) == 0 {}
156 regs.pllcfg.modify(pllcfg::sel::SET);
158 }
159 }
160 self.current_frequency.set(frequency);
161
162 regs.hfrosccfg.modify(hfrosccfg::enable::CLEAR);
164 }
165}