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 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 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 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 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 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 234 void pwrEnableWriteBackupDomainRegs(void) 235 { 236 PWR->CR |= PWR_CR_DBP; 237 } 238 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 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 275 uint32_t pwrResetReason(void) 276 { 277 return mResetReason; 278 } 279