1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cpu/barrier.h>
18 #include <plat/cmsis.h>
19 #include <plat/pwr.h>
20 #include <plat/rtc.h>
21 #include <reset.h>
22 #include <stddef.h>
23
24 struct StmRcc {
25 volatile uint32_t CR;
26 volatile uint32_t PLLCFGR;
27 volatile uint32_t CFGR;
28 volatile uint32_t CIR;
29 volatile uint32_t AHB1RSTR;
30 volatile uint32_t AHB2RSTR;
31 volatile uint32_t AHB3RSTR;
32 uint8_t unused0[4];
33 volatile uint32_t APB1RSTR;
34 volatile uint32_t APB2RSTR;
35 uint8_t unused1[8];
36 volatile uint32_t AHB1ENR;
37 volatile uint32_t AHB2ENR;
38 volatile uint32_t AHB3ENR;
39 uint8_t unused2[4];
40 volatile uint32_t APB1ENR;
41 volatile uint32_t APB2ENR;
42 uint8_t unused3[8];
43 volatile uint32_t AHB1LPENR;
44 volatile uint32_t AHB2LPENR;
45 volatile uint32_t AHB3LPENR;
46 uint8_t unused4[4];
47 volatile uint32_t APB1LPENR;
48 volatile uint32_t APB2LPENR;
49 uint8_t unused5[8];
50 volatile uint32_t BDCR;
51 volatile uint32_t CSR;
52 uint8_t unused6[8];
53 volatile uint32_t SSCGR;
54 volatile uint32_t PLLI2SCFGR;
55 };
56
57 struct StmPwr {
58 volatile uint32_t CR;
59 volatile uint32_t CSR;
60 };
61
62 #define RCC ((struct StmRcc*)RCC_BASE)
63 #define PWR ((struct StmPwr*)PWR_BASE)
64
65 /* RCC bit definitions */
66 #define RCC_BDCR_LSEON 0x00000001UL
67 #define RCC_BDCR_LSERDY 0x00000002UL
68 #define RCC_BDCR_LSEBYP 0x00000004UL
69 #define RCC_BDCR_LSEMOD 0x00000008UL
70 #define RCC_BDCR_RTCSEL_LSE 0x00000100UL
71 #define RCC_BDCR_RTCSEL_LSI 0x00000200UL
72 #define RCC_BDCR_RTCEN 0x00008000UL
73 #define RCC_BDCR_BDRST 0x00010000UL
74
75 #define RCC_CSR_LSION 0x00000001UL
76 #define RCC_CSR_LSIRDY 0x00000002UL
77 #define RCC_CSR_RMVF 0x01000000UL
78 #define RCC_CSR_BORRSTF 0x02000000UL
79 #define RCC_CSR_PINRSTF 0x04000000UL
80 #define RCC_CSR_PORRSTF 0x08000000UL
81 #define RCC_CSR_SFTRSTF 0x10000000UL
82 #define RCC_CSR_IWDGRSTF 0x20000000UL
83 #define RCC_CSR_WWDGRSTF 0x40000000UL
84 #define RCC_CSR_LPWRRSTF 0x80000000UL
85
86 /* PWR bit definitions */
87 #define PWR_CR_MRVLDS 0x00000800UL
88 #define PWR_CR_LPLVDS 0x00000400UL
89 #define PWR_CR_FPDS 0x00000200UL
90 #define PWR_CR_DBP 0x00000100UL
91 #define PWR_CR_PDDS 0x00000002UL
92 #define PWR_CR_LPDS 0x00000001UL
93
94
95 static uint32_t mResetReason;
96 static uint32_t mSysClk = 16000000UL;
97
98 #define RCC_REG(_bus, _type) ({ \
99 static const uint32_t clockRegOfsts[] = { \
100 offsetof(struct StmRcc, AHB1##_type), \
101 offsetof(struct StmRcc, AHB2##_type), \
102 offsetof(struct StmRcc, AHB3##_type), \
103 offsetof(struct StmRcc, APB1##_type), \
104 offsetof(struct StmRcc, APB2##_type) \
105 }; /* indexed by PERIPH_BUS_* */ \
106 (volatile uint32_t *)(RCC_BASE + clockRegOfsts[_bus]); \
107 }) \
108
pwrUnitClock(uint32_t bus,uint32_t unit,bool on)109 void pwrUnitClock(uint32_t bus, uint32_t unit, bool on)
110 {
111 volatile uint32_t *reg = RCC_REG(bus, ENR);
112
113 if (on)
114 *reg |= unit;
115 else
116 *reg &=~ unit;
117 }
118
pwrUnitReset(uint32_t bus,uint32_t unit,bool on)119 void pwrUnitReset(uint32_t bus, uint32_t unit, bool on)
120 {
121 volatile uint32_t *reg = RCC_REG(bus, RSTR);
122
123 if (on)
124 *reg |= unit;
125 else
126 *reg &=~ unit;
127 }
128
pwrGetBusSpeed(uint32_t bus)129 uint32_t pwrGetBusSpeed(uint32_t bus)
130 {
131 uint32_t cfg = RCC->CFGR;
132 uint32_t ahbDiv, apb1Div, apb2Div;
133 uint32_t ahbSpeed, apb1Speed, apb2Speed;
134 static const uint8_t ahbSpeedShifts[] = {1, 2, 3, 4, 6, 7, 8, 9};
135
136 ahbDiv = (cfg >> 4) & 0x0F;
137 apb1Div = (cfg >> 10) & 0x07;
138 apb2Div = (cfg >> 13) & 0x07;
139
140 ahbSpeed = (ahbDiv & 0x08) ? (mSysClk >> ahbSpeedShifts[ahbDiv & 0x07]) : mSysClk;
141 apb1Speed = (apb1Div & 0x04) ? (ahbSpeed >> ((apb1Div & 0x03) + 1)) : ahbSpeed;
142 apb2Speed = (apb2Div & 0x04) ? (ahbSpeed >> ((apb2Div & 0x03) + 1)) : ahbSpeed;
143
144 if (bus == PERIPH_BUS_AHB1 || bus == PERIPH_BUS_AHB2 || bus == PERIPH_BUS_AHB3)
145 return ahbSpeed;
146
147 if (bus == PERIPH_BUS_APB1)
148 return apb1Speed;
149
150 if (bus == PERIPH_BUS_APB2)
151 return apb2Speed;
152
153 /* WTF...? */
154 return 0;
155 }
156
pwrParseCsr(uint32_t csr)157 static uint32_t pwrParseCsr(uint32_t csr)
158 {
159 uint32_t reason = 0;
160
161 if (csr & RCC_CSR_LPWRRSTF)
162 reason |= RESET_POWER_MANAGEMENT;
163 if (csr & RCC_CSR_WWDGRSTF)
164 reason |= RESET_WINDOW_WATCHDOG;
165 if (csr & RCC_CSR_IWDGRSTF)
166 reason |= RESET_INDEPENDENT_WATCHDOG;
167 if (csr & RCC_CSR_SFTRSTF)
168 reason |= RESET_SOFTWARE;
169 if (csr & RCC_CSR_PORRSTF)
170 reason |= RESET_POWER_ON;
171 if (csr & RCC_CSR_PINRSTF)
172 reason |= RESET_HARDWARE;
173 if (csr & RCC_CSR_BORRSTF)
174 reason |= RESET_BROWN_OUT;
175
176 return reason;
177 }
178
pwrEnableAndClockRtc(enum RtcClock rtcClock)179 void pwrEnableAndClockRtc(enum RtcClock rtcClock)
180 {
181 uint32_t backupRegs[RTC_NUM_BACKUP_REGS], i, *regs = rtcGetBackupStorage();
182
183 /* Enable power clock */
184 pwrUnitClock(PERIPH_BUS_APB1, PERIPH_APB1_PWR, true);
185
186 /* Enable write permission for backup domain */
187 pwrEnableWriteBackupDomainRegs();
188 /* Prevent compiler reordering across this boundary. */
189 mem_reorder_barrier();
190
191 /* backup the backup regs (they have valuable data we want to persist) */
192 for (i = 0; i < RTC_NUM_BACKUP_REGS; i++)
193 backupRegs[i] = regs[i];
194
195 /* save and reset reset flags */
196 mResetReason = pwrParseCsr(RCC->CSR);
197 RCC->CSR |= RCC_CSR_RMVF;
198
199 /* Reset backup domain */
200 RCC->BDCR |= RCC_BDCR_BDRST;
201 /* Exit reset of backup domain */
202 RCC->BDCR &= ~RCC_BDCR_BDRST;
203
204 /* restore the backup regs */
205 for (i = 0; i < RTC_NUM_BACKUP_REGS; i++)
206 regs[i] = backupRegs[i];
207
208 if (rtcClock == RTC_CLK_LSE || rtcClock == RTC_CLK_LSE_BYPASS) {
209 /* Disable LSI */
210 RCC->CSR &= ~RCC_CSR_LSION;
211 if (rtcClock == RTC_CLK_LSE) {
212 /* Set LSE as backup domain clock source */
213 RCC->BDCR |= RCC_BDCR_LSEON;
214 } else {
215 /* Set LSE as backup domain clock source and enable bypass */
216 RCC->BDCR |= RCC_BDCR_LSEON | RCC_BDCR_LSEBYP;
217 }
218 /* Wait for LSE to be ready */
219 while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0);
220 /* Set LSE as RTC clock source */
221 RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
222 } else {
223 /* Enable LSI */
224 RCC->CSR |= RCC_CSR_LSION;
225 /* Wait for LSI to be ready */
226 while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
227 /* Set LSI as RTC clock source */
228 RCC->BDCR |= RCC_BDCR_RTCSEL_LSI;
229 }
230 /* Enable RTC */
231 RCC->BDCR |= RCC_BDCR_RTCEN;
232 }
233
pwrEnableWriteBackupDomainRegs(void)234 void pwrEnableWriteBackupDomainRegs(void)
235 {
236 PWR->CR |= PWR_CR_DBP;
237 }
238
pwrSetSleepType(enum Stm32F4xxSleepType sleepType)239 void pwrSetSleepType(enum Stm32F4xxSleepType sleepType)
240 {
241 uint32_t cr = PWR->CR &~ (PWR_CR_MRVLDS | PWR_CR_LPLVDS | PWR_CR_FPDS | PWR_CR_PDDS | PWR_CR_LPDS);
242
243 switch (sleepType) {
244 case stm32f411SleepModeSleep:
245 SCB->SCR &=~ SCB_SCR_SLEEPDEEP_Msk;
246 break;
247 case stm32f411SleepModeStopMR:
248 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
249 break;
250 case stm32f411SleepModeStopMRFPD:
251 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
252 cr |= PWR_CR_FPDS;
253 break;
254 case stm32f411SleepModeStopLPFD:
255 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
256 cr |= PWR_CR_FPDS | PWR_CR_LPDS;
257 break;
258 case stm32f411SleepModeStopLPLV:
259 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
260 cr |= PWR_CR_LPLVDS | PWR_CR_LPDS;
261 break;
262 }
263
264 PWR->CR = cr;
265 }
266
pwrSystemInit(void)267 void pwrSystemInit(void)
268 {
269 RCC->CR |= 1; //HSI on
270 while (!(RCC->CR & 2)); //wait for HSI
271 RCC->CFGR = 0x00000000; //all busses at HSI speed
272 RCC->CR &= 0x0000FFF1; //HSI on, all else off
273 }
274
pwrResetReason(void)275 uint32_t pwrResetReason(void)
276 {
277 return mResetReason;
278 }
279