1e419bc7fSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause 2e419bc7fSGatien Chevallier /* 3d60c61e1SGatien Chevallier * Copyright (C) 2018-2025, STMicroelectronics 4e419bc7fSGatien Chevallier */ 5e419bc7fSGatien Chevallier #include <assert.h> 6e419bc7fSGatien Chevallier #include <drivers/clk.h> 7e419bc7fSGatien Chevallier #include <drivers/clk_dt.h> 8e419bc7fSGatien Chevallier #include <drivers/rtc.h> 9*63000677SClément Le Goffic #include <drivers/stm32_rtc.h> 10e419bc7fSGatien Chevallier #include <drivers/stm32_rif.h> 11d60c61e1SGatien Chevallier #include <drivers/stm32_rtc.h> 12e419bc7fSGatien Chevallier #include <io.h> 137818ae9bSClément Le Goffic #include <keep.h> 14e419bc7fSGatien Chevallier #include <kernel/dt.h> 15e419bc7fSGatien Chevallier #include <kernel/dt_driver.h> 167818ae9bSClément Le Goffic #include <kernel/interrupt.h> 177818ae9bSClément Le Goffic #include <kernel/notif.h> 18e419bc7fSGatien Chevallier #include <kernel/panic.h> 19*63000677SClément Le Goffic #include <kernel/pm.h> 20d60c61e1SGatien Chevallier #include <kernel/spinlock.h> 21e419bc7fSGatien Chevallier #include <libfdt.h> 22e419bc7fSGatien Chevallier #include <mm/core_memprot.h> 23e419bc7fSGatien Chevallier 24e419bc7fSGatien Chevallier /* 25e419bc7fSGatien Chevallier * Registers 26e419bc7fSGatien Chevallier */ 27e419bc7fSGatien Chevallier #define RTC_TR U(0x00) 28e419bc7fSGatien Chevallier #define RTC_DR U(0x04) 29e419bc7fSGatien Chevallier #define RTC_SSR U(0x08) 30e419bc7fSGatien Chevallier #define RTC_ICSR U(0x0C) 31e419bc7fSGatien Chevallier #define RTC_PRER U(0x10) 32e419bc7fSGatien Chevallier #define RTC_WUTR U(0x14) 33e419bc7fSGatien Chevallier #define RTC_CR U(0x18) 34e419bc7fSGatien Chevallier #define RTC_PRIVCFGR U(0x1C) 35e419bc7fSGatien Chevallier /* RTC_SMCR is linked to RTC3v1_2 */ 36e419bc7fSGatien Chevallier #define RTC_SMCR U(0x20) 37e419bc7fSGatien Chevallier /* RTC_SECCFGR is linked to RTC3v3_2 and above */ 38e419bc7fSGatien Chevallier #define RTC_SECCFGR U(0x20) 39e419bc7fSGatien Chevallier #define RTC_WPR U(0x24) 40e419bc7fSGatien Chevallier #define RTC_CALR U(0x28) 41e419bc7fSGatien Chevallier #define RTC_SHIFTR U(0x2C) 42e419bc7fSGatien Chevallier #define RTC_TSTR U(0x30) 43e419bc7fSGatien Chevallier #define RTC_TSDR U(0x34) 44e419bc7fSGatien Chevallier #define RTC_TSSSR U(0x38) 45e419bc7fSGatien Chevallier #define RTC_ALRMAR U(0x40) 46e419bc7fSGatien Chevallier #define RTC_ALRMASSR U(0x44) 47e419bc7fSGatien Chevallier #define RTC_ALRMBR U(0x48) 48e419bc7fSGatien Chevallier #define RTC_ALRMBSSR U(0x4C) 49e419bc7fSGatien Chevallier #define RTC_SR U(0x50) 50e419bc7fSGatien Chevallier #define RTC_SCR U(0x5C) 51e419bc7fSGatien Chevallier #define RTC_OR U(0x60) 52e419bc7fSGatien Chevallier #define RTC_CIDCFGR(x) (U(0x80) + U(0x4) * (x)) 53e419bc7fSGatien Chevallier 54e419bc7fSGatien Chevallier #define RTC_TR_SU_MASK GENMASK_32(3, 0) 55e419bc7fSGatien Chevallier #define RTC_TR_ST_MASK GENMASK_32(6, 4) 56e419bc7fSGatien Chevallier #define RTC_TR_ST_SHIFT U(4) 57e419bc7fSGatien Chevallier #define RTC_TR_MNU_MASK GENMASK_32(11, 8) 58e419bc7fSGatien Chevallier #define RTC_TR_MNU_SHIFT U(8) 59e419bc7fSGatien Chevallier #define RTC_TR_MNT_MASK GENMASK_32(14, 12) 60e419bc7fSGatien Chevallier #define RTC_TR_MNT_SHIFT U(12) 61e419bc7fSGatien Chevallier #define RTC_TR_HU_MASK GENMASK_32(19, 16) 62e419bc7fSGatien Chevallier #define RTC_TR_HU_SHIFT U(16) 63e419bc7fSGatien Chevallier #define RTC_TR_HT_MASK GENMASK_32(21, 20) 64e419bc7fSGatien Chevallier #define RTC_TR_HT_SHIFT U(20) 65e419bc7fSGatien Chevallier #define RTC_TR_PM BIT(22) 66e419bc7fSGatien Chevallier 67e419bc7fSGatien Chevallier #define RTC_DR_DU_MASK GENMASK_32(3, 0) 68e419bc7fSGatien Chevallier #define RTC_DR_DT_MASK GENMASK_32(5, 4) 69e419bc7fSGatien Chevallier #define RTC_DR_DT_SHIFT U(4) 70e419bc7fSGatien Chevallier #define RTC_DR_MU_MASK GENMASK_32(11, 8) 71e419bc7fSGatien Chevallier #define RTC_DR_MU_SHIFT U(8) 72e419bc7fSGatien Chevallier #define RTC_DR_MT_MASK BIT(12) 73e419bc7fSGatien Chevallier #define RTC_DR_MT_SHIFT U(12) 74e419bc7fSGatien Chevallier #define RTC_DR_WDU_MASK GENMASK_32(15, 13) 75e419bc7fSGatien Chevallier #define RTC_DR_WDU_SHIFT U(13) 76e419bc7fSGatien Chevallier #define RTC_DR_YU_MASK GENMASK_32(19, 16) 77e419bc7fSGatien Chevallier #define RTC_DR_YU_SHIFT U(16) 78e419bc7fSGatien Chevallier #define RTC_DR_YT_MASK GENMASK_32(23, 20) 79e419bc7fSGatien Chevallier #define RTC_DR_YT_SHIFT U(20) 80e419bc7fSGatien Chevallier 81e419bc7fSGatien Chevallier #define RTC_SSR_SS_MASK GENMASK_32(15, 0) 82e419bc7fSGatien Chevallier 83e419bc7fSGatien Chevallier #define RTC_ICSR_RSF BIT(5) 84e419bc7fSGatien Chevallier #define RTC_ICSR_INITF BIT(6) 85e419bc7fSGatien Chevallier #define RTC_ICSR_INIT BIT(7) 86e419bc7fSGatien Chevallier 87446da993SClément Le Goffic #define RTC_PRER_PREDIV_S_SHIFT U(0) 88e419bc7fSGatien Chevallier #define RTC_PRER_PREDIV_S_MASK GENMASK_32(14, 0) 89446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_SHIFT U(16) 90446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_MASK GENMASK_32(22, 16) 91e419bc7fSGatien Chevallier 92e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD BIT(5) 93e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD_SHIFT U(5) 94446da993SClément Le Goffic #define RTC_CR_FMT BIT(6) 957818ae9bSClément Le Goffic #define RTC_CR_ALRAE BIT(8) 967818ae9bSClément Le Goffic #define RTC_CR_ALRAIE BIT(12) 97e419bc7fSGatien Chevallier #define RTC_CR_TAMPTS BIT(25) 98e419bc7fSGatien Chevallier 99e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES GENMASK_32(3, 0) 100e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES_TO_SHIFT GENMASK_32(5, 4) 101e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_SHIFT U(9) 102e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_MASK (GENMASK_32(14, 13) | GENMASK_32(3, 0)) 103e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_FULL_PRIV BIT(15) 104e419bc7fSGatien Chevallier 105e419bc7fSGatien Chevallier #define RTC_SMCR_TS_DPROT BIT(3) 106e419bc7fSGatien Chevallier 107e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES GENMASK_32(3, 0) 108e419bc7fSGatien Chevallier #define RTC_SECCFGR_TS_SEC BIT(3) 109e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES_TO_SHIFT GENMASK_32(5, 4) 110e419bc7fSGatien Chevallier #define RTC_SECCFGR_SHIFT U(9) 111e419bc7fSGatien Chevallier #define RTC_SECCFGR_MASK (GENMASK_32(14, 13) | GENMASK_32(3, 0)) 112e419bc7fSGatien Chevallier #define RTC_SECCFGR_FULL_SEC BIT(15) 113e419bc7fSGatien Chevallier 114e419bc7fSGatien Chevallier #define RTC_WPR_KEY1 U(0xCA) 115e419bc7fSGatien Chevallier #define RTC_WPR_KEY2 U(0x53) 116e419bc7fSGatien Chevallier #define RTC_WPR_KEY_LOCK U(0xFF) 117e419bc7fSGatien Chevallier 118e419bc7fSGatien Chevallier #define RTC_TSDR_MU_MASK GENMASK_32(11, 8) 119e419bc7fSGatien Chevallier #define RTC_TSDR_MU_SHIFT U(8) 120e419bc7fSGatien Chevallier #define RTC_TSDR_DT_MASK GENMASK_32(5, 4) 121e419bc7fSGatien Chevallier #define RTC_TSDR_DT_SHIFT U(4) 122e419bc7fSGatien Chevallier #define RTC_TSDR_DU_MASK GENMASK_32(3, 0) 123e419bc7fSGatien Chevallier #define RTC_TSDR_DU_SHIFT U(0) 124e419bc7fSGatien Chevallier 1257818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_UNITS_MASK GENMASK_32(3, 0) 1267818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_UNITS_SHIFT U(0) 1277818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_TENS_MASK GENMASK_32(6, 4) 1287818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_TENS_SHIFT U(4) 1297818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_MASK BIT(7) 1307818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_UNITS_MASK GENMASK_32(11, 8) 1317818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_UNITS_SHIFT U(8) 1327818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_TENS_MASK GENMASK_32(14, 12) 1337818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_TENS_SHIFT U(12) 1347818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_MASK BIT(15) 1357818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_UNITS_MASK GENMASK_32(19, 16) 1367818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_UNITS_SHIFT U(16) 1377818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_TENS_MASK GENMASK_32(21, 20) 1387818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_TENS_SHIFT U(20) 1397818ae9bSClément Le Goffic #define RTC_ALRMXR_PM BIT(22) 1407818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_MASK BIT(23) 1417818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_UNITS_MASK GENMASK_32(27, 24) 1427818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_UNITS_SHIFT U(24) 1437818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_TENS_MASK GENMASK_32(29, 28) 1447818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_TENS_SHIFT U(28) 1457818ae9bSClément Le Goffic 1467818ae9bSClément Le Goffic #define RTC_SR_ALRAF BIT(0) 147e419bc7fSGatien Chevallier #define RTC_SR_TSF BIT(3) 148e419bc7fSGatien Chevallier #define RTC_SR_TSOVF BIT(4) 149e419bc7fSGatien Chevallier 1507818ae9bSClément Le Goffic #define RTC_SCR_CALRAF BIT(0) 151e419bc7fSGatien Chevallier #define RTC_SCR_CTSF BIT(3) 152e419bc7fSGatien Chevallier #define RTC_SCR_CTSOVF BIT(4) 153e419bc7fSGatien Chevallier 154e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK GENMASK_32(6, 4) 155e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK_SHIFT U(4) 156e419bc7fSGatien Chevallier #define RTC_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | \ 157e419bc7fSGatien Chevallier RTC_CIDCFGR_SCID_MASK) 158e419bc7fSGatien Chevallier 159e419bc7fSGatien Chevallier /* 160e419bc7fSGatien Chevallier * RIF miscellaneous 161e419bc7fSGatien Chevallier */ 162e419bc7fSGatien Chevallier #define RTC_NB_RIF_RESOURCES U(6) 163e419bc7fSGatien Chevallier 164e419bc7fSGatien Chevallier #define RTC_RIF_FULL_PRIVILEGED U(0x3F) 165e419bc7fSGatien Chevallier #define RTC_RIF_FULL_SECURED U(0x3F) 166e419bc7fSGatien Chevallier 167e419bc7fSGatien Chevallier #define RTC_NB_MAX_CID_SUPPORTED U(7) 168e419bc7fSGatien Chevallier 169e419bc7fSGatien Chevallier /* 170e419bc7fSGatien Chevallier * Driver miscellaneous 171e419bc7fSGatien Chevallier */ 172e419bc7fSGatien Chevallier #define RTC_RES_TIMESTAMP U(3) 173e419bc7fSGatien Chevallier #define RTC_RES_CALIBRATION U(4) 174e419bc7fSGatien Chevallier #define RTC_RES_INITIALIZATION U(5) 175e419bc7fSGatien Chevallier 176e419bc7fSGatien Chevallier #define RTC_FLAGS_READ_TWICE BIT(0) 177e419bc7fSGatien Chevallier 178e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_SHADOW U(10000) 179e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_GENERIC U(100000) 180e419bc7fSGatien Chevallier 181e419bc7fSGatien Chevallier #define YEAR_REF ULL(2000) 182e419bc7fSGatien Chevallier #define YEAR_MAX (YEAR_REF + ULL(99)) 183e419bc7fSGatien Chevallier 184e419bc7fSGatien Chevallier struct rtc_compat { 185e419bc7fSGatien Chevallier bool has_seccfgr; 186e419bc7fSGatien Chevallier bool has_rif_support; 187e419bc7fSGatien Chevallier }; 188e419bc7fSGatien Chevallier 189e419bc7fSGatien Chevallier /* 190e419bc7fSGatien Chevallier * struct rtc_device - RTC device data 191e419bc7fSGatien Chevallier * @base: RTC IOMEM base address 192e419bc7fSGatien Chevallier * @compat: RTC compatible data 193e419bc7fSGatien Chevallier * @pclk: RTC bus clock 194e419bc7fSGatien Chevallier * @rtc_ck: RTC kernel clock 195e419bc7fSGatien Chevallier * @conf_data: RTC RIF configuration data, when supported 196e419bc7fSGatien Chevallier * @nb_res: Number of protectible RTC resources 197d60c61e1SGatien Chevallier * @ts_lock: Lock used for time stamping events handling 198e419bc7fSGatien Chevallier * @flags: RTC driver flags 199e419bc7fSGatien Chevallier * @is_secured: True if the RTC is fully secured 2007818ae9bSClément Le Goffic * @itr_chip: Interrupt chip 2017818ae9bSClément Le Goffic * @itr_num: Interrupt number 2027818ae9bSClément Le Goffic * @itr_handler: Interrupt handler 2037818ae9bSClément Le Goffic * @notif_id: Notification ID 2047818ae9bSClément Le Goffic * @wait_alarm_return_status: Status of the wait alarm thread 205*63000677SClément Le Goffic * @rtc: information for OP-TEE RTC device 206e419bc7fSGatien Chevallier */ 207e419bc7fSGatien Chevallier struct rtc_device { 208e419bc7fSGatien Chevallier struct io_pa_va base; 209e419bc7fSGatien Chevallier const struct rtc_compat *compat; 210e419bc7fSGatien Chevallier struct clk *pclk; 211e419bc7fSGatien Chevallier struct clk *rtc_ck; 212e419bc7fSGatien Chevallier struct rif_conf_data *conf_data; 213e419bc7fSGatien Chevallier unsigned int nb_res; 214d60c61e1SGatien Chevallier unsigned int ts_lock; 215e419bc7fSGatien Chevallier uint8_t flags; 216e419bc7fSGatien Chevallier bool is_secured; 2177818ae9bSClément Le Goffic struct itr_chip *itr_chip; 2187818ae9bSClément Le Goffic size_t itr_num; 2197818ae9bSClément Le Goffic struct itr_handler *itr_handler; 2207818ae9bSClément Le Goffic uint32_t notif_id; 2217818ae9bSClément Le Goffic enum rtc_wait_alarm_status wait_alarm_return_status; 222*63000677SClément Le Goffic struct rtc *rtc; 223e419bc7fSGatien Chevallier }; 224e419bc7fSGatien Chevallier 225e419bc7fSGatien Chevallier /* Expect a single RTC instance */ 226e419bc7fSGatien Chevallier static struct rtc_device rtc_dev; 227e419bc7fSGatien Chevallier 228e419bc7fSGatien Chevallier static vaddr_t get_base(void) 229e419bc7fSGatien Chevallier { 230e419bc7fSGatien Chevallier assert(rtc_dev.base.pa); 231e419bc7fSGatien Chevallier 232e419bc7fSGatien Chevallier return io_pa_or_va(&rtc_dev.base, 1); 233e419bc7fSGatien Chevallier } 234e419bc7fSGatien Chevallier 235e419bc7fSGatien Chevallier static void stm32_rtc_write_unprotect(void) 236e419bc7fSGatien Chevallier { 237e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 238e419bc7fSGatien Chevallier 239e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY1); 240e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY2); 241e419bc7fSGatien Chevallier } 242e419bc7fSGatien Chevallier 243e419bc7fSGatien Chevallier static void stm32_rtc_write_protect(void) 244e419bc7fSGatien Chevallier { 245e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 246e419bc7fSGatien Chevallier 247e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK); 248e419bc7fSGatien Chevallier } 249e419bc7fSGatien Chevallier 250e419bc7fSGatien Chevallier static bool stm32_rtc_get_bypshad(void) 251e419bc7fSGatien Chevallier { 252e419bc7fSGatien Chevallier return io_read32(get_base() + RTC_CR) & RTC_CR_BYPSHAD; 253e419bc7fSGatien Chevallier } 254e419bc7fSGatien Chevallier 255e419bc7fSGatien Chevallier /* Get the subsecond value. */ 256e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond(uint32_t ssr) 257e419bc7fSGatien Chevallier { 258e419bc7fSGatien Chevallier uint32_t prediv_s = io_read32(get_base() + RTC_PRER) & 259e419bc7fSGatien Chevallier RTC_PRER_PREDIV_S_MASK; 260e419bc7fSGatien Chevallier 261e419bc7fSGatien Chevallier return prediv_s - ssr; 262e419bc7fSGatien Chevallier } 263e419bc7fSGatien Chevallier 264e419bc7fSGatien Chevallier /* 265e419bc7fSGatien Chevallier * Get the subsecond scale. 266e419bc7fSGatien Chevallier * 267e419bc7fSGatien Chevallier * Number of subseconds in a second is linked to RTC PREDIV_S value. 268e419bc7fSGatien Chevallier * The higher PREDIV_S is, the more subsecond is precise. 269e419bc7fSGatien Chevallier */ 270e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond_scale(void) 271e419bc7fSGatien Chevallier { 272e419bc7fSGatien Chevallier return (io_read32(get_base() + RTC_PRER) & RTC_PRER_PREDIV_S_MASK) + 1; 273e419bc7fSGatien Chevallier } 274e419bc7fSGatien Chevallier 275e419bc7fSGatien Chevallier static bool cid1_has_access(unsigned int resource) 276e419bc7fSGatien Chevallier { 277e419bc7fSGatien Chevallier uint32_t cidcfgr = io_read32(get_base() + RTC_CIDCFGR(resource)); 278e419bc7fSGatien Chevallier 279e419bc7fSGatien Chevallier return !(cidcfgr & _CIDCFGR_CFEN) || 280e419bc7fSGatien Chevallier get_field_u32(cidcfgr, RTC_CIDCFGR_SCID_MASK) == RIF_CID1; 281e419bc7fSGatien Chevallier } 282e419bc7fSGatien Chevallier 283e419bc7fSGatien Chevallier static TEE_Result check_rif_config(void) 284e419bc7fSGatien Chevallier { 285e419bc7fSGatien Chevallier if (!cid1_has_access(RTC_RES_TIMESTAMP) || 286e419bc7fSGatien Chevallier !cid1_has_access(RTC_RES_CALIBRATION) || 287e419bc7fSGatien Chevallier !cid1_has_access(RTC_RES_INITIALIZATION)) 288e419bc7fSGatien Chevallier return TEE_ERROR_ACCESS_DENIED; 289e419bc7fSGatien Chevallier 290e419bc7fSGatien Chevallier return TEE_SUCCESS; 291e419bc7fSGatien Chevallier } 292e419bc7fSGatien Chevallier 293e419bc7fSGatien Chevallier static void apply_rif_config(bool is_tdcid) 294e419bc7fSGatien Chevallier { 295e419bc7fSGatien Chevallier vaddr_t base = get_base(); 296e419bc7fSGatien Chevallier unsigned int shifted_values = 0; 297e419bc7fSGatien Chevallier uint32_t seccfgr = 0; 298e419bc7fSGatien Chevallier uint32_t privcfgr = 0; 299e419bc7fSGatien Chevallier uint32_t access_mask_reg = 0; 300e419bc7fSGatien Chevallier unsigned int i = 0; 301e419bc7fSGatien Chevallier 302e419bc7fSGatien Chevallier if (!rtc_dev.conf_data) 303e419bc7fSGatien Chevallier return; 304e419bc7fSGatien Chevallier 305e419bc7fSGatien Chevallier /* Build access mask for RTC_SECCFGR and RTC_PRIVCFGR */ 306e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 307e419bc7fSGatien Chevallier if (rtc_dev.conf_data->access_mask[0] & BIT(i)) { 308e419bc7fSGatien Chevallier if (i <= RTC_RES_TIMESTAMP) 309e419bc7fSGatien Chevallier access_mask_reg |= BIT(i); 310e419bc7fSGatien Chevallier else 311e419bc7fSGatien Chevallier access_mask_reg |= BIT(i) << RTC_SECCFGR_SHIFT; 312e419bc7fSGatien Chevallier } 313e419bc7fSGatien Chevallier } 314e419bc7fSGatien Chevallier 315e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 316e419bc7fSGatien Chevallier if (!(BIT(i) & rtc_dev.conf_data->access_mask[0])) 317e419bc7fSGatien Chevallier continue; 318e419bc7fSGatien Chevallier 319e419bc7fSGatien Chevallier /* 320e419bc7fSGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID filtering 321e419bc7fSGatien Chevallier * configuration. Clearing previous configuration prevents 322e419bc7fSGatien Chevallier * undesired events during the only legitimate configuration. 323e419bc7fSGatien Chevallier */ 324e419bc7fSGatien Chevallier if (is_tdcid) 325e419bc7fSGatien Chevallier io_clrbits32(base + RTC_CIDCFGR(i), 326e419bc7fSGatien Chevallier RTC_CIDCFGR_CONF_MASK); 327e419bc7fSGatien Chevallier } 328e419bc7fSGatien Chevallier 329e419bc7fSGatien Chevallier /* Security RIF configuration */ 330e419bc7fSGatien Chevallier seccfgr = rtc_dev.conf_data->sec_conf[0]; 331e419bc7fSGatien Chevallier 332e419bc7fSGatien Chevallier /* Check if all resources must be secured */ 333e419bc7fSGatien Chevallier if (seccfgr == RTC_RIF_FULL_SECURED) { 334e419bc7fSGatien Chevallier io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_FULL_SEC); 335e419bc7fSGatien Chevallier rtc_dev.is_secured = true; 336e419bc7fSGatien Chevallier 337e419bc7fSGatien Chevallier if (!(io_read32(base + RTC_SECCFGR) & RTC_SECCFGR_FULL_SEC)) 338e419bc7fSGatien Chevallier panic("Bad RTC seccfgr configuration"); 339e419bc7fSGatien Chevallier } 340e419bc7fSGatien Chevallier 341e419bc7fSGatien Chevallier /* Shift some values to align with the register */ 342e419bc7fSGatien Chevallier shifted_values = SHIFT_U32(seccfgr & RTC_SECCFGR_VALUES_TO_SHIFT, 343e419bc7fSGatien Chevallier RTC_SECCFGR_SHIFT); 344e419bc7fSGatien Chevallier seccfgr = (seccfgr & RTC_SECCFGR_VALUES) + shifted_values; 345e419bc7fSGatien Chevallier 346e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_SECCFGR, 347e419bc7fSGatien Chevallier RTC_SECCFGR_MASK & access_mask_reg, seccfgr); 348e419bc7fSGatien Chevallier 349e419bc7fSGatien Chevallier /* Privilege RIF configuration */ 350e419bc7fSGatien Chevallier privcfgr = rtc_dev.conf_data->priv_conf[0]; 351e419bc7fSGatien Chevallier 352e419bc7fSGatien Chevallier /* Check if all resources must be privileged */ 353e419bc7fSGatien Chevallier if (privcfgr == RTC_RIF_FULL_PRIVILEGED) { 354e419bc7fSGatien Chevallier io_setbits32(base + RTC_PRIVCFGR, RTC_PRIVCFGR_FULL_PRIV); 355e419bc7fSGatien Chevallier 356e419bc7fSGatien Chevallier if (!(io_read32(base + RTC_PRIVCFGR) & RTC_PRIVCFGR_FULL_PRIV)) 357e419bc7fSGatien Chevallier panic("Bad RTC privcfgr configuration"); 358e419bc7fSGatien Chevallier } 359e419bc7fSGatien Chevallier 360e419bc7fSGatien Chevallier /* Shift some values to align with the register */ 361e419bc7fSGatien Chevallier shifted_values = SHIFT_U32(privcfgr & RTC_PRIVCFGR_VALUES_TO_SHIFT, 362e419bc7fSGatien Chevallier RTC_PRIVCFGR_SHIFT); 363e419bc7fSGatien Chevallier privcfgr = (privcfgr & RTC_PRIVCFGR_VALUES) + shifted_values; 364e419bc7fSGatien Chevallier 365e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_PRIVCFGR, 366e419bc7fSGatien Chevallier RTC_PRIVCFGR_MASK & access_mask_reg, privcfgr); 367e419bc7fSGatien Chevallier 368e419bc7fSGatien Chevallier if (!is_tdcid) 369e419bc7fSGatien Chevallier return; 370e419bc7fSGatien Chevallier 371e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 372e419bc7fSGatien Chevallier if (!(BIT(i) & rtc_dev.conf_data->access_mask[0])) 373e419bc7fSGatien Chevallier continue; 374e419bc7fSGatien Chevallier /* 375e419bc7fSGatien Chevallier * When at least one resource has CID filtering enabled, 376e419bc7fSGatien Chevallier * the RTC_PRIVCFGR_FULL_PRIV and RTC_SECCFGR_FULL_SEC bits are 377e419bc7fSGatien Chevallier * cleared. 378e419bc7fSGatien Chevallier */ 379e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_CIDCFGR(i), 380e419bc7fSGatien Chevallier RTC_CIDCFGR_CONF_MASK, 381e419bc7fSGatien Chevallier rtc_dev.conf_data->cid_confs[i]); 382e419bc7fSGatien Chevallier } 383e419bc7fSGatien Chevallier } 384e419bc7fSGatien Chevallier 3857818ae9bSClément Le Goffic static void stm32_rtc_clear_events(uint32_t flags) 3867818ae9bSClément Le Goffic { 3877818ae9bSClément Le Goffic io_write32(get_base() + RTC_SCR, flags); 3887818ae9bSClément Le Goffic } 3897818ae9bSClément Le Goffic 3907818ae9bSClément Le Goffic static enum itr_return stm32_rtc_it_handler(struct itr_handler *h __unused) 3917818ae9bSClément Le Goffic { 3927818ae9bSClément Le Goffic vaddr_t rtc_base = get_base(); 3937818ae9bSClément Le Goffic uint32_t status = io_read32(rtc_base + RTC_SR); 3947818ae9bSClément Le Goffic uint32_t cr = io_read32(rtc_base + RTC_CR); 3957818ae9bSClément Le Goffic 3967818ae9bSClément Le Goffic if ((status & RTC_SR_ALRAF) && (cr & RTC_CR_ALRAIE)) { 3977818ae9bSClément Le Goffic DMSG("Alarm occurred"); 3987818ae9bSClément Le Goffic /* Clear event's flags */ 3997818ae9bSClément Le Goffic stm32_rtc_clear_events(RTC_SCR_CALRAF); 4007818ae9bSClément Le Goffic /* 4017818ae9bSClément Le Goffic * Notify the caller of 'stm32_rtc_wait_alarm' to re-schedule 4027818ae9bSClément Le Goffic * the calling thread. 4037818ae9bSClément Le Goffic */ 4047818ae9bSClément Le Goffic notif_send_async(rtc_dev.notif_id, 0); 4057818ae9bSClément Le Goffic } 4067818ae9bSClément Le Goffic 4077818ae9bSClément Le Goffic return ITRR_HANDLED; 4087818ae9bSClément Le Goffic } 4097818ae9bSClément Le Goffic DECLARE_KEEP_PAGER(stm32_rtc_it_handler); 4107818ae9bSClément Le Goffic 411e419bc7fSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node) 412e419bc7fSGatien Chevallier { 413e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 414e419bc7fSGatien Chevallier const fdt32_t *cuint = NULL; 415e419bc7fSGatien Chevallier size_t reg_size = 0; 416e419bc7fSGatien Chevallier unsigned int i = 0; 417e419bc7fSGatien Chevallier int lenp = 0; 418e419bc7fSGatien Chevallier 419e419bc7fSGatien Chevallier if (fdt_reg_info(fdt, node, &rtc_dev.base.pa, ®_size)) 420e419bc7fSGatien Chevallier panic(); 421e419bc7fSGatien Chevallier 422e419bc7fSGatien Chevallier io_pa_or_va(&rtc_dev.base, reg_size); 423e419bc7fSGatien Chevallier assert(rtc_dev.base.va); 424e419bc7fSGatien Chevallier 425e419bc7fSGatien Chevallier res = clk_dt_get_by_name(fdt, node, "pclk", &rtc_dev.pclk); 426e419bc7fSGatien Chevallier if (res) 427e419bc7fSGatien Chevallier return res; 428e419bc7fSGatien Chevallier 429e419bc7fSGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rtc_ck", &rtc_dev.rtc_ck); 430e419bc7fSGatien Chevallier if (res) 431e419bc7fSGatien Chevallier return res; 432e419bc7fSGatien Chevallier 4337818ae9bSClément Le Goffic res = interrupt_dt_get(fdt, node, &rtc_dev.itr_chip, 4347818ae9bSClément Le Goffic &rtc_dev.itr_num); 435*63000677SClément Le Goffic if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND) 4367818ae9bSClément Le Goffic return res; 437*63000677SClément Le Goffic 438*63000677SClément Le Goffic if (fdt_getprop(fdt, node, "wakeup-source", NULL)) { 439*63000677SClément Le Goffic if (res != TEE_ERROR_ITEM_NOT_FOUND && 440*63000677SClément Le Goffic interrupt_can_set_wake(rtc_dev.itr_chip)) 441*63000677SClément Le Goffic rtc_dev.rtc->is_wakeup_source = true; 442*63000677SClément Le Goffic else 443*63000677SClément Le Goffic DMSG("RTC wakeup source ignored"); 4447818ae9bSClément Le Goffic } 4457818ae9bSClément Le Goffic 446e419bc7fSGatien Chevallier if (!rtc_dev.compat->has_rif_support) 447e419bc7fSGatien Chevallier return TEE_SUCCESS; 448e419bc7fSGatien Chevallier 449e419bc7fSGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 450e419bc7fSGatien Chevallier if (!cuint) { 451e419bc7fSGatien Chevallier DMSG("No RIF configuration available"); 452e419bc7fSGatien Chevallier return TEE_SUCCESS; 453e419bc7fSGatien Chevallier } 454e419bc7fSGatien Chevallier 455e419bc7fSGatien Chevallier rtc_dev.conf_data = calloc(1, sizeof(*rtc_dev.conf_data)); 456e419bc7fSGatien Chevallier if (!rtc_dev.conf_data) 457e419bc7fSGatien Chevallier panic(); 458e419bc7fSGatien Chevallier 459e419bc7fSGatien Chevallier rtc_dev.nb_res = (unsigned int)(lenp / sizeof(uint32_t)); 460e419bc7fSGatien Chevallier assert(rtc_dev.nb_res <= RTC_NB_RIF_RESOURCES); 461e419bc7fSGatien Chevallier 462e419bc7fSGatien Chevallier rtc_dev.conf_data->cid_confs = calloc(RTC_NB_RIF_RESOURCES, 463e419bc7fSGatien Chevallier sizeof(uint32_t)); 464e419bc7fSGatien Chevallier rtc_dev.conf_data->sec_conf = calloc(1, sizeof(uint32_t)); 465e419bc7fSGatien Chevallier rtc_dev.conf_data->priv_conf = calloc(1, sizeof(uint32_t)); 466e419bc7fSGatien Chevallier rtc_dev.conf_data->access_mask = calloc(1, sizeof(uint32_t)); 467e419bc7fSGatien Chevallier if (!rtc_dev.conf_data->cid_confs || !rtc_dev.conf_data->sec_conf || 468e419bc7fSGatien Chevallier !rtc_dev.conf_data->priv_conf || !rtc_dev.conf_data->access_mask) 469e419bc7fSGatien Chevallier panic("Not enough memory capacity for RTC RIF config"); 470e419bc7fSGatien Chevallier 471e419bc7fSGatien Chevallier for (i = 0; i < rtc_dev.nb_res; i++) 472e419bc7fSGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), rtc_dev.conf_data, 473e419bc7fSGatien Chevallier RTC_NB_RIF_RESOURCES); 474e419bc7fSGatien Chevallier 475e419bc7fSGatien Chevallier return TEE_SUCCESS; 476e419bc7fSGatien Chevallier } 477e419bc7fSGatien Chevallier 478e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_enter_init_mode(void) 479e419bc7fSGatien Chevallier { 480e419bc7fSGatien Chevallier vaddr_t base = get_base(); 481e419bc7fSGatien Chevallier uint32_t icsr = io_read32(base + RTC_ICSR); 482e419bc7fSGatien Chevallier uint32_t value = 0; 483e419bc7fSGatien Chevallier 484e419bc7fSGatien Chevallier if (!(icsr & RTC_ICSR_INITF)) { 485e419bc7fSGatien Chevallier icsr |= RTC_ICSR_INIT; 486e419bc7fSGatien Chevallier io_write32(base + RTC_ICSR, icsr); 487e419bc7fSGatien Chevallier 488e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value, 489e419bc7fSGatien Chevallier value & RTC_ICSR_INITF, 490e419bc7fSGatien Chevallier 10, TIMEOUT_US_RTC_GENERIC)) 491e419bc7fSGatien Chevallier return TEE_ERROR_BUSY; 492e419bc7fSGatien Chevallier } 493e419bc7fSGatien Chevallier 494e419bc7fSGatien Chevallier return TEE_SUCCESS; 495e419bc7fSGatien Chevallier } 496e419bc7fSGatien Chevallier 497446da993SClément Le Goffic static TEE_Result stm32_rtc_exit_init_mode(void) 498e419bc7fSGatien Chevallier { 499e419bc7fSGatien Chevallier vaddr_t base = get_base(); 500e419bc7fSGatien Chevallier uint32_t value = 0; 501e419bc7fSGatien Chevallier 502446da993SClément Le Goffic io_clrbits32(base + RTC_ICSR, RTC_ICSR_INIT); 503446da993SClément Le Goffic dsb(); 504446da993SClément Le Goffic 505e419bc7fSGatien Chevallier io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF); 506e419bc7fSGatien Chevallier 507e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value, 508e419bc7fSGatien Chevallier value & RTC_ICSR_RSF, 10, 509e419bc7fSGatien Chevallier TIMEOUT_US_RTC_GENERIC)) 510e419bc7fSGatien Chevallier return TEE_ERROR_BUSY; 511e419bc7fSGatien Chevallier 512e419bc7fSGatien Chevallier return TEE_SUCCESS; 513e419bc7fSGatien Chevallier } 514e419bc7fSGatien Chevallier 515d60c61e1SGatien Chevallier static void stm32_rtc_to_tm(uint32_t ssr, uint32_t tr, uint32_t dr, 516d60c61e1SGatien Chevallier struct optee_rtc_time *tm) 517d60c61e1SGatien Chevallier { 518d60c61e1SGatien Chevallier tm->tm_hour = ((tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10 + 519d60c61e1SGatien Chevallier ((tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT); 520d60c61e1SGatien Chevallier 521d60c61e1SGatien Chevallier if (tr & RTC_TR_PM) 522d60c61e1SGatien Chevallier tm->tm_hour += 12; 523d60c61e1SGatien Chevallier 524d60c61e1SGatien Chevallier tm->tm_ms = (stm32_rtc_get_subsecond(ssr) * MS_PER_SEC) / 525d60c61e1SGatien Chevallier stm32_rtc_get_subsecond_scale(); 526d60c61e1SGatien Chevallier 527d60c61e1SGatien Chevallier tm->tm_sec = ((tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10 + 528d60c61e1SGatien Chevallier (tr & RTC_TR_SU_MASK); 529d60c61e1SGatien Chevallier 530d60c61e1SGatien Chevallier tm->tm_min = ((tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10 + 531d60c61e1SGatien Chevallier ((tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT); 532d60c61e1SGatien Chevallier 533d60c61e1SGatien Chevallier tm->tm_wday = ((dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT) % 7; 534d60c61e1SGatien Chevallier 535d60c61e1SGatien Chevallier tm->tm_mday = ((dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10 + 536d60c61e1SGatien Chevallier (dr & RTC_DR_DU_MASK); 537d60c61e1SGatien Chevallier 538d60c61e1SGatien Chevallier tm->tm_mon = ((dr & RTC_DR_MT_MASK) >> RTC_DR_MT_SHIFT) * 10 + 539d60c61e1SGatien Chevallier ((dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT) - 1; 540d60c61e1SGatien Chevallier 541d60c61e1SGatien Chevallier tm->tm_year = ((dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10 + 542d60c61e1SGatien Chevallier ((dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + YEAR_REF; 543d60c61e1SGatien Chevallier } 544d60c61e1SGatien Chevallier 545446da993SClément Le Goffic static TEE_Result stm32_rtc_init(void) 546446da993SClément Le Goffic { 547446da993SClément Le Goffic uint32_t pred_a_max = RTC_PRER_PREDIV_A_MASK >> RTC_PRER_PREDIV_A_SHIFT; 548446da993SClément Le Goffic uint32_t pred_s_max = RTC_PRER_PREDIV_S_MASK >> RTC_PRER_PREDIV_S_SHIFT; 549446da993SClément Le Goffic unsigned long rate = clk_get_rate(rtc_dev.rtc_ck); 550446da993SClément Le Goffic TEE_Result res = TEE_ERROR_GENERIC; 551446da993SClément Le Goffic vaddr_t base = get_base(); 552446da993SClément Le Goffic uint32_t pred_a = 0; 553446da993SClément Le Goffic uint32_t pred_s = 0; 554446da993SClément Le Goffic uint32_t prer = io_read32(base + RTC_PRER); 555446da993SClément Le Goffic uint32_t cr = io_read32(base + RTC_CR); 556446da993SClément Le Goffic 557446da993SClément Le Goffic if (rate > (pred_a_max + 1) * (pred_s_max + 1)) 558446da993SClément Le Goffic panic("rtc_ck rate is too high"); 559446da993SClément Le Goffic 560446da993SClément Le Goffic if (cr & RTC_CR_FMT && !IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) 561446da993SClément Le Goffic return TEE_SUCCESS; 562446da993SClément Le Goffic 563446da993SClément Le Goffic if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) { 564446da993SClément Le Goffic /* 565446da993SClément Le Goffic * Compute the prescaler values whom divides the clock in order 566446da993SClément Le Goffic * to get a * 1 Hz output by maximizing accuracy 567446da993SClément Le Goffic * (maximizing PREDIV_S). 568446da993SClément Le Goffic */ 569446da993SClément Le Goffic for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { 570446da993SClément Le Goffic pred_s = (rate / (pred_a + 1)) - 1; 571446da993SClément Le Goffic if (pred_s <= pred_s_max && 572446da993SClément Le Goffic ((pred_s + 1) * (pred_a + 1)) == rate) 573446da993SClément Le Goffic break; 574446da993SClément Le Goffic } 575446da993SClément Le Goffic 576446da993SClément Le Goffic /* 577446da993SClément Le Goffic * 1 Hz output not possible, give priority to RTC power 578446da993SClément Le Goffic * consumption by choosing the higher possible value for 579446da993SClément Le Goffic * prediv_a 580446da993SClément Le Goffic */ 581446da993SClément Le Goffic if (pred_s > pred_s_max || pred_a > pred_a_max) { 582446da993SClément Le Goffic pred_a = pred_a_max; 583446da993SClément Le Goffic pred_s = (rate / (pred_a + 1)) - 1; 584446da993SClément Le Goffic 585446da993SClément Le Goffic DMSG("rtc_ck is %s", 586446da993SClément Le Goffic (rate < ((pred_a + 1) * (pred_s + 1))) ? 587446da993SClément Le Goffic "fast" : "slow"); 588446da993SClément Le Goffic } 589446da993SClément Le Goffic 590446da993SClément Le Goffic prer &= RTC_PRER_PREDIV_S_MASK | RTC_PRER_PREDIV_A_MASK; 591446da993SClément Le Goffic pred_s = SHIFT_U32(pred_s, RTC_PRER_PREDIV_S_SHIFT) & 592446da993SClément Le Goffic RTC_PRER_PREDIV_S_MASK; 593446da993SClément Le Goffic pred_a = SHIFT_U32(pred_a, RTC_PRER_PREDIV_A_SHIFT) & 594446da993SClément Le Goffic RTC_PRER_PREDIV_A_MASK; 595446da993SClément Le Goffic 596446da993SClément Le Goffic /* Return if there is nothing to initialize */ 597446da993SClément Le Goffic if (cr & RTC_CR_FMT && prer == (pred_s | pred_a)) 598446da993SClément Le Goffic return TEE_SUCCESS; 599446da993SClément Le Goffic } 600446da993SClément Le Goffic 601446da993SClément Le Goffic stm32_rtc_write_unprotect(); 602446da993SClément Le Goffic 603446da993SClément Le Goffic res = stm32_rtc_enter_init_mode(); 604446da993SClément Le Goffic if (res) { 605446da993SClément Le Goffic EMSG("Can't enter init mode. Fail to initialize RTC."); 606446da993SClément Le Goffic stm32_rtc_write_protect(); 607446da993SClément Le Goffic return res; 608446da993SClément Le Goffic } 609446da993SClément Le Goffic 610446da993SClément Le Goffic if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) { 611446da993SClément Le Goffic io_write32(base + RTC_PRER, pred_s); 612446da993SClément Le Goffic io_write32(base + RTC_PRER, pred_a | pred_s); 613446da993SClément Le Goffic } 614446da993SClément Le Goffic 615446da993SClément Le Goffic /* Force 24h time format */ 616446da993SClément Le Goffic cr &= ~RTC_CR_FMT; 617446da993SClément Le Goffic io_write32(base + RTC_CR, cr); 618446da993SClément Le Goffic 619446da993SClément Le Goffic res = stm32_rtc_exit_init_mode(); 620446da993SClément Le Goffic if (res) 621446da993SClément Le Goffic EMSG("Can't exit init mode. Fail to initialize RTC."); 622446da993SClément Le Goffic 623446da993SClément Le Goffic stm32_rtc_write_protect(); 624446da993SClément Le Goffic 625446da993SClément Le Goffic return res; 626446da993SClément Le Goffic } 627446da993SClément Le Goffic 628e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_get_time(struct rtc *rtc __unused, 629e419bc7fSGatien Chevallier struct optee_rtc_time *tm) 630e419bc7fSGatien Chevallier { 631e419bc7fSGatien Chevallier vaddr_t base = get_base(); 632e419bc7fSGatien Chevallier uint32_t ssr = 0; 633e419bc7fSGatien Chevallier uint32_t dr = 0; 634e419bc7fSGatien Chevallier uint32_t tr = 0; 635e419bc7fSGatien Chevallier 636e419bc7fSGatien Chevallier if (!stm32_rtc_get_bypshad()) { 637e419bc7fSGatien Chevallier uint32_t icsr = 0; 638e419bc7fSGatien Chevallier 639e419bc7fSGatien Chevallier /* Wait calendar registers are ready */ 640e419bc7fSGatien Chevallier io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF); 641e419bc7fSGatien Chevallier 642e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, icsr, 643e419bc7fSGatien Chevallier icsr & RTC_ICSR_RSF, 0, 644e419bc7fSGatien Chevallier TIMEOUT_US_RTC_SHADOW)) 645e419bc7fSGatien Chevallier panic(); 646e419bc7fSGatien Chevallier } 647e419bc7fSGatien Chevallier 648e419bc7fSGatien Chevallier /* 649e419bc7fSGatien Chevallier * In our RTC we start : 650e419bc7fSGatien Chevallier * - year at 0 651e419bc7fSGatien Chevallier * - month at 1 652e419bc7fSGatien Chevallier * - day at 1 653e419bc7fSGatien Chevallier * - weekday at Monday = 1 654e419bc7fSGatien Chevallier * Change month value so it becomes 0=January, 1 = February, ... 655e419bc7fSGatien Chevallier * Change week day value so it becomes 0=Sunday, 1 = Monday, ... 656e419bc7fSGatien Chevallier */ 657e419bc7fSGatien Chevallier 658e419bc7fSGatien Chevallier ssr = io_read32(base + RTC_SSR); 659e419bc7fSGatien Chevallier tr = io_read32(base + RTC_TR); 660e419bc7fSGatien Chevallier dr = io_read32(base + RTC_DR); 661e419bc7fSGatien Chevallier 662d60c61e1SGatien Chevallier stm32_rtc_to_tm(ssr, tr, dr, tm); 663e419bc7fSGatien Chevallier 664e419bc7fSGatien Chevallier return TEE_SUCCESS; 665e419bc7fSGatien Chevallier } 666e419bc7fSGatien Chevallier 667e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_set_time(struct rtc *rtc, struct optee_rtc_time *tm) 668e419bc7fSGatien Chevallier { 669e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 670e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 671e419bc7fSGatien Chevallier uint32_t tr = 0; 672e419bc7fSGatien Chevallier uint32_t dr = 0; 673e419bc7fSGatien Chevallier 674e419bc7fSGatien Chevallier /* 675e419bc7fSGatien Chevallier * In our RTC we start : 676e419bc7fSGatien Chevallier * - year at 0 677e419bc7fSGatien Chevallier * - month at 1 678e419bc7fSGatien Chevallier * - day at 1 679e419bc7fSGatien Chevallier * - weekday at Monday = 1 680e419bc7fSGatien Chevallier * Change month value so it becomes 1=January, 2 = February, ... 681e419bc7fSGatien Chevallier * Change week day value so it becomes 7=Sunday, 1 = Monday, ... 682e419bc7fSGatien Chevallier */ 683e419bc7fSGatien Chevallier tr = ((tm->tm_sec % 10) & RTC_TR_SU_MASK) | 684e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_sec / 10, RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) | 685e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_min % 10, RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK) | 686e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_min / 10, RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) | 687e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_hour % 10, RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK) | 688e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_hour / 10, RTC_TR_HT_SHIFT) & RTC_TR_HT_MASK); 689e419bc7fSGatien Chevallier 690e419bc7fSGatien Chevallier dr = ((tm->tm_mday % 10) & RTC_DR_DU_MASK) | 691e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_mday / 10, RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) | 692e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_mon + 1) % 10, RTC_DR_MU_SHIFT) & 693e419bc7fSGatien Chevallier RTC_DR_MU_MASK) | 694e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_mon + 1) / 10, RTC_DR_MT_SHIFT) & 695e419bc7fSGatien Chevallier RTC_DR_MT_MASK) | 696e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_wday ? tm->tm_wday : 7, RTC_DR_WDU_SHIFT) & 697e419bc7fSGatien Chevallier RTC_DR_WDU_MASK) | 698e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) % 10, 699e419bc7fSGatien Chevallier RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK) | 700e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) / 10, 701e419bc7fSGatien Chevallier RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK); 702e419bc7fSGatien Chevallier 703e419bc7fSGatien Chevallier stm32_rtc_write_unprotect(); 704e419bc7fSGatien Chevallier 705e419bc7fSGatien Chevallier res = stm32_rtc_enter_init_mode(); 706e419bc7fSGatien Chevallier if (res) 707e419bc7fSGatien Chevallier goto end; 708e419bc7fSGatien Chevallier 709e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_TR, tr); 710e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_DR, dr); 711e419bc7fSGatien Chevallier 712446da993SClément Le Goffic res = stm32_rtc_exit_init_mode(); 713e419bc7fSGatien Chevallier end: 714e419bc7fSGatien Chevallier stm32_rtc_write_protect(); 715e419bc7fSGatien Chevallier 716e419bc7fSGatien Chevallier return res; 717e419bc7fSGatien Chevallier } 718e419bc7fSGatien Chevallier 719d60c61e1SGatien Chevallier TEE_Result stm32_rtc_get_timestamp(struct optee_rtc_time *tm) 720d60c61e1SGatien Chevallier { 721d60c61e1SGatien Chevallier vaddr_t base = get_base(); 722d60c61e1SGatien Chevallier uint32_t exceptions = 0; 723d60c61e1SGatien Chevallier uint32_t value = 0; 724d60c61e1SGatien Chevallier uint32_t ssr = 0; 725d60c61e1SGatien Chevallier uint32_t dr = 0; 726d60c61e1SGatien Chevallier uint32_t tr = 0; 727d60c61e1SGatien Chevallier 728d60c61e1SGatien Chevallier exceptions = cpu_spin_lock_xsave(&rtc_dev.ts_lock); 729d60c61e1SGatien Chevallier 730d60c61e1SGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_SR, value, 731d60c61e1SGatien Chevallier value & RTC_SR_TSF, 732d60c61e1SGatien Chevallier 10, TIMEOUT_US_RTC_GENERIC)) { 733d60c61e1SGatien Chevallier cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions); 734d60c61e1SGatien Chevallier return TEE_ERROR_NO_DATA; 735d60c61e1SGatien Chevallier } 736d60c61e1SGatien Chevallier 737d60c61e1SGatien Chevallier ssr = io_read32(base + RTC_TSSSR); 738d60c61e1SGatien Chevallier tr = io_read32(base + RTC_TSTR); 739d60c61e1SGatien Chevallier dr = io_read32(base + RTC_TSDR); 740d60c61e1SGatien Chevallier 741d60c61e1SGatien Chevallier io_setbits32(base + RTC_SCR, RTC_SCR_CTSF); 742d60c61e1SGatien Chevallier 743d60c61e1SGatien Chevallier /* Tamper event overflow detection */ 744d60c61e1SGatien Chevallier if (io_read32(base + RTC_SR) & RTC_SR_TSOVF) { 745d60c61e1SGatien Chevallier io_setbits32(base + RTC_SCR, RTC_SCR_CTSOVF); 746d60c61e1SGatien Chevallier DMSG("A timestamp event occurred while handling current event"); 747d60c61e1SGatien Chevallier } 748d60c61e1SGatien Chevallier 749d60c61e1SGatien Chevallier cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions); 750d60c61e1SGatien Chevallier 751d60c61e1SGatien Chevallier stm32_rtc_to_tm(ssr, tr, dr, tm); 752d60c61e1SGatien Chevallier 753d60c61e1SGatien Chevallier /* No year timestamp available */ 754d60c61e1SGatien Chevallier tm->tm_year = 0; 755d60c61e1SGatien Chevallier 756d60c61e1SGatien Chevallier return TEE_SUCCESS; 757d60c61e1SGatien Chevallier } 758d60c61e1SGatien Chevallier 759d60c61e1SGatien Chevallier TEE_Result stm32_rtc_set_tamper_timestamp(void) 760d60c61e1SGatien Chevallier { 761d60c61e1SGatien Chevallier vaddr_t base = get_base(); 762d60c61e1SGatien Chevallier 763d60c61e1SGatien Chevallier stm32_rtc_write_unprotect(); 764d60c61e1SGatien Chevallier 765d60c61e1SGatien Chevallier /* Secure Timestamp bit */ 766d60c61e1SGatien Chevallier if (!rtc_dev.compat->has_seccfgr) { 767d60c61e1SGatien Chevallier /* Inverted logic */ 768d60c61e1SGatien Chevallier io_clrbits32(base + RTC_SMCR, RTC_SMCR_TS_DPROT); 769d60c61e1SGatien Chevallier } else { 770d60c61e1SGatien Chevallier io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_TS_SEC); 771d60c61e1SGatien Chevallier } 772d60c61e1SGatien Chevallier 773d60c61e1SGatien Chevallier /* Enable tamper timestamper */ 774d60c61e1SGatien Chevallier io_setbits32(base + RTC_CR, RTC_CR_TAMPTS); 775d60c61e1SGatien Chevallier 776d60c61e1SGatien Chevallier stm32_rtc_write_protect(); 777d60c61e1SGatien Chevallier 778d60c61e1SGatien Chevallier return TEE_SUCCESS; 779d60c61e1SGatien Chevallier } 780d60c61e1SGatien Chevallier 781d60c61e1SGatien Chevallier TEE_Result stm32_rtc_is_timestamp_enabled(bool *ret) 782d60c61e1SGatien Chevallier { 783d60c61e1SGatien Chevallier *ret = io_read32(get_base() + RTC_CR) & RTC_CR_TAMPTS; 784d60c61e1SGatien Chevallier 785d60c61e1SGatien Chevallier return TEE_SUCCESS; 786d60c61e1SGatien Chevallier } 787d60c61e1SGatien Chevallier 788d60c61e1SGatien Chevallier TEE_Result stm32_rtc_driver_is_initialized(void) 789d60c61e1SGatien Chevallier { 790d60c61e1SGatien Chevallier if (rtc_dev.pclk) 791d60c61e1SGatien Chevallier return TEE_SUCCESS; 792d60c61e1SGatien Chevallier 793d60c61e1SGatien Chevallier return TEE_ERROR_DEFER_DRIVER_INIT; 794d60c61e1SGatien Chevallier } 795d60c61e1SGatien Chevallier 7967818ae9bSClément Le Goffic static TEE_Result stm32_rtc_read_alarm(struct rtc *rtc, 7977818ae9bSClément Le Goffic struct optee_rtc_alarm *alarm) 7987818ae9bSClément Le Goffic { 7997818ae9bSClément Le Goffic struct optee_rtc_time *alarm_tm = NULL; 8007818ae9bSClément Le Goffic struct optee_rtc_time current_tm = { }; 8017818ae9bSClément Le Goffic TEE_Result res = TEE_ERROR_GENERIC; 8027818ae9bSClément Le Goffic vaddr_t rtc_base = get_base(); 8037818ae9bSClément Le Goffic uint32_t alrmar = io_read32(rtc_base + RTC_ALRMAR); 8047818ae9bSClément Le Goffic uint32_t cr = io_read32(rtc_base + RTC_CR); 8057818ae9bSClément Le Goffic uint32_t status = io_read32(rtc_base + RTC_SR); 8067818ae9bSClément Le Goffic 8077818ae9bSClément Le Goffic alarm_tm = &alarm->time; 8087818ae9bSClément Le Goffic 8097818ae9bSClément Le Goffic res = stm32_rtc_get_time(rtc, ¤t_tm); 8107818ae9bSClément Le Goffic if (res) 8117818ae9bSClément Le Goffic return res; 8127818ae9bSClément Le Goffic 8137818ae9bSClément Le Goffic alarm_tm->tm_year = current_tm.tm_year; 8147818ae9bSClément Le Goffic alarm_tm->tm_mon = current_tm.tm_mon; 8157818ae9bSClément Le Goffic alarm_tm->tm_mday = ((alrmar & RTC_ALRMXR_DATE_UNITS_MASK) >> 8167818ae9bSClément Le Goffic RTC_ALRMXR_DATE_UNITS_SHIFT) + 8177818ae9bSClément Le Goffic ((alrmar & RTC_ALRMXR_DATE_TENS_MASK) >> 8187818ae9bSClément Le Goffic RTC_ALRMXR_DATE_TENS_SHIFT) * 10; 8197818ae9bSClément Le Goffic alarm_tm->tm_hour = ((alrmar & RTC_ALRMXR_HOUR_UNITS_MASK) >> 8207818ae9bSClément Le Goffic RTC_ALRMXR_HOUR_UNITS_SHIFT) + 8217818ae9bSClément Le Goffic ((alrmar & RTC_ALRMXR_HOUR_TENS_MASK) >> 8227818ae9bSClément Le Goffic RTC_ALRMXR_HOUR_TENS_SHIFT) * 10; 8237818ae9bSClément Le Goffic alarm_tm->tm_min = ((alrmar & RTC_ALRMXR_MIN_UNITS_MASK) >> 8247818ae9bSClément Le Goffic RTC_ALRMXR_MIN_UNITS_SHIFT) + 8257818ae9bSClément Le Goffic ((alrmar & RTC_ALRMXR_MIN_TENS_MASK) >> 8267818ae9bSClément Le Goffic RTC_ALRMXR_MIN_TENS_SHIFT) * 10; 8277818ae9bSClément Le Goffic alarm_tm->tm_sec = ((alrmar & RTC_ALRMXR_MIN_UNITS_MASK) >> 8287818ae9bSClément Le Goffic RTC_ALRMXR_MIN_UNITS_SHIFT) + 8297818ae9bSClément Le Goffic ((alrmar & RTC_ALRMXR_MIN_TENS_MASK) >> 8307818ae9bSClément Le Goffic RTC_ALRMXR_MIN_TENS_SHIFT) * 10; 8317818ae9bSClément Le Goffic 8327818ae9bSClément Le Goffic if (rtc_timecmp(alarm_tm, ¤t_tm) < 0) { 8337818ae9bSClément Le Goffic if (current_tm.tm_mon == 11) { 8347818ae9bSClément Le Goffic alarm_tm->tm_mon = 0; 8357818ae9bSClément Le Goffic alarm_tm->tm_year += 1; 8367818ae9bSClément Le Goffic } else { 8377818ae9bSClément Le Goffic alarm_tm->tm_mon += 1; 8387818ae9bSClément Le Goffic } 8397818ae9bSClément Le Goffic } 8407818ae9bSClément Le Goffic 8417818ae9bSClément Le Goffic alarm->enabled = cr & RTC_CR_ALRAE; 8427818ae9bSClément Le Goffic alarm->pending = status & RTC_SR_ALRAF; 8437818ae9bSClément Le Goffic 8447818ae9bSClément Le Goffic return TEE_SUCCESS; 8457818ae9bSClément Le Goffic } 8467818ae9bSClément Le Goffic 8477818ae9bSClément Le Goffic static TEE_Result stm32_rtc_enable_alarm(struct rtc *rtc __unused, bool enabled) 8487818ae9bSClément Le Goffic { 8497818ae9bSClément Le Goffic vaddr_t rtc_base = get_base(); 8507818ae9bSClément Le Goffic 8517818ae9bSClément Le Goffic stm32_rtc_write_unprotect(); 8527818ae9bSClément Le Goffic 8537818ae9bSClément Le Goffic if (enabled) 8547818ae9bSClément Le Goffic io_setbits32(rtc_base + RTC_CR, RTC_CR_ALRAIE | RTC_CR_ALRAE); 8557818ae9bSClément Le Goffic else 8567818ae9bSClément Le Goffic io_clrbits32(rtc_base + RTC_CR, RTC_CR_ALRAIE | RTC_CR_ALRAE); 8577818ae9bSClément Le Goffic 8587818ae9bSClément Le Goffic stm32_rtc_clear_events(RTC_SCR_CALRAF); 8597818ae9bSClément Le Goffic 8607818ae9bSClément Le Goffic stm32_rtc_write_protect(); 8617818ae9bSClément Le Goffic 8627818ae9bSClément Le Goffic return TEE_SUCCESS; 8637818ae9bSClément Le Goffic } 8647818ae9bSClément Le Goffic 8657818ae9bSClément Le Goffic static void stm32_rtc_add_one_month(struct optee_rtc_time *tm) 8667818ae9bSClément Le Goffic { 8677818ae9bSClément Le Goffic tm->tm_mon++; 8687818ae9bSClément Le Goffic if (tm->tm_mon > 11) { 8697818ae9bSClément Le Goffic tm->tm_mon = 0; 8707818ae9bSClément Le Goffic tm->tm_year++; 8717818ae9bSClément Le Goffic } 8727818ae9bSClément Le Goffic 8737818ae9bSClément Le Goffic /* Saturate to the next month last day */ 8747818ae9bSClément Le Goffic tm->tm_mday = MIN(tm->tm_mday, 8757818ae9bSClément Le Goffic rtc_get_month_days(tm->tm_mon, tm->tm_year)); 8767818ae9bSClément Le Goffic } 8777818ae9bSClément Le Goffic 8787818ae9bSClément Le Goffic static TEE_Result stm32_rtc_valid_alarm_time(struct rtc *rtc, 8797818ae9bSClément Le Goffic struct optee_rtc_time *tm) 8807818ae9bSClément Le Goffic { 8817818ae9bSClément Le Goffic struct optee_rtc_time current_tm = { }; 8827818ae9bSClément Le Goffic TEE_Result res = TEE_ERROR_GENERIC; 8837818ae9bSClément Le Goffic struct optee_rtc_time *max = NULL; 8847818ae9bSClément Le Goffic 8857818ae9bSClément Le Goffic /* 8867818ae9bSClément Le Goffic * Assuming current date is M-D-Y H:M:S. 8877818ae9bSClément Le Goffic * RTC alarm can't be set on a specific month and year. 8887818ae9bSClément Le Goffic * So the valid alarm range is: 8897818ae9bSClément Le Goffic * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S 8907818ae9bSClément Le Goffic */ 8917818ae9bSClément Le Goffic 8927818ae9bSClément Le Goffic res = stm32_rtc_get_time(rtc, ¤t_tm); 8937818ae9bSClément Le Goffic if (res) 8947818ae9bSClément Le Goffic return res; 8957818ae9bSClément Le Goffic 8967818ae9bSClément Le Goffic /* Don't allow alarm to be set in the past. */ 8977818ae9bSClément Le Goffic if (rtc_timecmp(¤t_tm, tm) >= 0) 8987818ae9bSClément Le Goffic return TEE_ERROR_BAD_PARAMETERS; 8997818ae9bSClément Le Goffic 9007818ae9bSClément Le Goffic max = ¤t_tm; 9017818ae9bSClément Le Goffic 9027818ae9bSClément Le Goffic stm32_rtc_add_one_month(max); 9037818ae9bSClément Le Goffic 9047818ae9bSClément Le Goffic if (rtc_timecmp(max, tm) <= 0) 9057818ae9bSClément Le Goffic return TEE_ERROR_BAD_PARAMETERS; 9067818ae9bSClément Le Goffic 9077818ae9bSClément Le Goffic return TEE_SUCCESS; 9087818ae9bSClément Le Goffic } 9097818ae9bSClément Le Goffic 9107818ae9bSClément Le Goffic static TEE_Result stm32_rtc_set_alarm(struct rtc *rtc, 9117818ae9bSClément Le Goffic struct optee_rtc_alarm *alarm) 9127818ae9bSClément Le Goffic { 9137818ae9bSClément Le Goffic struct optee_rtc_time *alarm_time = &alarm->time; 9147818ae9bSClément Le Goffic TEE_Result res = TEE_ERROR_GENERIC; 9157818ae9bSClément Le Goffic vaddr_t rtc_base = get_base(); 9167818ae9bSClément Le Goffic uint32_t alrmar = 0; 9177818ae9bSClément Le Goffic uint32_t cr = io_read32(rtc_base + RTC_CR); 9187818ae9bSClément Le Goffic uint32_t prer = io_read32(rtc_base + RTC_PRER); 9197818ae9bSClément Le Goffic uint32_t prediv_s = prer & RTC_PRER_PREDIV_S_MASK; 9207818ae9bSClément Le Goffic 9217818ae9bSClément Le Goffic /* tm_year and tm_mon are not used because not supported by RTC */ 9227818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_mday / 10) << RTC_ALRMXR_DATE_TENS_SHIFT) & 9237818ae9bSClément Le Goffic RTC_ALRMXR_DATE_TENS_MASK; 9247818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_mday % 10) << RTC_ALRMXR_DATE_UNITS_SHIFT) & 9257818ae9bSClément Le Goffic RTC_ALRMXR_DATE_UNITS_MASK; 9267818ae9bSClément Le Goffic /* 24-hour format */ 9277818ae9bSClément Le Goffic alrmar &= ~RTC_ALRMXR_PM; 9287818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_hour / 10) << RTC_ALRMXR_HOUR_TENS_SHIFT) & 9297818ae9bSClément Le Goffic RTC_ALRMXR_HOUR_TENS_MASK; 9307818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_hour % 10) << RTC_ALRMXR_HOUR_UNITS_SHIFT) & 9317818ae9bSClément Le Goffic RTC_ALRMXR_HOUR_UNITS_MASK; 9327818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_min / 10) << RTC_ALRMXR_MIN_TENS_SHIFT) & 9337818ae9bSClément Le Goffic RTC_ALRMXR_MIN_TENS_MASK; 9347818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_min % 10) << RTC_ALRMXR_MIN_UNITS_SHIFT) & 9357818ae9bSClément Le Goffic RTC_ALRMXR_MIN_UNITS_MASK; 9367818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_sec / 10) << RTC_ALRMXR_SEC_TENS_SHIFT) & 9377818ae9bSClément Le Goffic RTC_ALRMXR_SEC_TENS_MASK; 9387818ae9bSClément Le Goffic alrmar |= ((alarm_time->tm_sec % 10) << RTC_ALRMXR_SEC_UNITS_SHIFT) & 9397818ae9bSClément Le Goffic RTC_ALRMXR_SEC_UNITS_MASK; 9407818ae9bSClément Le Goffic 9417818ae9bSClément Le Goffic if ((alrmar & !RTC_ALRMXR_SEC_MASK) && prediv_s < 3) { 9427818ae9bSClément Le Goffic EMSG("RTC Alarm conditions not met"); 9437818ae9bSClément Le Goffic return TEE_ERROR_BAD_STATE; 9447818ae9bSClément Le Goffic } 9457818ae9bSClément Le Goffic 9467818ae9bSClément Le Goffic stm32_rtc_write_unprotect(); 9477818ae9bSClément Le Goffic 9487818ae9bSClément Le Goffic res = stm32_rtc_valid_alarm_time(rtc, alarm_time); 9497818ae9bSClément Le Goffic if (res) { 9507818ae9bSClément Le Goffic stm32_rtc_write_unprotect(); 9517818ae9bSClément Le Goffic return res; 9527818ae9bSClément Le Goffic } 9537818ae9bSClément Le Goffic 9547818ae9bSClément Le Goffic /* Disable Alarm */ 9557818ae9bSClément Le Goffic cr &= ~RTC_CR_ALRAE; 9567818ae9bSClément Le Goffic io_write32(rtc_base + RTC_CR, cr); 9577818ae9bSClément Le Goffic 9587818ae9bSClément Le Goffic io_write32(rtc_base + RTC_ALRMAR, alrmar); 9597818ae9bSClément Le Goffic 9607818ae9bSClément Le Goffic stm32_rtc_enable_alarm(rtc, alarm->enabled); 9617818ae9bSClément Le Goffic 9627818ae9bSClément Le Goffic stm32_rtc_write_protect(); 9637818ae9bSClément Le Goffic 9647818ae9bSClément Le Goffic return TEE_SUCCESS; 9657818ae9bSClément Le Goffic } 9667818ae9bSClément Le Goffic 9677818ae9bSClément Le Goffic static TEE_Result stm32_rtc_cancel_wait_alarm(struct rtc *rtc __unused) 9687818ae9bSClément Le Goffic { 9697818ae9bSClément Le Goffic rtc_dev.wait_alarm_return_status = RTC_WAIT_ALARM_CANCELED; 9707818ae9bSClément Le Goffic notif_send_async(rtc_dev.notif_id, 0); 9717818ae9bSClément Le Goffic 9727818ae9bSClément Le Goffic return TEE_SUCCESS; 9737818ae9bSClément Le Goffic } 9747818ae9bSClément Le Goffic 9757818ae9bSClément Le Goffic static TEE_Result 9767818ae9bSClément Le Goffic stm32_rtc_wait_alarm(struct rtc *rtc __unused, 9777818ae9bSClément Le Goffic enum rtc_wait_alarm_status *return_status) 9787818ae9bSClément Le Goffic { 9797818ae9bSClément Le Goffic TEE_Result res = TEE_ERROR_GENERIC; 9807818ae9bSClément Le Goffic 9817818ae9bSClément Le Goffic rtc_dev.wait_alarm_return_status = RTC_WAIT_ALARM_RESET; 9827818ae9bSClément Le Goffic 9837818ae9bSClément Le Goffic /* Wait until a notification arrives - blocking */ 9847818ae9bSClément Le Goffic res = notif_wait(rtc_dev.notif_id); 9857818ae9bSClément Le Goffic if (res) 9867818ae9bSClément Le Goffic return res; 9877818ae9bSClément Le Goffic 9887818ae9bSClément Le Goffic if (rtc_dev.wait_alarm_return_status == 9897818ae9bSClément Le Goffic RTC_WAIT_ALARM_CANCELED) { 9907818ae9bSClément Le Goffic *return_status = RTC_WAIT_ALARM_CANCELED; 9917818ae9bSClément Le Goffic stm32_rtc_enable_alarm(rtc, 0); 9927818ae9bSClément Le Goffic } else { 9937818ae9bSClément Le Goffic *return_status = RTC_WAIT_ALARM_ALARM_OCCURRED; 9947818ae9bSClément Le Goffic } 9957818ae9bSClément Le Goffic 9967818ae9bSClément Le Goffic return TEE_SUCCESS; 9977818ae9bSClément Le Goffic } 9987818ae9bSClément Le Goffic 999*63000677SClément Le Goffic static TEE_Result stm32_rtc_set_alarm_wakeup_status(struct rtc *rtc __unused, 1000*63000677SClément Le Goffic bool status) 1001*63000677SClément Le Goffic { 1002*63000677SClément Le Goffic if (!rtc_dev.rtc->is_wakeup_source) 1003*63000677SClément Le Goffic return TEE_ERROR_NOT_SUPPORTED; 1004*63000677SClément Le Goffic 1005*63000677SClément Le Goffic interrupt_set_wake(rtc_dev.itr_chip, rtc_dev.itr_num, status); 1006*63000677SClément Le Goffic 1007*63000677SClément Le Goffic return TEE_SUCCESS; 1008*63000677SClément Le Goffic } 1009*63000677SClément Le Goffic 1010e419bc7fSGatien Chevallier static const struct rtc_ops stm32_rtc_ops = { 1011e419bc7fSGatien Chevallier .get_time = stm32_rtc_get_time, 1012e419bc7fSGatien Chevallier .set_time = stm32_rtc_set_time, 10137818ae9bSClément Le Goffic .read_alarm = stm32_rtc_read_alarm, 10147818ae9bSClément Le Goffic .set_alarm = stm32_rtc_set_alarm, 10157818ae9bSClément Le Goffic .enable_alarm = stm32_rtc_enable_alarm, 10167818ae9bSClément Le Goffic .wait_alarm = stm32_rtc_wait_alarm, 10177818ae9bSClément Le Goffic .cancel_wait = stm32_rtc_cancel_wait_alarm, 1018*63000677SClément Le Goffic .set_alarm_wakeup_status = stm32_rtc_set_alarm_wakeup_status, 1019e419bc7fSGatien Chevallier }; 1020e419bc7fSGatien Chevallier 1021e419bc7fSGatien Chevallier static struct rtc stm32_rtc = { 1022e419bc7fSGatien Chevallier .ops = &stm32_rtc_ops, 1023e419bc7fSGatien Chevallier .range_min = RTC_TIME(YEAR_REF, 0, 1, 0, 0, 0, 0, 0), 1024e419bc7fSGatien Chevallier .range_max = RTC_TIME(YEAR_MAX, 11, 31, 4, 23, 59, 59, 999), 1025e419bc7fSGatien Chevallier }; 1026e419bc7fSGatien Chevallier 1027e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_probe(const void *fdt, int node, 1028e419bc7fSGatien Chevallier const void *compat_data) 1029e419bc7fSGatien Chevallier { 1030e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 1031e419bc7fSGatien Chevallier bool is_tdcid = false; 1032e419bc7fSGatien Chevallier 1033e419bc7fSGatien Chevallier rtc_dev.compat = compat_data; 1034*63000677SClément Le Goffic rtc_dev.rtc = &stm32_rtc; 1035e419bc7fSGatien Chevallier 1036e419bc7fSGatien Chevallier if (rtc_dev.compat->has_rif_support) { 1037e419bc7fSGatien Chevallier res = stm32_rifsc_check_tdcid(&is_tdcid); 1038e419bc7fSGatien Chevallier if (res) 1039e419bc7fSGatien Chevallier return res; 1040e419bc7fSGatien Chevallier } 1041e419bc7fSGatien Chevallier 1042e419bc7fSGatien Chevallier res = parse_dt(fdt, node); 1043e419bc7fSGatien Chevallier if (res) { 1044e419bc7fSGatien Chevallier memset(&rtc_dev, 0, sizeof(rtc_dev)); 1045e419bc7fSGatien Chevallier return res; 1046e419bc7fSGatien Chevallier } 1047e419bc7fSGatien Chevallier 1048e419bc7fSGatien Chevallier /* Unbalanced clock enable to ensure RTC core clock is always on */ 1049e419bc7fSGatien Chevallier res = clk_enable(rtc_dev.rtc_ck); 1050e419bc7fSGatien Chevallier if (res) 1051e419bc7fSGatien Chevallier panic("Couldn't enable RTC clock"); 1052e419bc7fSGatien Chevallier 1053e419bc7fSGatien Chevallier if (clk_get_rate(rtc_dev.pclk) < (clk_get_rate(rtc_dev.rtc_ck) * 7)) 1054e419bc7fSGatien Chevallier rtc_dev.flags |= RTC_FLAGS_READ_TWICE; 1055e419bc7fSGatien Chevallier 1056e419bc7fSGatien Chevallier if (rtc_dev.compat->has_rif_support) { 1057e419bc7fSGatien Chevallier res = clk_enable(rtc_dev.pclk); 1058e419bc7fSGatien Chevallier if (res) 1059e419bc7fSGatien Chevallier panic("Could not enable RTC bus clock"); 1060e419bc7fSGatien Chevallier 1061e419bc7fSGatien Chevallier apply_rif_config(is_tdcid); 1062e419bc7fSGatien Chevallier 1063e419bc7fSGatien Chevallier /* 1064e419bc7fSGatien Chevallier * Verify if applied RIF config will not disable 1065e419bc7fSGatien Chevallier * other functionalities of this driver. 1066e419bc7fSGatien Chevallier */ 1067e419bc7fSGatien Chevallier res = check_rif_config(); 1068e419bc7fSGatien Chevallier if (res) 1069e419bc7fSGatien Chevallier panic("Incompatible RTC RIF configuration"); 1070e419bc7fSGatien Chevallier 1071e419bc7fSGatien Chevallier clk_disable(rtc_dev.pclk); 1072e419bc7fSGatien Chevallier } 1073e419bc7fSGatien Chevallier 1074446da993SClément Le Goffic res = stm32_rtc_init(); 1075446da993SClément Le Goffic if (res) 1076446da993SClément Le Goffic return res; 10777818ae9bSClément Le Goffic 1078e419bc7fSGatien Chevallier rtc_register(&stm32_rtc); 1079e419bc7fSGatien Chevallier 10807818ae9bSClément Le Goffic if (IS_ENABLED(CFG_RTC_PTA) && IS_ENABLED(CFG_CORE_ASYNC_NOTIF) && 1081*63000677SClément Le Goffic rtc_dev.is_secured && rtc_dev.itr_chip) { 10827818ae9bSClément Le Goffic res = notif_alloc_async_value(&rtc_dev.notif_id); 10837818ae9bSClément Le Goffic if (res) 1084e419bc7fSGatien Chevallier return res; 10857818ae9bSClément Le Goffic 1086*63000677SClément Le Goffic res = interrupt_create_handler(rtc_dev.itr_chip, 1087*63000677SClément Le Goffic rtc_dev.itr_num, 1088*63000677SClément Le Goffic stm32_rtc_it_handler, 1089*63000677SClément Le Goffic &rtc_dev, 0, 1090*63000677SClément Le Goffic &rtc_dev.itr_handler); 1091*63000677SClément Le Goffic if (res) 1092*63000677SClément Le Goffic goto out_rtc_secured_and_itr_chip; 1093*63000677SClément Le Goffic 10947818ae9bSClément Le Goffic /* Unbalanced clock enable to ensure IRQ interface is alive */ 10957818ae9bSClément Le Goffic res = clk_enable(rtc_dev.pclk); 10967818ae9bSClément Le Goffic if (res) 1097*63000677SClément Le Goffic goto out_rtc_secured_and_itr_chip; 10987818ae9bSClément Le Goffic 10997818ae9bSClément Le Goffic interrupt_enable(rtc_dev.itr_chip, rtc_dev.itr_num); 11007818ae9bSClément Le Goffic 11017818ae9bSClément Le Goffic return TEE_SUCCESS; 11027818ae9bSClément Le Goffic 1103*63000677SClément Le Goffic out_rtc_secured_and_itr_chip: 1104*63000677SClément Le Goffic interrupt_remove_handler(rtc_dev.itr_handler); 11057818ae9bSClément Le Goffic notif_free_async_value(rtc_dev.notif_id); 11067818ae9bSClément Le Goffic return res; 11077818ae9bSClément Le Goffic } 11087818ae9bSClément Le Goffic 11097818ae9bSClément Le Goffic return TEE_SUCCESS; 1110e419bc7fSGatien Chevallier } 1111e419bc7fSGatien Chevallier 1112e419bc7fSGatien Chevallier static const struct rtc_compat mp25_compat = { 1113e419bc7fSGatien Chevallier .has_seccfgr = true, 1114e419bc7fSGatien Chevallier .has_rif_support = true, 1115e419bc7fSGatien Chevallier }; 1116e419bc7fSGatien Chevallier 1117e419bc7fSGatien Chevallier static const struct rtc_compat mp15_compat = { 1118e419bc7fSGatien Chevallier .has_seccfgr = false, 1119e419bc7fSGatien Chevallier .has_rif_support = false, 1120e419bc7fSGatien Chevallier }; 1121e419bc7fSGatien Chevallier 1122e419bc7fSGatien Chevallier static const struct rtc_compat mp13_compat = { 1123e419bc7fSGatien Chevallier .has_seccfgr = true, 1124e419bc7fSGatien Chevallier .has_rif_support = false, 1125e419bc7fSGatien Chevallier }; 1126e419bc7fSGatien Chevallier 1127e419bc7fSGatien Chevallier static const struct dt_device_match stm32_rtc_match_table[] = { 1128e419bc7fSGatien Chevallier { 1129e419bc7fSGatien Chevallier .compatible = "st,stm32mp25-rtc", 1130e419bc7fSGatien Chevallier .compat_data = &mp25_compat, 1131e419bc7fSGatien Chevallier }, 1132e419bc7fSGatien Chevallier { 1133e419bc7fSGatien Chevallier .compatible = "st,stm32mp1-rtc", 1134e419bc7fSGatien Chevallier .compat_data = &mp15_compat, 1135e419bc7fSGatien Chevallier }, 1136e419bc7fSGatien Chevallier { 1137e419bc7fSGatien Chevallier .compatible = "st,stm32mp13-rtc", 1138e419bc7fSGatien Chevallier .compat_data = &mp13_compat, 1139e419bc7fSGatien Chevallier }, 1140e419bc7fSGatien Chevallier { } 1141e419bc7fSGatien Chevallier }; 1142e419bc7fSGatien Chevallier 1143e419bc7fSGatien Chevallier DEFINE_DT_DRIVER(stm32_rtc_dt_driver) = { 1144e419bc7fSGatien Chevallier .name = "stm32-rtc", 1145e419bc7fSGatien Chevallier .match_table = stm32_rtc_match_table, 1146e419bc7fSGatien Chevallier .probe = stm32_rtc_probe, 1147e419bc7fSGatien Chevallier }; 1148