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 <cpu/cpuMath.h>
     19 #include <plat/rtc.h>
     20 #include <plat/pwr.h>
     21 #include <timer.h>
     22 #include <platform.h>
     23 #include <plat/exti.h>
     24 #include <plat/cmsis.h>
     25 #include <variant/variant.h>
     26 
     27 #ifndef NS_PER_S
     28 #define NS_PER_S                    UINT64_C(1000000000)
     29 #endif
     30 
     31 
     32 struct StmRtc
     33 {
     34     volatile uint32_t TR;       /* 0x00 */
     35     volatile uint32_t DR;       /* 0x04 */
     36     volatile uint32_t CR;       /* 0x08 */
     37     volatile uint32_t ISR;      /* 0x0C */
     38     volatile uint32_t PRER;     /* 0x10 */
     39     volatile uint32_t WUTR;     /* 0x14 */
     40     volatile uint32_t CALIBR;   /* 0x18 */
     41     volatile uint32_t ALRMAR;   /* 0x1C */
     42     volatile uint32_t ALRMBR;   /* 0x20 */
     43     volatile uint32_t WPR;      /* 0x24 */
     44     volatile uint32_t SSR;      /* 0x28 */
     45     volatile uint32_t SHIFTR;   /* 0x2C */
     46     volatile uint32_t TSTR;     /* 0x30 */
     47     volatile uint32_t TSDR;     /* 0x34 */
     48     volatile uint32_t TSSSR;    /* 0x38 */
     49     volatile uint32_t CALR;     /* 0x3C */
     50     volatile uint32_t TAFCR;    /* 0x40 */
     51     volatile uint32_t ALRMASSR; /* 0x44 */
     52     volatile uint32_t ALRMBSSR; /* 0x48 */
     53     uint8_t unused0[4];         /* 0x4C */
     54     volatile uint32_t BKPR[20]; /* 0x50 - 0x9C */
     55 };
     56 
     57 #define RTC ((struct StmRtc*)RTC_BASE)
     58 
     59 /* RTC bit defintions */
     60 #define RTC_CR_WUCKSEL_MASK         0x00000007UL
     61 #define RTC_CR_WUCKSEL_16DIV        0x00000000UL
     62 #define RTC_CR_WUCKSEL_8DIV         0x00000001UL
     63 #define RTC_CR_WUCKSEL_4DIV         0x00000002UL
     64 #define RTC_CR_WUCKSEL_2DIV         0x00000003UL
     65 #define RTC_CR_WUCKSEL_CK_SPRE      0x00000004UL
     66 #define RTC_CR_WUCKSEL_CK_SPRE_2    0x00000006UL
     67 #define RTC_CR_BYPSHAD              0x00000020UL
     68 #define RTC_CR_FMT                  0x00000040UL
     69 #define RTC_CR_ALRAE                0x00000100UL
     70 #define RTC_CR_WUTE                 0x00000400UL
     71 #define RTC_CR_ALRAIE               0x00001000UL
     72 #define RTC_CR_WUTIE                0x00004000UL
     73 
     74 #define RTC_ISR_ALRAWF              0x00000001UL
     75 #define RTC_ISR_WUTWF               0x00000004UL
     76 #define RTC_ISR_RSF                 0x00000020UL
     77 #define RTC_ISR_INITF               0x00000040UL
     78 #define RTC_ISR_INIT                0x00000080UL
     79 #define RTC_ISR_WUTF                0x00000400UL
     80 
     81 /* RTC internal values */
     82 #define RTC_FREQ_HZ                 32768UL
     83 #define RTC_WKUP_DOWNCOUNT_MAX      0x10000UL
     84 
     85 /* TODO: Reset to crystal PPM once known */
     86 #define RTC_PPM                     50UL
     87 
     88 /* Default prescalars of P[async] = 127 and P[sync] = 255 are appropriate
     89  * produce a 1 Hz clock when using a 32.768kHZ clock source */
     90 #ifndef RTC_PREDIV_A
     91 #define RTC_PREDIV_A                31UL
     92 #endif
     93 #ifndef RTC_PREDIV_S
     94 #define RTC_PREDIV_S                1023UL
     95 #endif
     96 #ifndef RTC_CALM
     97 #define RTC_CALM                    0
     98 #endif
     99 #ifndef RTC_CALP
    100 #define RTC_CALP                    0
    101 #endif
    102 
    103 /* Jitter = max wakeup timer resolution (61.035 us)
    104  * + 2 RTC cycles for synchronization (61.035 us) */
    105 #define RTC_DIV2_PERIOD_NS          UINT64_C(61035)
    106 #define RTC_DIV4_PERIOD_NS          UINT64_C(122070)
    107 #define RTC_DIV8_PERIOD_NS          UINT64_C(244141)
    108 #define RTC_DIV16_PERIOD_NS         UINT64_C(488281)
    109 
    110 #define RTC_VALID_DELAY_FOR_PERIOD(delay, period) \
    111     (delay < (period * (RTC_WKUP_DOWNCOUNT_MAX + 1)))
    112 
    113 static void rtcSetDefaultDateTimeAndPrescalar(void)
    114 {
    115     /* Enable writability of RTC registers */
    116     RTC->WPR = 0xCA;
    117     RTC->WPR = 0x53;
    118 
    119     /* Enter RTC init mode */
    120     RTC->ISR |= RTC_ISR_INIT;
    121 
    122     mem_reorder_barrier();
    123     /* Wait for initialization mode to be entered. */
    124     while ((RTC->ISR & RTC_ISR_INITF) == 0);
    125 
    126     /* Set prescalar rtc register.  Two writes required. */
    127     RTC->PRER = RTC_PREDIV_S;
    128     RTC->PRER |= (RTC_PREDIV_A << 16);
    129     RTC->CALR = (RTC_CALP << 15) | (RTC_CALM & 0x1FF);
    130 
    131     /* 24 hour format */
    132     RTC->CR &= ~RTC_CR_FMT;
    133 
    134     /* disable shadow registers */
    135     RTC->CR |= RTC_CR_BYPSHAD;
    136 
    137     /* Set time and date registers to defaults */
    138     /* Midnight */
    139     RTC->TR = 0x0;
    140     RTC->SSR = 0x0;
    141     /* Sat Jan 1st, 2000 BCD */
    142     RTC->DR = 0b1100000100000001;
    143 
    144     /* Exit init mode for RTC */
    145     RTC->ISR &= ~RTC_ISR_INIT;
    146 
    147     /* Re-enable register write protection.  RTC counting doesn't start for
    148      * 4 RTC cycles after set - must poll RSF before read DR or TR */
    149     RTC->WPR = 0xFF;
    150 
    151     extiEnableIntLine(EXTI_LINE_RTC_WKUP, EXTI_TRIGGER_RISING);
    152     NVIC_EnableIRQ(RTC_WKUP_IRQn);
    153 }
    154 
    155 void rtcInit(void)
    156 {
    157     pwrEnableAndClockRtc(RTC_CLK);
    158     rtcSetDefaultDateTimeAndPrescalar();
    159 }
    160 
    161 /* Set calendar alarm to go off after delay has expired. uint64_t delay must
    162  * be in valid uint64_t format */
    163 int rtcSetWakeupTimer(uint64_t delay)
    164 {
    165     uint64_t intState;
    166     uint64_t periodNsRecip;
    167     uint32_t wakeupClock;
    168     uint32_t periodNs;
    169 
    170     /* Minimum wakeup interrupt period is 122 us, max is 36.4 hours */
    171     if (delay < (RTC_DIV2_PERIOD_NS * 2)) {
    172         return RTC_ERR_TOO_SMALL;
    173     } else if (delay > (NS_PER_S * 2 * RTC_WKUP_DOWNCOUNT_MAX)) {
    174         delay = NS_PER_S * 2 * RTC_WKUP_DOWNCOUNT_MAX;
    175     }
    176 
    177     /* Get appropriate clock period for delay size.  Wakeup clock = RTC/x. */
    178     if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV2_PERIOD_NS)) {
    179 
    180         wakeupClock = RTC_CR_WUCKSEL_2DIV;
    181         periodNs = RTC_DIV2_PERIOD_NS;
    182         periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV2_PERIOD_NS);
    183     }
    184     else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV4_PERIOD_NS)) {
    185 
    186         wakeupClock = RTC_CR_WUCKSEL_4DIV;
    187         periodNs = RTC_DIV4_PERIOD_NS;
    188         periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV4_PERIOD_NS);
    189     }
    190     else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV8_PERIOD_NS)) {
    191 
    192         wakeupClock = RTC_CR_WUCKSEL_8DIV;
    193         periodNs = RTC_DIV8_PERIOD_NS;
    194         periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV8_PERIOD_NS);
    195     }
    196     else if (RTC_VALID_DELAY_FOR_PERIOD(delay, RTC_DIV16_PERIOD_NS)) {
    197 
    198         wakeupClock = RTC_CR_WUCKSEL_16DIV;
    199         periodNs = RTC_DIV16_PERIOD_NS;
    200         periodNsRecip = U64_RECIPROCAL_CALCULATE(RTC_DIV16_PERIOD_NS);
    201     }
    202     else {
    203 
    204         if (RTC_VALID_DELAY_FOR_PERIOD(delay, NS_PER_S))
    205             wakeupClock = RTC_CR_WUCKSEL_CK_SPRE;
    206         else
    207             wakeupClock = RTC_CR_WUCKSEL_CK_SPRE_2;
    208         periodNs = NS_PER_S;
    209         periodNsRecip = U64_RECIPROCAL_CALCULATE(NS_PER_S);
    210     }
    211 
    212     intState = cpuIntsOff();
    213 
    214     /* Enable RTC register write */
    215     RTC->WPR = 0xCA;
    216     RTC->WPR = 0x53;
    217 
    218     /* Disable wakeup timer */
    219     RTC->CR &= ~RTC_CR_WUTE;
    220 
    221     /* Wait for access enabled for wakeup timer registers */
    222     while ((RTC->ISR & RTC_ISR_WUTWF) == 0);
    223 
    224     /* Clear wakeup clock source */
    225     RTC->CR &= ~RTC_CR_WUCKSEL_MASK;
    226 
    227     RTC->CR |= wakeupClock;
    228     /* Downcounter value for wakeup clock.  Wakeup flag is set every
    229      * RTC->WUTR[15:0] + 1 cycles of the WUT clock. */
    230     RTC->WUTR = cpuMathRecipAssistedUdiv64by32(delay, periodNs, periodNsRecip) - 1;
    231 
    232     /* Enable wakeup interrupts */
    233     RTC->CR |= RTC_CR_WUTIE;
    234     extiClearPendingLine(EXTI_LINE_RTC_WKUP);
    235 
    236     /* Enable wakeup timer */
    237     RTC->CR |= RTC_CR_WUTE;
    238 
    239     /* Clear overflow flag */
    240     RTC->ISR &= ~RTC_ISR_WUTF;
    241 
    242     /* Write-protect RTC registers */
    243     RTC->WPR = 0xFF;
    244 
    245     cpuIntsRestore(intState);
    246 
    247     return 0;
    248 }
    249 
    250 uint64_t rtcGetTime(void)
    251 {
    252     int32_t time_s;
    253     uint32_t dr, tr, ssr;
    254     // cumulative adjustments from 32 day months (year 2000)
    255     //   31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    256     //    1,  3,  1,  2,  1,  2,  1,  1,  2,  1,  2,  1
    257     //  0   1,  4,  5,  7,  8, 10, 11, 12, 14, 15, 17
    258     static const uint8_t adjust[] = { 0, 1, 4, 5, 7, 8, 10, 11, 12, 14, 15, 17 };
    259     uint8_t month;
    260 
    261     // need to loop incase an interrupt occurs in the middle or ssr
    262     // decrements (which can propagate changes to tr and dr)
    263     do {
    264         ssr = RTC->SSR;
    265         tr = RTC->TR;
    266         dr = RTC->DR;
    267     } while (ssr != RTC->SSR);
    268 
    269     month = (((dr >> 12) & 0x1) * 10) + ((dr >> 8) & 0xf) - 1;
    270     time_s = (((((dr >> 4) & 0x3) * 10) + (dr & 0xF) - 1) + (month << 5) - adjust[month]) * 86400ULL;
    271     time_s += ((((tr >> 22) & 0x1) * 43200ULL) +
    272              (((tr >> 20) & 0x3) * 36000ULL) +
    273              (((tr >> 16) & 0xF) * 3600ULL) +
    274              (((tr >> 12) & 0x7) * 600ULL) +
    275              (((tr >> 8) & 0xF) * 60ULL) +
    276              (((tr >> 4) & 0x7) * 10ULL) +
    277              (((tr) & 0xF)));
    278 
    279     return (time_s * NS_PER_S) + U64_DIV_BY_CONST_U16(((RTC_PREDIV_S - ssr) * NS_PER_S), (RTC_PREDIV_S + 1));
    280 }
    281 
    282 void EXTI22_RTC_WKUP_IRQHandler(void);
    283 void EXTI22_RTC_WKUP_IRQHandler(void)
    284 {
    285     extiClearPendingLine(EXTI_LINE_RTC_WKUP);
    286     timIntHandler();
    287 }
    288 
    289 uint32_t* rtcGetBackupStorage(void)
    290 {
    291     return (uint32_t*)RTC->BKPR;
    292 }
    293