1bebbd1e23eb6463fbd4dac6e71906f9acf063e0
[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_SOPT2: u32 = SIM_BASE + 0x1004;
32
33 const SIM_CLKDIV1: u32 = SIM_BASE + 0x1044;
34
35 const SIM_SOPT2_PLLFLLSEL: u32 = 1 << 16;
36
37 const SIM_CLKDIV1_OUTDIV4_SHIFT: u32 = 16;
38 const SIM_CLKDIV1_OUTDIV1_SHIFT: u32 = 28;
39
40 const MCG_BASE: u32 = 0x40064000;
41
42 const MCG_C1: u32 = MCG_BASE + 0;
43 const MCG_C2: u32 = MCG_BASE + 1;
44 const MCG_C4: u32 = MCG_BASE + 3;
45 const MCG_C5: u32 = MCG_BASE + 4;
46 const MCG_C6: u32 = MCG_BASE + 5;
47 const MCG_S : u32 = MCG_BASE + 6;
48
49 const MCG_C1_FRDIV_SHIFT: u32 = 3;
50 const MCG_C1_CLKS_SHIFT: u32 = 6;
51
52 const MCG_C2_IRCS: u8 = 1 << 0;
53 const MCG_C2_EREFS0: u8 = 1 << 2;
54 const MCG_C2_RANGE0_SHIFT: u32 = 4;
55
56 const MCG_C4_DMX32: u8 = 1 << 7;
57 const MCG_C4_DRST_DRS_MASK: u8 = 3 << 5;
58
59 const MCG_C5_PLLSTEN0: u8 = 1 << 5;
60 const MCG_C5_PRDIV0_SHIFT: u32 = 0;
61
62 const MCG_C6_VDIV0_SHIFT: u32 = 0;
63 const MCG_C6_CME0: u8 = 1 << 5;
64 const MCG_C6_PLLS: u8 = 1 << 6;
65
66 const MCG_S_CLKST_SHIFT: u32 = 2;
67 const MCG_S_CLKST_MASK: u8 = 3 << MCG_S_CLKST_SHIFT;
68 const MCG_S_IREFST: u8 = 1 << 4;
69 const MCG_S_LOCK0: u8 = 1 << 6;
70
71 fn configure_clkdiv() {
72     let mut clkdiv1 = Reg32::new(SIM_CLKDIV1);
73
74     clkdiv1.write(1 << SIM_CLKDIV1_OUTDIV4_SHIFT);
75     clkdiv1.modify(|v| v | (1 << SIM_CLKDIV1_OUTDIV1_SHIFT));
76 }
77
78 fn switch_to_fbe() {
79     let mut c2 = Reg8::new(MCG_C2);
80     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
81
82     let mut c1 = Reg8::new(MCG_C1);
83     c1.write((2 << MCG_C1_CLKS_SHIFT) | (3 << MCG_C1_FRDIV_SHIFT));
84
85     let mut c4 = Reg8::new(MCG_C4);
86     c4.modify(|v| v & !MCG_C4_DMX32 & !MCG_C4_DRST_DRS_MASK);
87
88     let mut c5 = Reg8::new(MCG_C5);
89     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
90
91     let mut c6 = Reg8::new(MCG_C6);
92     c6.write(24 << MCG_C6_VDIV0_SHIFT);
93
94     let s = Reg8::new(MCG_S);
95
96     while (s.read() & MCG_S_IREFST) != 0 {
97     }
98
99     while (s.read() & MCG_S_CLKST_MASK) != (2 << MCG_S_CLKST_SHIFT) {
100     }
101 }
102
103 fn switch_to_pbe() {
104     let mut c1 = Reg8::new(MCG_C1);
105     c1.write((2 << MCG_C1_CLKS_SHIFT) | (3 << MCG_C1_FRDIV_SHIFT));
106
107     let mut c2 = Reg8::new(MCG_C2);
108     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
109
110     let mut c5 = Reg8::new(MCG_C5);
111     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
112
113     let mut c6 = Reg8::new(MCG_C6);
114     c6.write(MCG_C6_PLLS | 24 << MCG_C6_VDIV0_SHIFT);
115
116     let s = Reg8::new(MCG_S);
117
118     while (s.read() & MCG_S_CLKST_MASK) != (2 << MCG_S_CLKST_SHIFT) {
119     }
120
121     while (s.read() & MCG_S_LOCK0) == 0 {
122     }
123 }
124
125 fn switch_to_pee() {
126     let mut c1 = Reg8::new(MCG_C1);
127     c1.write(3 << MCG_C1_FRDIV_SHIFT);
128
129     let mut c2 = Reg8::new(MCG_C2);
130     c2.write((2 << MCG_C2_RANGE0_SHIFT) | MCG_C2_EREFS0 | MCG_C2_IRCS);
131
132     let mut c5 = Reg8::new(MCG_C5);
133     c5.write(MCG_C5_PLLSTEN0 | (11 << MCG_C5_PRDIV0_SHIFT));
134
135     let mut c6 = Reg8::new(MCG_C6);
136     c6.write(MCG_C6_PLLS | 24 << MCG_C6_VDIV0_SHIFT);
137
138     let s = Reg8::new(MCG_S);
139
140     while (s.read() & MCG_S_CLKST_MASK) != (3 << MCG_S_CLKST_SHIFT) {
141     }
142
143     c6.modify(|v| v | MCG_C6_CME0);
144 }
145
146 pub unsafe fn configure() {
147     configure_clkdiv();
148
149     switch_to_fbe();
150     switch_to_pbe();
151     switch_to_pee();
152
153     let mut sopt2 = Reg32::new(SIM_SOPT2);
154
155     sopt2.modify(|v| {
156         v | SIM_SOPT2_PLLFLLSEL
157     });
158 }