Home | History | Annotate | Download | only in stm32
      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