common: Combine writes to SIM_CLKDIV1 in clock::configure_clkdiv().
[gps-watch.git] / src / common / clock.rs
1 /*
2  * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 use register;
25
26 type Reg8 = register::Register<u8>;
27 type Reg32 = register::Register<u32>;
28
29 const SIM_BASE: u32 = 0x40047000;
30
31 const SIM_SOPT1: u32 = SIM_BASE + 0x0000;
32 const SIM_SOPT2: u32 = SIM_BASE + 0x1004;
33
34 const SIM_SCGC4: u32 = SIM_BASE + 0x1034;
35 const SIM_CLKDIV1: u32 = SIM_BASE + 0x1044;
36
37 const SIM_SOPT1_USBREGEN: u32 = 1 << 31;
38
39 const SIM_SOPT2_PLLFLLSEL: u32 = 1 << 16;
40 const SIM_SOPT2_USBSRC: u32 = 1 << 18;
41
42 const SIM_SCGC4_USBOTG: u32 = 1 << 18;
43
44 const SIM_CLKDIV1_OUTDIV4_SHIFT: u32 = 16;
45 const SIM_CLKDIV1_OUTDIV1_SHIFT: u32 = 28;
46
47 const MCG_BASE: u32 = 0x40064000;
48
49 const MCG_C1: u32 = MCG_BASE + 0;
50 const MCG_C2: u32 = MCG_BASE + 1;
51 const MCG_C4: u32 = MCG_BASE + 3;
52 const MCG_C5: u32 = MCG_BASE + 4;
53 const MCG_C6: u32 = MCG_BASE + 5;
54 const MCG_S : u32 = MCG_BASE + 6;
55
56 const MCG_C1_FRDIV_SHIFT: u32 = 3;
57 const MCG_C1_CLKS_SHIFT: u32 = 6;
58
59 const MCG_C2_IRCS: u8 = 1 << 0;
60 const MCG_C2_EREFS0: u8 = 1 << 2;
61 const MCG_C2_RANGE0_SHIFT: u32 = 4;
62
63 const MCG_C4_DMX32: u8 = 1 << 7;
64 const MCG_C4_DRST_DRS_MASK: u8 = 3 << 5;
65
66 const MCG_C5_PLLSTEN0: u8 = 1 << 5;
67 const MCG_C5_PRDIV0_SHIFT: u32 = 0;
68
69 const MCG_C6_VDIV0_SHIFT: u32 = 0;
70 const MCG_C6_CME0: u8 = 1 << 5;
71 const MCG_C6_PLLS: u8 = 1 << 6;
72
73 const MCG_S_CLKST_SHIFT: u32 = 2;
74 const MCG_S_CLKST_MASK: u8 = 3 << MCG_S_CLKST_SHIFT;
75 const MCG_S_IREFST: u8 = 1 << 4;
76 const MCG_S_LOCK0: u8 = 1 << 6;
77
78 fn configure_clkdiv() {
79     let mut clkdiv1 = Reg32::new(SIM_CLKDIV1);
80
81     clkdiv1.write((1 << SIM_CLKDIV1_OUTDIV4_SHIFT)
82                 | (1 << SIM_CLKDIV1_OUTDIV1_SHIFT));
83 }
84
85 fn switch_to_fbe() {
86     let mut c2 = Reg8::new(MCG_C2);
87     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
88
89     let mut c1 = Reg8::new(MCG_C1);
90     c1.write((2 << MCG_C1_CLKS_SHIFT) | (3 << MCG_C1_FRDIV_SHIFT));
91
92     let mut c4 = Reg8::new(MCG_C4);
93     c4.modify(|v| v & !MCG_C4_DMX32 & !MCG_C4_DRST_DRS_MASK);
94
95     let mut c5 = Reg8::new(MCG_C5);
96     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
97
98     let mut c6 = Reg8::new(MCG_C6);
99     c6.write(24 << MCG_C6_VDIV0_SHIFT);
100
101     let s = Reg8::new(MCG_S);
102
103     while (s.read() & MCG_S_IREFST) != 0 {
104     }
105
106     while (s.read() & MCG_S_CLKST_MASK) != (2 << MCG_S_CLKST_SHIFT) {
107     }
108 }
109
110 fn switch_to_pbe() {
111     let mut c1 = Reg8::new(MCG_C1);
112     c1.write((2 << MCG_C1_CLKS_SHIFT) | (3 << MCG_C1_FRDIV_SHIFT));
113
114     let mut c2 = Reg8::new(MCG_C2);
115     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
116
117     let mut c5 = Reg8::new(MCG_C5);
118     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
119
120     let mut c6 = Reg8::new(MCG_C6);
121     c6.write(MCG_C6_PLLS | 24 << MCG_C6_VDIV0_SHIFT);
122
123     let s = Reg8::new(MCG_S);
124
125     while (s.read() & MCG_S_CLKST_MASK) != (2 << MCG_S_CLKST_SHIFT) {
126     }
127
128     while (s.read() & MCG_S_LOCK0) == 0 {
129     }
130 }
131
132 fn switch_to_pee() {
133     let mut c1 = Reg8::new(MCG_C1);
134     c1.write(3 << MCG_C1_FRDIV_SHIFT);
135
136     let mut c2 = Reg8::new(MCG_C2);
137     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
138
139     let mut c5 = Reg8::new(MCG_C5);
140     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
141
142     let mut c6 = Reg8::new(MCG_C6);
143     c6.write(MCG_C6_PLLS | 24 << MCG_C6_VDIV0_SHIFT);
144
145     let s = Reg8::new(MCG_S);
146
147     while (s.read() & MCG_S_CLKST_MASK) != (3 << MCG_S_CLKST_SHIFT) {
148     }
149
150     c6.modify(|v| v | MCG_C6_CME0);
151 }
152
153 pub unsafe fn configure() {
154     configure_clkdiv();
155
156     switch_to_fbe();
157     switch_to_pbe();
158     switch_to_pee();
159
160     let mut sopt2 = Reg32::new(SIM_SOPT2);
161
162     sopt2.modify(|v| {
163         v | SIM_SOPT2_PLLFLLSEL
164     });
165 }
166
167 pub unsafe fn configure_usb() {
168     let mut scgc4 = Reg32::new(SIM_SCGC4);
169     scgc4.modify(|v| v & !SIM_SCGC4_USBOTG);
170
171     let mut sopt1 = Reg32::new(SIM_SOPT1);
172     sopt1.modify(|v| v | SIM_SOPT1_USBREGEN);
173
174     let mut sopt2 = Reg32::new(SIM_SOPT2);
175     sopt2.modify(|v| v | SIM_SOPT2_USBSRC);
176
177     scgc4.modify(|v| v | SIM_SCGC4_USBOTG);
178 }