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}