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