1e419bc7fSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause 2e419bc7fSGatien Chevallier /* 3*d60c61e1SGatien 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> 9e419bc7fSGatien Chevallier #include <drivers/stm32_rif.h> 10*d60c61e1SGatien Chevallier #include <drivers/stm32_rtc.h> 11e419bc7fSGatien Chevallier #include <io.h> 12e419bc7fSGatien Chevallier #include <kernel/dt.h> 13e419bc7fSGatien Chevallier #include <kernel/dt_driver.h> 14e419bc7fSGatien Chevallier #include <kernel/panic.h> 15*d60c61e1SGatien Chevallier #include <kernel/spinlock.h> 16e419bc7fSGatien Chevallier #include <libfdt.h> 17e419bc7fSGatien Chevallier #include <mm/core_memprot.h> 18e419bc7fSGatien Chevallier 19e419bc7fSGatien Chevallier /* 20e419bc7fSGatien Chevallier * Registers 21e419bc7fSGatien Chevallier */ 22e419bc7fSGatien Chevallier #define RTC_TR U(0x00) 23e419bc7fSGatien Chevallier #define RTC_DR U(0x04) 24e419bc7fSGatien Chevallier #define RTC_SSR U(0x08) 25e419bc7fSGatien Chevallier #define RTC_ICSR U(0x0C) 26e419bc7fSGatien Chevallier #define RTC_PRER U(0x10) 27e419bc7fSGatien Chevallier #define RTC_WUTR U(0x14) 28e419bc7fSGatien Chevallier #define RTC_CR U(0x18) 29e419bc7fSGatien Chevallier #define RTC_PRIVCFGR U(0x1C) 30e419bc7fSGatien Chevallier /* RTC_SMCR is linked to RTC3v1_2 */ 31e419bc7fSGatien Chevallier #define RTC_SMCR U(0x20) 32e419bc7fSGatien Chevallier /* RTC_SECCFGR is linked to RTC3v3_2 and above */ 33e419bc7fSGatien Chevallier #define RTC_SECCFGR U(0x20) 34e419bc7fSGatien Chevallier #define RTC_WPR U(0x24) 35e419bc7fSGatien Chevallier #define RTC_CALR U(0x28) 36e419bc7fSGatien Chevallier #define RTC_SHIFTR U(0x2C) 37e419bc7fSGatien Chevallier #define RTC_TSTR U(0x30) 38e419bc7fSGatien Chevallier #define RTC_TSDR U(0x34) 39e419bc7fSGatien Chevallier #define RTC_TSSSR U(0x38) 40e419bc7fSGatien Chevallier #define RTC_ALRMAR U(0x40) 41e419bc7fSGatien Chevallier #define RTC_ALRMASSR U(0x44) 42e419bc7fSGatien Chevallier #define RTC_ALRMBR U(0x48) 43e419bc7fSGatien Chevallier #define RTC_ALRMBSSR U(0x4C) 44e419bc7fSGatien Chevallier #define RTC_SR U(0x50) 45e419bc7fSGatien Chevallier #define RTC_SCR U(0x5C) 46e419bc7fSGatien Chevallier #define RTC_OR U(0x60) 47e419bc7fSGatien Chevallier #define RTC_CIDCFGR(x) (U(0x80) + U(0x4) * (x)) 48e419bc7fSGatien Chevallier 49e419bc7fSGatien Chevallier #define RTC_TR_SU_MASK GENMASK_32(3, 0) 50e419bc7fSGatien Chevallier #define RTC_TR_ST_MASK GENMASK_32(6, 4) 51e419bc7fSGatien Chevallier #define RTC_TR_ST_SHIFT U(4) 52e419bc7fSGatien Chevallier #define RTC_TR_MNU_MASK GENMASK_32(11, 8) 53e419bc7fSGatien Chevallier #define RTC_TR_MNU_SHIFT U(8) 54e419bc7fSGatien Chevallier #define RTC_TR_MNT_MASK GENMASK_32(14, 12) 55e419bc7fSGatien Chevallier #define RTC_TR_MNT_SHIFT U(12) 56e419bc7fSGatien Chevallier #define RTC_TR_HU_MASK GENMASK_32(19, 16) 57e419bc7fSGatien Chevallier #define RTC_TR_HU_SHIFT U(16) 58e419bc7fSGatien Chevallier #define RTC_TR_HT_MASK GENMASK_32(21, 20) 59e419bc7fSGatien Chevallier #define RTC_TR_HT_SHIFT U(20) 60e419bc7fSGatien Chevallier #define RTC_TR_PM BIT(22) 61e419bc7fSGatien Chevallier 62e419bc7fSGatien Chevallier #define RTC_DR_DU_MASK GENMASK_32(3, 0) 63e419bc7fSGatien Chevallier #define RTC_DR_DT_MASK GENMASK_32(5, 4) 64e419bc7fSGatien Chevallier #define RTC_DR_DT_SHIFT U(4) 65e419bc7fSGatien Chevallier #define RTC_DR_MU_MASK GENMASK_32(11, 8) 66e419bc7fSGatien Chevallier #define RTC_DR_MU_SHIFT U(8) 67e419bc7fSGatien Chevallier #define RTC_DR_MT_MASK BIT(12) 68e419bc7fSGatien Chevallier #define RTC_DR_MT_SHIFT U(12) 69e419bc7fSGatien Chevallier #define RTC_DR_WDU_MASK GENMASK_32(15, 13) 70e419bc7fSGatien Chevallier #define RTC_DR_WDU_SHIFT U(13) 71e419bc7fSGatien Chevallier #define RTC_DR_YU_MASK GENMASK_32(19, 16) 72e419bc7fSGatien Chevallier #define RTC_DR_YU_SHIFT U(16) 73e419bc7fSGatien Chevallier #define RTC_DR_YT_MASK GENMASK_32(23, 20) 74e419bc7fSGatien Chevallier #define RTC_DR_YT_SHIFT U(20) 75e419bc7fSGatien Chevallier 76e419bc7fSGatien Chevallier #define RTC_SSR_SS_MASK GENMASK_32(15, 0) 77e419bc7fSGatien Chevallier 78e419bc7fSGatien Chevallier #define RTC_ICSR_RSF BIT(5) 79e419bc7fSGatien Chevallier #define RTC_ICSR_INITF BIT(6) 80e419bc7fSGatien Chevallier #define RTC_ICSR_INIT BIT(7) 81e419bc7fSGatien Chevallier 82e419bc7fSGatien Chevallier #define RTC_PRER_PREDIV_S_MASK GENMASK_32(14, 0) 83e419bc7fSGatien Chevallier 84e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD BIT(5) 85e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD_SHIFT U(5) 86e419bc7fSGatien Chevallier #define RTC_CR_TAMPTS BIT(25) 87e419bc7fSGatien Chevallier 88e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES GENMASK_32(3, 0) 89e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES_TO_SHIFT GENMASK_32(5, 4) 90e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_SHIFT U(9) 91e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_MASK (GENMASK_32(14, 13) | GENMASK_32(3, 0)) 92e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_FULL_PRIV BIT(15) 93e419bc7fSGatien Chevallier 94e419bc7fSGatien Chevallier #define RTC_SMCR_TS_DPROT BIT(3) 95e419bc7fSGatien Chevallier 96e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES GENMASK_32(3, 0) 97e419bc7fSGatien Chevallier #define RTC_SECCFGR_TS_SEC BIT(3) 98e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES_TO_SHIFT GENMASK_32(5, 4) 99e419bc7fSGatien Chevallier #define RTC_SECCFGR_SHIFT U(9) 100e419bc7fSGatien Chevallier #define RTC_SECCFGR_MASK (GENMASK_32(14, 13) | GENMASK_32(3, 0)) 101e419bc7fSGatien Chevallier #define RTC_SECCFGR_FULL_SEC BIT(15) 102e419bc7fSGatien Chevallier 103e419bc7fSGatien Chevallier #define RTC_WPR_KEY1 U(0xCA) 104e419bc7fSGatien Chevallier #define RTC_WPR_KEY2 U(0x53) 105e419bc7fSGatien Chevallier #define RTC_WPR_KEY_LOCK U(0xFF) 106e419bc7fSGatien Chevallier 107e419bc7fSGatien Chevallier #define RTC_TSDR_MU_MASK GENMASK_32(11, 8) 108e419bc7fSGatien Chevallier #define RTC_TSDR_MU_SHIFT U(8) 109e419bc7fSGatien Chevallier #define RTC_TSDR_DT_MASK GENMASK_32(5, 4) 110e419bc7fSGatien Chevallier #define RTC_TSDR_DT_SHIFT U(4) 111e419bc7fSGatien Chevallier #define RTC_TSDR_DU_MASK GENMASK_32(3, 0) 112e419bc7fSGatien Chevallier #define RTC_TSDR_DU_SHIFT U(0) 113e419bc7fSGatien Chevallier 114e419bc7fSGatien Chevallier #define RTC_SR_TSF BIT(3) 115e419bc7fSGatien Chevallier #define RTC_SR_TSOVF BIT(4) 116e419bc7fSGatien Chevallier 117e419bc7fSGatien Chevallier #define RTC_SCR_CTSF BIT(3) 118e419bc7fSGatien Chevallier #define RTC_SCR_CTSOVF BIT(4) 119e419bc7fSGatien Chevallier 120e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK GENMASK_32(6, 4) 121e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK_SHIFT U(4) 122e419bc7fSGatien Chevallier #define RTC_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | \ 123e419bc7fSGatien Chevallier RTC_CIDCFGR_SCID_MASK) 124e419bc7fSGatien Chevallier 125e419bc7fSGatien Chevallier /* 126e419bc7fSGatien Chevallier * RIF miscellaneous 127e419bc7fSGatien Chevallier */ 128e419bc7fSGatien Chevallier #define RTC_NB_RIF_RESOURCES U(6) 129e419bc7fSGatien Chevallier 130e419bc7fSGatien Chevallier #define RTC_RIF_FULL_PRIVILEGED U(0x3F) 131e419bc7fSGatien Chevallier #define RTC_RIF_FULL_SECURED U(0x3F) 132e419bc7fSGatien Chevallier 133e419bc7fSGatien Chevallier #define RTC_NB_MAX_CID_SUPPORTED U(7) 134e419bc7fSGatien Chevallier 135e419bc7fSGatien Chevallier /* 136e419bc7fSGatien Chevallier * Driver miscellaneous 137e419bc7fSGatien Chevallier */ 138e419bc7fSGatien Chevallier #define RTC_RES_TIMESTAMP U(3) 139e419bc7fSGatien Chevallier #define RTC_RES_CALIBRATION U(4) 140e419bc7fSGatien Chevallier #define RTC_RES_INITIALIZATION U(5) 141e419bc7fSGatien Chevallier 142e419bc7fSGatien Chevallier #define RTC_FLAGS_READ_TWICE BIT(0) 143e419bc7fSGatien Chevallier 144e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_SHADOW U(10000) 145e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_GENERIC U(100000) 146e419bc7fSGatien Chevallier 147e419bc7fSGatien Chevallier #define YEAR_REF ULL(2000) 148e419bc7fSGatien Chevallier #define YEAR_MAX (YEAR_REF + ULL(99)) 149e419bc7fSGatien Chevallier 150e419bc7fSGatien Chevallier struct rtc_compat { 151e419bc7fSGatien Chevallier bool has_seccfgr; 152e419bc7fSGatien Chevallier bool has_rif_support; 153e419bc7fSGatien Chevallier }; 154e419bc7fSGatien Chevallier 155e419bc7fSGatien Chevallier /* 156e419bc7fSGatien Chevallier * struct rtc_device - RTC device data 157e419bc7fSGatien Chevallier * @base: RTC IOMEM base address 158e419bc7fSGatien Chevallier * @compat: RTC compatible data 159e419bc7fSGatien Chevallier * @pclk: RTC bus clock 160e419bc7fSGatien Chevallier * @rtc_ck: RTC kernel clock 161e419bc7fSGatien Chevallier * @conf_data: RTC RIF configuration data, when supported 162e419bc7fSGatien Chevallier * @nb_res: Number of protectible RTC resources 163*d60c61e1SGatien Chevallier * @ts_lock: Lock used for time stamping events handling 164e419bc7fSGatien Chevallier * @flags: RTC driver flags 165e419bc7fSGatien Chevallier * @is_secured: True if the RTC is fully secured 166e419bc7fSGatien Chevallier */ 167e419bc7fSGatien Chevallier struct rtc_device { 168e419bc7fSGatien Chevallier struct io_pa_va base; 169e419bc7fSGatien Chevallier const struct rtc_compat *compat; 170e419bc7fSGatien Chevallier struct clk *pclk; 171e419bc7fSGatien Chevallier struct clk *rtc_ck; 172e419bc7fSGatien Chevallier struct rif_conf_data *conf_data; 173e419bc7fSGatien Chevallier unsigned int nb_res; 174*d60c61e1SGatien Chevallier unsigned int ts_lock; 175e419bc7fSGatien Chevallier uint8_t flags; 176e419bc7fSGatien Chevallier bool is_secured; 177e419bc7fSGatien Chevallier }; 178e419bc7fSGatien Chevallier 179e419bc7fSGatien Chevallier /* Expect a single RTC instance */ 180e419bc7fSGatien Chevallier static struct rtc_device rtc_dev; 181e419bc7fSGatien Chevallier 182e419bc7fSGatien Chevallier static vaddr_t get_base(void) 183e419bc7fSGatien Chevallier { 184e419bc7fSGatien Chevallier assert(rtc_dev.base.pa); 185e419bc7fSGatien Chevallier 186e419bc7fSGatien Chevallier return io_pa_or_va(&rtc_dev.base, 1); 187e419bc7fSGatien Chevallier } 188e419bc7fSGatien Chevallier 189e419bc7fSGatien Chevallier static void stm32_rtc_write_unprotect(void) 190e419bc7fSGatien Chevallier { 191e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 192e419bc7fSGatien Chevallier 193e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY1); 194e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY2); 195e419bc7fSGatien Chevallier } 196e419bc7fSGatien Chevallier 197e419bc7fSGatien Chevallier static void stm32_rtc_write_protect(void) 198e419bc7fSGatien Chevallier { 199e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 200e419bc7fSGatien Chevallier 201e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK); 202e419bc7fSGatien Chevallier } 203e419bc7fSGatien Chevallier 204e419bc7fSGatien Chevallier static bool stm32_rtc_get_bypshad(void) 205e419bc7fSGatien Chevallier { 206e419bc7fSGatien Chevallier return io_read32(get_base() + RTC_CR) & RTC_CR_BYPSHAD; 207e419bc7fSGatien Chevallier } 208e419bc7fSGatien Chevallier 209e419bc7fSGatien Chevallier /* Get the subsecond value. */ 210e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond(uint32_t ssr) 211e419bc7fSGatien Chevallier { 212e419bc7fSGatien Chevallier uint32_t prediv_s = io_read32(get_base() + RTC_PRER) & 213e419bc7fSGatien Chevallier RTC_PRER_PREDIV_S_MASK; 214e419bc7fSGatien Chevallier 215e419bc7fSGatien Chevallier return prediv_s - ssr; 216e419bc7fSGatien Chevallier } 217e419bc7fSGatien Chevallier 218e419bc7fSGatien Chevallier /* 219e419bc7fSGatien Chevallier * Get the subsecond scale. 220e419bc7fSGatien Chevallier * 221e419bc7fSGatien Chevallier * Number of subseconds in a second is linked to RTC PREDIV_S value. 222e419bc7fSGatien Chevallier * The higher PREDIV_S is, the more subsecond is precise. 223e419bc7fSGatien Chevallier */ 224e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond_scale(void) 225e419bc7fSGatien Chevallier { 226e419bc7fSGatien Chevallier return (io_read32(get_base() + RTC_PRER) & RTC_PRER_PREDIV_S_MASK) + 1; 227e419bc7fSGatien Chevallier } 228e419bc7fSGatien Chevallier 229e419bc7fSGatien Chevallier static bool cid1_has_access(unsigned int resource) 230e419bc7fSGatien Chevallier { 231e419bc7fSGatien Chevallier uint32_t cidcfgr = io_read32(get_base() + RTC_CIDCFGR(resource)); 232e419bc7fSGatien Chevallier 233e419bc7fSGatien Chevallier return !(cidcfgr & _CIDCFGR_CFEN) || 234e419bc7fSGatien Chevallier get_field_u32(cidcfgr, RTC_CIDCFGR_SCID_MASK) == RIF_CID1; 235e419bc7fSGatien Chevallier } 236e419bc7fSGatien Chevallier 237e419bc7fSGatien Chevallier static TEE_Result check_rif_config(void) 238e419bc7fSGatien Chevallier { 239e419bc7fSGatien Chevallier if (!cid1_has_access(RTC_RES_TIMESTAMP) || 240e419bc7fSGatien Chevallier !cid1_has_access(RTC_RES_CALIBRATION) || 241e419bc7fSGatien Chevallier !cid1_has_access(RTC_RES_INITIALIZATION)) 242e419bc7fSGatien Chevallier return TEE_ERROR_ACCESS_DENIED; 243e419bc7fSGatien Chevallier 244e419bc7fSGatien Chevallier return TEE_SUCCESS; 245e419bc7fSGatien Chevallier } 246e419bc7fSGatien Chevallier 247e419bc7fSGatien Chevallier static void apply_rif_config(bool is_tdcid) 248e419bc7fSGatien Chevallier { 249e419bc7fSGatien Chevallier vaddr_t base = get_base(); 250e419bc7fSGatien Chevallier unsigned int shifted_values = 0; 251e419bc7fSGatien Chevallier uint32_t seccfgr = 0; 252e419bc7fSGatien Chevallier uint32_t privcfgr = 0; 253e419bc7fSGatien Chevallier uint32_t access_mask_reg = 0; 254e419bc7fSGatien Chevallier unsigned int i = 0; 255e419bc7fSGatien Chevallier 256e419bc7fSGatien Chevallier if (!rtc_dev.conf_data) 257e419bc7fSGatien Chevallier return; 258e419bc7fSGatien Chevallier 259e419bc7fSGatien Chevallier /* Build access mask for RTC_SECCFGR and RTC_PRIVCFGR */ 260e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 261e419bc7fSGatien Chevallier if (rtc_dev.conf_data->access_mask[0] & BIT(i)) { 262e419bc7fSGatien Chevallier if (i <= RTC_RES_TIMESTAMP) 263e419bc7fSGatien Chevallier access_mask_reg |= BIT(i); 264e419bc7fSGatien Chevallier else 265e419bc7fSGatien Chevallier access_mask_reg |= BIT(i) << RTC_SECCFGR_SHIFT; 266e419bc7fSGatien Chevallier } 267e419bc7fSGatien Chevallier } 268e419bc7fSGatien Chevallier 269e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 270e419bc7fSGatien Chevallier if (!(BIT(i) & rtc_dev.conf_data->access_mask[0])) 271e419bc7fSGatien Chevallier continue; 272e419bc7fSGatien Chevallier 273e419bc7fSGatien Chevallier /* 274e419bc7fSGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID filtering 275e419bc7fSGatien Chevallier * configuration. Clearing previous configuration prevents 276e419bc7fSGatien Chevallier * undesired events during the only legitimate configuration. 277e419bc7fSGatien Chevallier */ 278e419bc7fSGatien Chevallier if (is_tdcid) 279e419bc7fSGatien Chevallier io_clrbits32(base + RTC_CIDCFGR(i), 280e419bc7fSGatien Chevallier RTC_CIDCFGR_CONF_MASK); 281e419bc7fSGatien Chevallier } 282e419bc7fSGatien Chevallier 283e419bc7fSGatien Chevallier /* Security RIF configuration */ 284e419bc7fSGatien Chevallier seccfgr = rtc_dev.conf_data->sec_conf[0]; 285e419bc7fSGatien Chevallier 286e419bc7fSGatien Chevallier /* Check if all resources must be secured */ 287e419bc7fSGatien Chevallier if (seccfgr == RTC_RIF_FULL_SECURED) { 288e419bc7fSGatien Chevallier io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_FULL_SEC); 289e419bc7fSGatien Chevallier rtc_dev.is_secured = true; 290e419bc7fSGatien Chevallier 291e419bc7fSGatien Chevallier if (!(io_read32(base + RTC_SECCFGR) & RTC_SECCFGR_FULL_SEC)) 292e419bc7fSGatien Chevallier panic("Bad RTC seccfgr configuration"); 293e419bc7fSGatien Chevallier } 294e419bc7fSGatien Chevallier 295e419bc7fSGatien Chevallier /* Shift some values to align with the register */ 296e419bc7fSGatien Chevallier shifted_values = SHIFT_U32(seccfgr & RTC_SECCFGR_VALUES_TO_SHIFT, 297e419bc7fSGatien Chevallier RTC_SECCFGR_SHIFT); 298e419bc7fSGatien Chevallier seccfgr = (seccfgr & RTC_SECCFGR_VALUES) + shifted_values; 299e419bc7fSGatien Chevallier 300e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_SECCFGR, 301e419bc7fSGatien Chevallier RTC_SECCFGR_MASK & access_mask_reg, seccfgr); 302e419bc7fSGatien Chevallier 303e419bc7fSGatien Chevallier /* Privilege RIF configuration */ 304e419bc7fSGatien Chevallier privcfgr = rtc_dev.conf_data->priv_conf[0]; 305e419bc7fSGatien Chevallier 306e419bc7fSGatien Chevallier /* Check if all resources must be privileged */ 307e419bc7fSGatien Chevallier if (privcfgr == RTC_RIF_FULL_PRIVILEGED) { 308e419bc7fSGatien Chevallier io_setbits32(base + RTC_PRIVCFGR, RTC_PRIVCFGR_FULL_PRIV); 309e419bc7fSGatien Chevallier 310e419bc7fSGatien Chevallier if (!(io_read32(base + RTC_PRIVCFGR) & RTC_PRIVCFGR_FULL_PRIV)) 311e419bc7fSGatien Chevallier panic("Bad RTC privcfgr configuration"); 312e419bc7fSGatien Chevallier } 313e419bc7fSGatien Chevallier 314e419bc7fSGatien Chevallier /* Shift some values to align with the register */ 315e419bc7fSGatien Chevallier shifted_values = SHIFT_U32(privcfgr & RTC_PRIVCFGR_VALUES_TO_SHIFT, 316e419bc7fSGatien Chevallier RTC_PRIVCFGR_SHIFT); 317e419bc7fSGatien Chevallier privcfgr = (privcfgr & RTC_PRIVCFGR_VALUES) + shifted_values; 318e419bc7fSGatien Chevallier 319e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_PRIVCFGR, 320e419bc7fSGatien Chevallier RTC_PRIVCFGR_MASK & access_mask_reg, privcfgr); 321e419bc7fSGatien Chevallier 322e419bc7fSGatien Chevallier if (!is_tdcid) 323e419bc7fSGatien Chevallier return; 324e419bc7fSGatien Chevallier 325e419bc7fSGatien Chevallier for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) { 326e419bc7fSGatien Chevallier if (!(BIT(i) & rtc_dev.conf_data->access_mask[0])) 327e419bc7fSGatien Chevallier continue; 328e419bc7fSGatien Chevallier /* 329e419bc7fSGatien Chevallier * When at least one resource has CID filtering enabled, 330e419bc7fSGatien Chevallier * the RTC_PRIVCFGR_FULL_PRIV and RTC_SECCFGR_FULL_SEC bits are 331e419bc7fSGatien Chevallier * cleared. 332e419bc7fSGatien Chevallier */ 333e419bc7fSGatien Chevallier io_clrsetbits32(base + RTC_CIDCFGR(i), 334e419bc7fSGatien Chevallier RTC_CIDCFGR_CONF_MASK, 335e419bc7fSGatien Chevallier rtc_dev.conf_data->cid_confs[i]); 336e419bc7fSGatien Chevallier } 337e419bc7fSGatien Chevallier } 338e419bc7fSGatien Chevallier 339e419bc7fSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node) 340e419bc7fSGatien Chevallier { 341e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 342e419bc7fSGatien Chevallier const fdt32_t *cuint = NULL; 343e419bc7fSGatien Chevallier size_t reg_size = 0; 344e419bc7fSGatien Chevallier unsigned int i = 0; 345e419bc7fSGatien Chevallier int lenp = 0; 346e419bc7fSGatien Chevallier 347e419bc7fSGatien Chevallier if (fdt_reg_info(fdt, node, &rtc_dev.base.pa, ®_size)) 348e419bc7fSGatien Chevallier panic(); 349e419bc7fSGatien Chevallier 350e419bc7fSGatien Chevallier io_pa_or_va(&rtc_dev.base, reg_size); 351e419bc7fSGatien Chevallier assert(rtc_dev.base.va); 352e419bc7fSGatien Chevallier 353e419bc7fSGatien Chevallier res = clk_dt_get_by_name(fdt, node, "pclk", &rtc_dev.pclk); 354e419bc7fSGatien Chevallier if (res) 355e419bc7fSGatien Chevallier return res; 356e419bc7fSGatien Chevallier 357e419bc7fSGatien Chevallier res = clk_dt_get_by_name(fdt, node, "rtc_ck", &rtc_dev.rtc_ck); 358e419bc7fSGatien Chevallier if (res) 359e419bc7fSGatien Chevallier return res; 360e419bc7fSGatien Chevallier 361e419bc7fSGatien Chevallier if (!rtc_dev.compat->has_rif_support) 362e419bc7fSGatien Chevallier return TEE_SUCCESS; 363e419bc7fSGatien Chevallier 364e419bc7fSGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 365e419bc7fSGatien Chevallier if (!cuint) { 366e419bc7fSGatien Chevallier DMSG("No RIF configuration available"); 367e419bc7fSGatien Chevallier return TEE_SUCCESS; 368e419bc7fSGatien Chevallier } 369e419bc7fSGatien Chevallier 370e419bc7fSGatien Chevallier rtc_dev.conf_data = calloc(1, sizeof(*rtc_dev.conf_data)); 371e419bc7fSGatien Chevallier if (!rtc_dev.conf_data) 372e419bc7fSGatien Chevallier panic(); 373e419bc7fSGatien Chevallier 374e419bc7fSGatien Chevallier rtc_dev.nb_res = (unsigned int)(lenp / sizeof(uint32_t)); 375e419bc7fSGatien Chevallier assert(rtc_dev.nb_res <= RTC_NB_RIF_RESOURCES); 376e419bc7fSGatien Chevallier 377e419bc7fSGatien Chevallier rtc_dev.conf_data->cid_confs = calloc(RTC_NB_RIF_RESOURCES, 378e419bc7fSGatien Chevallier sizeof(uint32_t)); 379e419bc7fSGatien Chevallier rtc_dev.conf_data->sec_conf = calloc(1, sizeof(uint32_t)); 380e419bc7fSGatien Chevallier rtc_dev.conf_data->priv_conf = calloc(1, sizeof(uint32_t)); 381e419bc7fSGatien Chevallier rtc_dev.conf_data->access_mask = calloc(1, sizeof(uint32_t)); 382e419bc7fSGatien Chevallier if (!rtc_dev.conf_data->cid_confs || !rtc_dev.conf_data->sec_conf || 383e419bc7fSGatien Chevallier !rtc_dev.conf_data->priv_conf || !rtc_dev.conf_data->access_mask) 384e419bc7fSGatien Chevallier panic("Not enough memory capacity for RTC RIF config"); 385e419bc7fSGatien Chevallier 386e419bc7fSGatien Chevallier for (i = 0; i < rtc_dev.nb_res; i++) 387e419bc7fSGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), rtc_dev.conf_data, 388e419bc7fSGatien Chevallier RTC_NB_RIF_RESOURCES); 389e419bc7fSGatien Chevallier 390e419bc7fSGatien Chevallier return TEE_SUCCESS; 391e419bc7fSGatien Chevallier } 392e419bc7fSGatien Chevallier 393e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_enter_init_mode(void) 394e419bc7fSGatien Chevallier { 395e419bc7fSGatien Chevallier vaddr_t base = get_base(); 396e419bc7fSGatien Chevallier uint32_t icsr = io_read32(base + RTC_ICSR); 397e419bc7fSGatien Chevallier uint32_t value = 0; 398e419bc7fSGatien Chevallier 399e419bc7fSGatien Chevallier if (!(icsr & RTC_ICSR_INITF)) { 400e419bc7fSGatien Chevallier icsr |= RTC_ICSR_INIT; 401e419bc7fSGatien Chevallier io_write32(base + RTC_ICSR, icsr); 402e419bc7fSGatien Chevallier 403e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value, 404e419bc7fSGatien Chevallier value & RTC_ICSR_INITF, 405e419bc7fSGatien Chevallier 10, TIMEOUT_US_RTC_GENERIC)) 406e419bc7fSGatien Chevallier return TEE_ERROR_BUSY; 407e419bc7fSGatien Chevallier } 408e419bc7fSGatien Chevallier 409e419bc7fSGatien Chevallier return TEE_SUCCESS; 410e419bc7fSGatien Chevallier } 411e419bc7fSGatien Chevallier 412e419bc7fSGatien Chevallier static void stm32_rtc_exit_init_mode(void) 413e419bc7fSGatien Chevallier { 414e419bc7fSGatien Chevallier io_clrbits32(get_base() + RTC_ICSR, RTC_ICSR_INIT); 415e419bc7fSGatien Chevallier dsb(); 416e419bc7fSGatien Chevallier } 417e419bc7fSGatien Chevallier 418e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_wait_sync(void) 419e419bc7fSGatien Chevallier { 420e419bc7fSGatien Chevallier vaddr_t base = get_base(); 421e419bc7fSGatien Chevallier uint32_t value = 0; 422e419bc7fSGatien Chevallier 423e419bc7fSGatien Chevallier io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF); 424e419bc7fSGatien Chevallier 425e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value, 426e419bc7fSGatien Chevallier value & RTC_ICSR_RSF, 10, 427e419bc7fSGatien Chevallier TIMEOUT_US_RTC_GENERIC)) 428e419bc7fSGatien Chevallier return TEE_ERROR_BUSY; 429e419bc7fSGatien Chevallier 430e419bc7fSGatien Chevallier return TEE_SUCCESS; 431e419bc7fSGatien Chevallier } 432e419bc7fSGatien Chevallier 433*d60c61e1SGatien Chevallier static void stm32_rtc_to_tm(uint32_t ssr, uint32_t tr, uint32_t dr, 434*d60c61e1SGatien Chevallier struct optee_rtc_time *tm) 435*d60c61e1SGatien Chevallier { 436*d60c61e1SGatien Chevallier tm->tm_hour = ((tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10 + 437*d60c61e1SGatien Chevallier ((tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT); 438*d60c61e1SGatien Chevallier 439*d60c61e1SGatien Chevallier if (tr & RTC_TR_PM) 440*d60c61e1SGatien Chevallier tm->tm_hour += 12; 441*d60c61e1SGatien Chevallier 442*d60c61e1SGatien Chevallier tm->tm_ms = (stm32_rtc_get_subsecond(ssr) * MS_PER_SEC) / 443*d60c61e1SGatien Chevallier stm32_rtc_get_subsecond_scale(); 444*d60c61e1SGatien Chevallier 445*d60c61e1SGatien Chevallier tm->tm_sec = ((tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10 + 446*d60c61e1SGatien Chevallier (tr & RTC_TR_SU_MASK); 447*d60c61e1SGatien Chevallier 448*d60c61e1SGatien Chevallier tm->tm_min = ((tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10 + 449*d60c61e1SGatien Chevallier ((tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT); 450*d60c61e1SGatien Chevallier 451*d60c61e1SGatien Chevallier tm->tm_wday = ((dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT) % 7; 452*d60c61e1SGatien Chevallier 453*d60c61e1SGatien Chevallier tm->tm_mday = ((dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10 + 454*d60c61e1SGatien Chevallier (dr & RTC_DR_DU_MASK); 455*d60c61e1SGatien Chevallier 456*d60c61e1SGatien Chevallier tm->tm_mon = ((dr & RTC_DR_MT_MASK) >> RTC_DR_MT_SHIFT) * 10 + 457*d60c61e1SGatien Chevallier ((dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT) - 1; 458*d60c61e1SGatien Chevallier 459*d60c61e1SGatien Chevallier tm->tm_year = ((dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10 + 460*d60c61e1SGatien Chevallier ((dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + YEAR_REF; 461*d60c61e1SGatien Chevallier } 462*d60c61e1SGatien Chevallier 463e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_get_time(struct rtc *rtc __unused, 464e419bc7fSGatien Chevallier struct optee_rtc_time *tm) 465e419bc7fSGatien Chevallier { 466e419bc7fSGatien Chevallier vaddr_t base = get_base(); 467e419bc7fSGatien Chevallier uint32_t ssr = 0; 468e419bc7fSGatien Chevallier uint32_t dr = 0; 469e419bc7fSGatien Chevallier uint32_t tr = 0; 470e419bc7fSGatien Chevallier 471e419bc7fSGatien Chevallier if (!stm32_rtc_get_bypshad()) { 472e419bc7fSGatien Chevallier uint32_t icsr = 0; 473e419bc7fSGatien Chevallier 474e419bc7fSGatien Chevallier /* Wait calendar registers are ready */ 475e419bc7fSGatien Chevallier io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF); 476e419bc7fSGatien Chevallier 477e419bc7fSGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, icsr, 478e419bc7fSGatien Chevallier icsr & RTC_ICSR_RSF, 0, 479e419bc7fSGatien Chevallier TIMEOUT_US_RTC_SHADOW)) 480e419bc7fSGatien Chevallier panic(); 481e419bc7fSGatien Chevallier } 482e419bc7fSGatien Chevallier 483e419bc7fSGatien Chevallier /* 484e419bc7fSGatien Chevallier * In our RTC we start : 485e419bc7fSGatien Chevallier * - year at 0 486e419bc7fSGatien Chevallier * - month at 1 487e419bc7fSGatien Chevallier * - day at 1 488e419bc7fSGatien Chevallier * - weekday at Monday = 1 489e419bc7fSGatien Chevallier * Change month value so it becomes 0=January, 1 = February, ... 490e419bc7fSGatien Chevallier * Change week day value so it becomes 0=Sunday, 1 = Monday, ... 491e419bc7fSGatien Chevallier */ 492e419bc7fSGatien Chevallier 493e419bc7fSGatien Chevallier ssr = io_read32(base + RTC_SSR); 494e419bc7fSGatien Chevallier tr = io_read32(base + RTC_TR); 495e419bc7fSGatien Chevallier dr = io_read32(base + RTC_DR); 496e419bc7fSGatien Chevallier 497*d60c61e1SGatien Chevallier stm32_rtc_to_tm(ssr, tr, dr, tm); 498e419bc7fSGatien Chevallier 499e419bc7fSGatien Chevallier return TEE_SUCCESS; 500e419bc7fSGatien Chevallier } 501e419bc7fSGatien Chevallier 502e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_set_time(struct rtc *rtc, struct optee_rtc_time *tm) 503e419bc7fSGatien Chevallier { 504e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 505e419bc7fSGatien Chevallier vaddr_t rtc_base = get_base(); 506e419bc7fSGatien Chevallier uint32_t tr = 0; 507e419bc7fSGatien Chevallier uint32_t dr = 0; 508e419bc7fSGatien Chevallier 509e419bc7fSGatien Chevallier /* 510e419bc7fSGatien Chevallier * In our RTC we start : 511e419bc7fSGatien Chevallier * - year at 0 512e419bc7fSGatien Chevallier * - month at 1 513e419bc7fSGatien Chevallier * - day at 1 514e419bc7fSGatien Chevallier * - weekday at Monday = 1 515e419bc7fSGatien Chevallier * Change month value so it becomes 1=January, 2 = February, ... 516e419bc7fSGatien Chevallier * Change week day value so it becomes 7=Sunday, 1 = Monday, ... 517e419bc7fSGatien Chevallier */ 518e419bc7fSGatien Chevallier tr = ((tm->tm_sec % 10) & RTC_TR_SU_MASK) | 519e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_sec / 10, RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) | 520e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_min % 10, RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK) | 521e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_min / 10, RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) | 522e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_hour % 10, RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK) | 523e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_hour / 10, RTC_TR_HT_SHIFT) & RTC_TR_HT_MASK); 524e419bc7fSGatien Chevallier 525e419bc7fSGatien Chevallier dr = ((tm->tm_mday % 10) & RTC_DR_DU_MASK) | 526e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_mday / 10, RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) | 527e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_mon + 1) % 10, RTC_DR_MU_SHIFT) & 528e419bc7fSGatien Chevallier RTC_DR_MU_MASK) | 529e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_mon + 1) / 10, RTC_DR_MT_SHIFT) & 530e419bc7fSGatien Chevallier RTC_DR_MT_MASK) | 531e419bc7fSGatien Chevallier (SHIFT_U32(tm->tm_wday ? tm->tm_wday : 7, RTC_DR_WDU_SHIFT) & 532e419bc7fSGatien Chevallier RTC_DR_WDU_MASK) | 533e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) % 10, 534e419bc7fSGatien Chevallier RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK) | 535e419bc7fSGatien Chevallier (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) / 10, 536e419bc7fSGatien Chevallier RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK); 537e419bc7fSGatien Chevallier 538e419bc7fSGatien Chevallier stm32_rtc_write_unprotect(); 539e419bc7fSGatien Chevallier 540e419bc7fSGatien Chevallier res = stm32_rtc_enter_init_mode(); 541e419bc7fSGatien Chevallier if (res) 542e419bc7fSGatien Chevallier goto end; 543e419bc7fSGatien Chevallier 544e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_TR, tr); 545e419bc7fSGatien Chevallier io_write32(rtc_base + RTC_DR, dr); 546e419bc7fSGatien Chevallier 547e419bc7fSGatien Chevallier stm32_rtc_exit_init_mode(); 548e419bc7fSGatien Chevallier 549e419bc7fSGatien Chevallier res = stm32_rtc_wait_sync(); 550e419bc7fSGatien Chevallier end: 551e419bc7fSGatien Chevallier stm32_rtc_write_protect(); 552e419bc7fSGatien Chevallier 553e419bc7fSGatien Chevallier return res; 554e419bc7fSGatien Chevallier } 555e419bc7fSGatien Chevallier 556*d60c61e1SGatien Chevallier TEE_Result stm32_rtc_get_timestamp(struct optee_rtc_time *tm) 557*d60c61e1SGatien Chevallier { 558*d60c61e1SGatien Chevallier vaddr_t base = get_base(); 559*d60c61e1SGatien Chevallier uint32_t exceptions = 0; 560*d60c61e1SGatien Chevallier uint32_t value = 0; 561*d60c61e1SGatien Chevallier uint32_t ssr = 0; 562*d60c61e1SGatien Chevallier uint32_t dr = 0; 563*d60c61e1SGatien Chevallier uint32_t tr = 0; 564*d60c61e1SGatien Chevallier 565*d60c61e1SGatien Chevallier exceptions = cpu_spin_lock_xsave(&rtc_dev.ts_lock); 566*d60c61e1SGatien Chevallier 567*d60c61e1SGatien Chevallier if (IO_READ32_POLL_TIMEOUT(base + RTC_SR, value, 568*d60c61e1SGatien Chevallier value & RTC_SR_TSF, 569*d60c61e1SGatien Chevallier 10, TIMEOUT_US_RTC_GENERIC)) { 570*d60c61e1SGatien Chevallier cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions); 571*d60c61e1SGatien Chevallier return TEE_ERROR_NO_DATA; 572*d60c61e1SGatien Chevallier } 573*d60c61e1SGatien Chevallier 574*d60c61e1SGatien Chevallier ssr = io_read32(base + RTC_TSSSR); 575*d60c61e1SGatien Chevallier tr = io_read32(base + RTC_TSTR); 576*d60c61e1SGatien Chevallier dr = io_read32(base + RTC_TSDR); 577*d60c61e1SGatien Chevallier 578*d60c61e1SGatien Chevallier io_setbits32(base + RTC_SCR, RTC_SCR_CTSF); 579*d60c61e1SGatien Chevallier 580*d60c61e1SGatien Chevallier /* Tamper event overflow detection */ 581*d60c61e1SGatien Chevallier if (io_read32(base + RTC_SR) & RTC_SR_TSOVF) { 582*d60c61e1SGatien Chevallier io_setbits32(base + RTC_SCR, RTC_SCR_CTSOVF); 583*d60c61e1SGatien Chevallier DMSG("A timestamp event occurred while handling current event"); 584*d60c61e1SGatien Chevallier } 585*d60c61e1SGatien Chevallier 586*d60c61e1SGatien Chevallier cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions); 587*d60c61e1SGatien Chevallier 588*d60c61e1SGatien Chevallier stm32_rtc_to_tm(ssr, tr, dr, tm); 589*d60c61e1SGatien Chevallier 590*d60c61e1SGatien Chevallier /* No year timestamp available */ 591*d60c61e1SGatien Chevallier tm->tm_year = 0; 592*d60c61e1SGatien Chevallier 593*d60c61e1SGatien Chevallier return TEE_SUCCESS; 594*d60c61e1SGatien Chevallier } 595*d60c61e1SGatien Chevallier 596*d60c61e1SGatien Chevallier TEE_Result stm32_rtc_set_tamper_timestamp(void) 597*d60c61e1SGatien Chevallier { 598*d60c61e1SGatien Chevallier vaddr_t base = get_base(); 599*d60c61e1SGatien Chevallier 600*d60c61e1SGatien Chevallier stm32_rtc_write_unprotect(); 601*d60c61e1SGatien Chevallier 602*d60c61e1SGatien Chevallier /* Secure Timestamp bit */ 603*d60c61e1SGatien Chevallier if (!rtc_dev.compat->has_seccfgr) { 604*d60c61e1SGatien Chevallier /* Inverted logic */ 605*d60c61e1SGatien Chevallier io_clrbits32(base + RTC_SMCR, RTC_SMCR_TS_DPROT); 606*d60c61e1SGatien Chevallier } else { 607*d60c61e1SGatien Chevallier io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_TS_SEC); 608*d60c61e1SGatien Chevallier } 609*d60c61e1SGatien Chevallier 610*d60c61e1SGatien Chevallier /* Enable tamper timestamper */ 611*d60c61e1SGatien Chevallier io_setbits32(base + RTC_CR, RTC_CR_TAMPTS); 612*d60c61e1SGatien Chevallier 613*d60c61e1SGatien Chevallier stm32_rtc_write_protect(); 614*d60c61e1SGatien Chevallier 615*d60c61e1SGatien Chevallier return TEE_SUCCESS; 616*d60c61e1SGatien Chevallier } 617*d60c61e1SGatien Chevallier 618*d60c61e1SGatien Chevallier TEE_Result stm32_rtc_is_timestamp_enabled(bool *ret) 619*d60c61e1SGatien Chevallier { 620*d60c61e1SGatien Chevallier *ret = io_read32(get_base() + RTC_CR) & RTC_CR_TAMPTS; 621*d60c61e1SGatien Chevallier 622*d60c61e1SGatien Chevallier return TEE_SUCCESS; 623*d60c61e1SGatien Chevallier } 624*d60c61e1SGatien Chevallier 625*d60c61e1SGatien Chevallier TEE_Result stm32_rtc_driver_is_initialized(void) 626*d60c61e1SGatien Chevallier { 627*d60c61e1SGatien Chevallier if (rtc_dev.pclk) 628*d60c61e1SGatien Chevallier return TEE_SUCCESS; 629*d60c61e1SGatien Chevallier 630*d60c61e1SGatien Chevallier return TEE_ERROR_DEFER_DRIVER_INIT; 631*d60c61e1SGatien Chevallier } 632*d60c61e1SGatien Chevallier 633e419bc7fSGatien Chevallier static const struct rtc_ops stm32_rtc_ops = { 634e419bc7fSGatien Chevallier .get_time = stm32_rtc_get_time, 635e419bc7fSGatien Chevallier .set_time = stm32_rtc_set_time, 636e419bc7fSGatien Chevallier }; 637e419bc7fSGatien Chevallier 638e419bc7fSGatien Chevallier static struct rtc stm32_rtc = { 639e419bc7fSGatien Chevallier .ops = &stm32_rtc_ops, 640e419bc7fSGatien Chevallier .range_min = RTC_TIME(YEAR_REF, 0, 1, 0, 0, 0, 0, 0), 641e419bc7fSGatien Chevallier .range_max = RTC_TIME(YEAR_MAX, 11, 31, 4, 23, 59, 59, 999), 642e419bc7fSGatien Chevallier }; 643e419bc7fSGatien Chevallier 644e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_probe(const void *fdt, int node, 645e419bc7fSGatien Chevallier const void *compat_data) 646e419bc7fSGatien Chevallier { 647e419bc7fSGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 648e419bc7fSGatien Chevallier bool is_tdcid = false; 649e419bc7fSGatien Chevallier 650e419bc7fSGatien Chevallier rtc_dev.compat = compat_data; 651e419bc7fSGatien Chevallier 652e419bc7fSGatien Chevallier if (rtc_dev.compat->has_rif_support) { 653e419bc7fSGatien Chevallier res = stm32_rifsc_check_tdcid(&is_tdcid); 654e419bc7fSGatien Chevallier if (res) 655e419bc7fSGatien Chevallier return res; 656e419bc7fSGatien Chevallier } 657e419bc7fSGatien Chevallier 658e419bc7fSGatien Chevallier res = parse_dt(fdt, node); 659e419bc7fSGatien Chevallier if (res) { 660e419bc7fSGatien Chevallier memset(&rtc_dev, 0, sizeof(rtc_dev)); 661e419bc7fSGatien Chevallier return res; 662e419bc7fSGatien Chevallier } 663e419bc7fSGatien Chevallier 664e419bc7fSGatien Chevallier /* Unbalanced clock enable to ensure RTC core clock is always on */ 665e419bc7fSGatien Chevallier res = clk_enable(rtc_dev.rtc_ck); 666e419bc7fSGatien Chevallier if (res) 667e419bc7fSGatien Chevallier panic("Couldn't enable RTC clock"); 668e419bc7fSGatien Chevallier 669e419bc7fSGatien Chevallier if (clk_get_rate(rtc_dev.pclk) < (clk_get_rate(rtc_dev.rtc_ck) * 7)) 670e419bc7fSGatien Chevallier rtc_dev.flags |= RTC_FLAGS_READ_TWICE; 671e419bc7fSGatien Chevallier 672e419bc7fSGatien Chevallier if (rtc_dev.compat->has_rif_support) { 673e419bc7fSGatien Chevallier res = clk_enable(rtc_dev.pclk); 674e419bc7fSGatien Chevallier if (res) 675e419bc7fSGatien Chevallier panic("Could not enable RTC bus clock"); 676e419bc7fSGatien Chevallier 677e419bc7fSGatien Chevallier apply_rif_config(is_tdcid); 678e419bc7fSGatien Chevallier 679e419bc7fSGatien Chevallier /* 680e419bc7fSGatien Chevallier * Verify if applied RIF config will not disable 681e419bc7fSGatien Chevallier * other functionalities of this driver. 682e419bc7fSGatien Chevallier */ 683e419bc7fSGatien Chevallier res = check_rif_config(); 684e419bc7fSGatien Chevallier if (res) 685e419bc7fSGatien Chevallier panic("Incompatible RTC RIF configuration"); 686e419bc7fSGatien Chevallier 687e419bc7fSGatien Chevallier clk_disable(rtc_dev.pclk); 688e419bc7fSGatien Chevallier } 689e419bc7fSGatien Chevallier 690e419bc7fSGatien Chevallier rtc_register(&stm32_rtc); 691e419bc7fSGatien Chevallier 692e419bc7fSGatien Chevallier return res; 693e419bc7fSGatien Chevallier } 694e419bc7fSGatien Chevallier 695e419bc7fSGatien Chevallier static const struct rtc_compat mp25_compat = { 696e419bc7fSGatien Chevallier .has_seccfgr = true, 697e419bc7fSGatien Chevallier .has_rif_support = true, 698e419bc7fSGatien Chevallier }; 699e419bc7fSGatien Chevallier 700e419bc7fSGatien Chevallier static const struct rtc_compat mp15_compat = { 701e419bc7fSGatien Chevallier .has_seccfgr = false, 702e419bc7fSGatien Chevallier .has_rif_support = false, 703e419bc7fSGatien Chevallier }; 704e419bc7fSGatien Chevallier 705e419bc7fSGatien Chevallier static const struct rtc_compat mp13_compat = { 706e419bc7fSGatien Chevallier .has_seccfgr = true, 707e419bc7fSGatien Chevallier .has_rif_support = false, 708e419bc7fSGatien Chevallier }; 709e419bc7fSGatien Chevallier 710e419bc7fSGatien Chevallier static const struct dt_device_match stm32_rtc_match_table[] = { 711e419bc7fSGatien Chevallier { 712e419bc7fSGatien Chevallier .compatible = "st,stm32mp25-rtc", 713e419bc7fSGatien Chevallier .compat_data = &mp25_compat, 714e419bc7fSGatien Chevallier }, 715e419bc7fSGatien Chevallier { 716e419bc7fSGatien Chevallier .compatible = "st,stm32mp1-rtc", 717e419bc7fSGatien Chevallier .compat_data = &mp15_compat, 718e419bc7fSGatien Chevallier }, 719e419bc7fSGatien Chevallier { 720e419bc7fSGatien Chevallier .compatible = "st,stm32mp13-rtc", 721e419bc7fSGatien Chevallier .compat_data = &mp13_compat, 722e419bc7fSGatien Chevallier }, 723e419bc7fSGatien Chevallier { } 724e419bc7fSGatien Chevallier }; 725e419bc7fSGatien Chevallier 726e419bc7fSGatien Chevallier DEFINE_DT_DRIVER(stm32_rtc_dt_driver) = { 727e419bc7fSGatien Chevallier .name = "stm32-rtc", 728e419bc7fSGatien Chevallier .match_table = stm32_rtc_match_table, 729e419bc7fSGatien Chevallier .probe = stm32_rtc_probe, 730e419bc7fSGatien Chevallier }; 731