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/inc/barrier.h>
18 #include <plat/inc/cmsis.h>
19 #include <plat/inc/pwr.h>
20 #include <plat/inc/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 #define RCC ((struct StmRcc*)RCC_BASE)
58 
59 struct StmPwr {
60     volatile uint32_t CR;
61     volatile uint32_t CSR;
62 };
63 
64 #define PWR ((struct StmPwr*)PWR_BASE)
65 
66 /* RCC bit definitions */
67 #define RCC_BDCR_LSEON      0x00000001UL
68 #define RCC_BDCR_LSERDY     0x00000002UL
69 #define RCC_BDCR_LSEBYP     0x00000004UL
70 #define RCC_BDCR_LSEMOD     0x00000008UL
71 #define RCC_BDCR_RTCSEL_LSE 0x00000100UL
72 #define RCC_BDCR_RTCSEL_LSI 0x00000200UL
73 #define RCC_BDCR_RTCEN      0x00008000UL
74 #define RCC_BDCR_BDRST      0x00010000UL
75 
76 #define RCC_CSR_LSION       0x00000001UL
77 #define RCC_CSR_LSIRDY      0x00000002UL
78 #define RCC_CSR_RMVF        0x01000000UL
79 #define RCC_CSR_BORRSTF     0x02000000UL
80 #define RCC_CSR_PINRSTF     0x04000000UL
81 #define RCC_CSR_PORRSTF     0x08000000UL
82 #define RCC_CSR_SFTRSTF     0x10000000UL
83 #define RCC_CSR_IWDGRSTF    0x20000000UL
84 #define RCC_CSR_WWDGRSTF    0x40000000UL
85 #define RCC_CSR_LPWRRSTF    0x80000000UL
86 
87 /* PWR bit definitions */
88 #define PWR_CR_MRVLDS       0x00000800UL
89 #define PWR_CR_LPLVDS       0x00000400UL
90 #define PWR_CR_FPDS         0x00000200UL
91 #define PWR_CR_DBP          0x00000100UL
92 #define PWR_CR_PDDS         0x00000002UL
93 #define PWR_CR_LPDS         0x00000001UL
94 
95 
96 static uint32_t mResetReason;
97 static uint32_t mSysClk = 16000000UL;
98 
99 #define RCC_REG(_bus, _type) ({                                 \
100         static const uint32_t clockRegOfsts[] = {               \
101             offsetof(struct StmRcc, AHB1##_type),               \
102             offsetof(struct StmRcc, AHB2##_type),               \
103             offsetof(struct StmRcc, AHB3##_type),               \
104             offsetof(struct StmRcc, APB1##_type),               \
105             offsetof(struct StmRcc, APB2##_type)                \
106         }; /* indexed by PERIPH_BUS_* */                        \
107         (volatile uint32_t *)(RCC_BASE + clockRegOfsts[_bus]);  \
108     })                                                          \
109 
pwrUnitClock(uint32_t bus,uint32_t unit,bool on)110 void pwrUnitClock(uint32_t bus, uint32_t unit, bool on)
111 {
112     volatile uint32_t *reg = RCC_REG(bus, ENR);
113 
114     if (on)
115         *reg |= unit;
116     else
117         *reg &=~ unit;
118 }
119 
pwrUnitReset(uint32_t bus,uint32_t unit,bool on)120 void pwrUnitReset(uint32_t bus, uint32_t unit, bool on)
121 {
122     volatile uint32_t *reg = RCC_REG(bus, RSTR);
123 
124     if (on)
125         *reg |= unit;
126     else
127         *reg &=~ unit;
128 }
129 
pwrGetBusSpeed(uint32_t bus)130 uint32_t pwrGetBusSpeed(uint32_t bus)
131 {
132     uint32_t cfg = RCC->CFGR;
133     uint32_t ahbDiv, apb1Div, apb2Div;
134     uint32_t ahbSpeed, apb1Speed, apb2Speed;
135     static const uint8_t ahbSpeedShifts[] = {1, 2, 3, 4, 6, 7, 8, 9};
136 
137     ahbDiv = (cfg >> 4) & 0x0F;
138     apb1Div = (cfg >> 10) & 0x07;
139     apb2Div = (cfg >> 13) & 0x07;
140 
141     ahbSpeed = (ahbDiv & 0x08) ? (mSysClk >> ahbSpeedShifts[ahbDiv & 0x07]) : mSysClk;
142     apb1Speed = (apb1Div & 0x04) ? (ahbSpeed >> ((apb1Div & 0x03) + 1)) : ahbSpeed;
143     apb2Speed = (apb2Div & 0x04) ? (ahbSpeed >> ((apb2Div & 0x03) + 1)) : ahbSpeed;
144 
145     if (bus == PERIPH_BUS_AHB1 || bus == PERIPH_BUS_AHB2 || bus == PERIPH_BUS_AHB3)
146         return ahbSpeed;
147 
148     if (bus == PERIPH_BUS_APB1)
149         return apb1Speed;
150 
151     if (bus == PERIPH_BUS_APB2)
152         return apb2Speed;
153 
154     /* WTF...? */
155     return 0;
156 }
157 
pwrParseCsr(uint32_t csr)158 static uint32_t pwrParseCsr(uint32_t csr)
159 {
160     uint32_t reason = 0;
161 
162     if (csr & RCC_CSR_LPWRRSTF)
163         reason |= RESET_POWER_MANAGEMENT;
164     if (csr & RCC_CSR_WWDGRSTF)
165         reason |= RESET_WINDOW_WATCHDOG;
166     if (csr & RCC_CSR_IWDGRSTF)
167         reason |= RESET_INDEPENDENT_WATCHDOG;
168     if (csr & RCC_CSR_SFTRSTF)
169         reason |= RESET_SOFTWARE;
170     if (csr & RCC_CSR_PORRSTF)
171         reason |= RESET_POWER_ON;
172     if (csr & RCC_CSR_PINRSTF)
173         reason |= RESET_HARDWARE;
174     if (csr & RCC_CSR_BORRSTF)
175         reason |= RESET_BROWN_OUT;
176 
177     return reason;
178 }
179 
pwrEnableAndClockRtc(enum RtcClock rtcClock)180 void pwrEnableAndClockRtc(enum RtcClock rtcClock)
181 {
182     uint32_t backupRegs[RTC_NUM_BACKUP_REGS], i, *regs = rtcGetBackupStorage();
183 
184     /* Enable power clock */
185     RCC->APB1ENR |= PERIPH_APB1_PWR;
186 
187     /* Enable write permission for backup domain */
188     pwrEnableWriteBackupDomainRegs();
189     /* Prevent compiler reordering across this boundary. */
190     mem_reorder_barrier();
191 
192     /* backup the backup regs (they have valuable data we want to persist) */
193     for (i = 0; i < RTC_NUM_BACKUP_REGS; i++)
194         backupRegs[i] = regs[i];
195 
196     /* save and reset reset flags */
197     mResetReason = pwrParseCsr(RCC->CSR);
198     RCC->CSR |= RCC_CSR_RMVF;
199 
200     /* Reset backup domain */
201     RCC->BDCR |= RCC_BDCR_BDRST;
202     /* Exit reset of backup domain */
203     RCC->BDCR &= ~RCC_BDCR_BDRST;
204 
205     /* restore the backup regs */
206     for (i = 0; i < RTC_NUM_BACKUP_REGS; i++)
207         regs[i] = backupRegs[i];
208 
209     if (rtcClock == RTC_CLK_LSE || rtcClock == RTC_CLK_LSE_BYPASS) {
210         /* Disable LSI */
211         RCC->CSR &= ~RCC_CSR_LSION;
212         if (rtcClock == RTC_CLK_LSE) {
213             /* Set LSE as backup domain clock source */
214             RCC->BDCR |= RCC_BDCR_LSEON;
215         } else {
216             /* Set LSE as backup domain clock source and enable bypass */
217             RCC->BDCR |= RCC_BDCR_LSEON | RCC_BDCR_LSEBYP;
218         }
219         /* Wait for LSE to be ready */
220         while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0);
221         /* Set LSE as RTC clock source */
222         RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
223     } else {
224         /* Enable LSI */
225         RCC->CSR |= RCC_CSR_LSION;
226         /* Wait for LSI to be ready */
227         while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
228         /* Set LSI as RTC clock source */
229         RCC->BDCR |= RCC_BDCR_RTCSEL_LSI;
230     }
231     /* Enable RTC */
232     RCC->BDCR |= RCC_BDCR_RTCEN;
233 }
234 
pwrEnableWriteBackupDomainRegs(void)235 void pwrEnableWriteBackupDomainRegs(void)
236 {
237     PWR->CR |= PWR_CR_DBP;
238 }
239 
pwrSetSleepType(enum Stm32F4xxSleepType sleepType)240 void pwrSetSleepType(enum Stm32F4xxSleepType sleepType)
241 {
242     uint32_t cr = PWR->CR &~ (PWR_CR_MRVLDS | PWR_CR_LPLVDS | PWR_CR_FPDS | PWR_CR_PDDS | PWR_CR_LPDS);
243 
244     switch (sleepType) {
245     case stm32f411SleepModeSleep:
246         SCB->SCR &=~ SCB_SCR_SLEEPDEEP_Msk;
247         break;
248     case stm32f144SleepModeStopMR:
249         SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
250         break;
251     case stm32f144SleepModeStopMRFPD:
252         SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
253         cr |= PWR_CR_FPDS;
254         break;
255     case stm32f411SleepModeStopLPFD:
256         SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
257         cr |= PWR_CR_FPDS | PWR_CR_LPDS;
258         break;
259     case stm32f411SleepModeStopLPLV:
260         SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
261         cr |= PWR_CR_LPLVDS | PWR_CR_LPDS;
262         break;
263     }
264 
265     PWR->CR = cr;
266 }
267 
pwrSystemInit(void)268 void pwrSystemInit(void)
269 {
270     RCC->CR |= 1;                             //HSI on
271     while (!(RCC->CR & 2));                    //wait for HSI
272     RCC->CFGR = 0x00000000;                   //all busses at HSI speed
273     RCC->CR &= 0x0000FFF1;                    //HSI on, all else off
274 }
275 
pwrResetReason(void)276 uint32_t pwrResetReason(void)
277 {
278     return mResetReason;
279 }
280