1use kernel::utilities::registers::interfaces::{Readable, Writeable};
8use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
9use kernel::utilities::StaticRef;
10
11#[repr(C)]
12struct BpmRegisters {
13    ier: WriteOnly<u32, Interrupt::Register>,
14    idr: WriteOnly<u32, Interrupt::Register>,
15    imr: ReadOnly<u32, Interrupt::Register>,
16    isr: ReadOnly<u32, Interrupt::Register>,
17    icr: WriteOnly<u32, Interrupt::Register>,
18    sr: ReadOnly<u32, Status::Register>,
19    unlock: ReadWrite<u32, Unlock::Register>,
20    pmcon: ReadWrite<u32, PowerModeControl::Register>,
21    _reserved0: [u32; 2],
22    bkupwcause: ReadOnly<u32, BackupWakeup::Register>,
23    bkupwen: ReadWrite<u32, BackupWakeup::Register>,
24    bkuppmux: ReadWrite<u32, BackupPinMuxing::Register>,
25    ioret: ReadWrite<u32, InputOutputRetention::Register>,
26}
27
28register_bitfields![u32,
29    Interrupt [
30        AE 31,
32        PSOK 0
34    ],
35
36    Status [
37        AE 31,
39        PSOK 0
41    ],
42
43    Unlock [
44        KEY OFFSET(24) NUMBITS(8) [],
46        ADDR OFFSET(0) NUMBITS(10) []
48    ],
49
50    PowerModeControl [
51        FASTWKUP OFFSET(24) NUMBITS(1) [
53            NormalWakeup = 0,
54            FastWakeup = 1
55        ],
56        CK32S OFFSET(16) NUMBITS(1) [
58            Osc32k = 0,
59            Rc32k = 1
60        ],
61        SLEEP OFFSET(12) NUMBITS(2) [
63            CpuStopped = 0,
64            CpuAhbStopped = 1,
65            CpuAhbPbGclkStopped = 2,
66            CpuAhbPbGclkClockStopped = 3
67        ],
68        RET OFFSET(9) NUMBITS(1) [
70            NoPowerSave = 0,
71            PowerSave = 1
72        ],
73        BKUP OFFSET(8) NUMBITS(1) [
75            NoPowerSave = 0,
76            PowerSave = 1
77        ],
78        PSCM OFFSET(3) NUMBITS(1) [
87            WithCpuHalt = 0,
88            WithoutCpuHalt = 1
89        ],
90        PSCREQ OFFSET(2) NUMBITS(1) [
92            PowerScalingNotRequested = 0,
93            PowerScalingRequested = 1
94        ],
95        PS OFFSET(0) NUMBITS(2) []
97    ],
98
99    BackupWakeup [
100        BKUP OFFSET(0) NUMBITS(32) [
101            Eic =      0b000001,
102            Ast =      0b000010,
103            Wdt =      0b000100,
104            Bod33 =    0b001000,
105            Bod18 =    0b010000,
106            Picouart = 0b100000
107        ]
108    ],
109
110    BackupPinMuxing [
111        BKUPPMUX OFFSET(0) NUMBITS(9) [
113            Pb01 = 0b000000001,
114            Pa06 = 0b000000010,
115            Pa04 = 0b000000100,
116            Pa05 = 0b000001000,
117            Pa07 = 0b000010000,
118            Pc03 = 0b000100000,
119            Pc04 = 0b001000000,
120            Pc05 = 0b010000000,
121            Pc06 = 0b100000000
122        ]
123    ],
124
125    InputOutputRetention [
126        RET OFFSET(0) NUMBITS(1) [
128            IoLinesNotHeld = 0,
129            IoLinesHeld = 1
130        ]
131    ]
132];
133
134const BPM_UNLOCK_KEY: u32 = 0xAA;
135
136const BPM: StaticRef<BpmRegisters> = unsafe { StaticRef::new(0x400F0000 as *const BpmRegisters) };
137
138pub enum PowerScaling {
143    PS0,
148
149    PS1,
159
160    PS2,
165}
166
167pub enum CK32Source {
168    OSC32K = 0,
169    RC32K = 1,
170}
171
172#[inline(never)]
173pub unsafe fn set_ck32source(source: CK32Source) {
174    let control = BPM.pmcon.extract();
175    unlock_register(0x1c); BPM.pmcon
177        .modify_no_read(control, PowerModeControl::CK32S.val(source as u32));
178}
179
180unsafe fn unlock_register(register_offset: u32) {
181    BPM.unlock
182        .write(Unlock::KEY.val(BPM_UNLOCK_KEY) + Unlock::ADDR.val(register_offset));
183}
184
185unsafe fn power_scaling_ok() -> bool {
186    BPM.sr.is_set(Status::PSOK)
187}
188
189pub unsafe fn set_power_scaling(ps_value: PowerScaling) {
191    while !power_scaling_ok() {}
194
195    let control = BPM.pmcon.extract();
196
197    unlock_register(0x1c); BPM.pmcon.modify_no_read(
202        control,
203        PowerModeControl::PS.val(ps_value as u32)
204            + PowerModeControl::PSCM::WithoutCpuHalt
205            + PowerModeControl::PSCREQ::PowerScalingRequested,
206    );
207}