1*35abff2fSClément Léger // SPDX-License-Identifier: BSD-2-Clause 2*35abff2fSClément Léger /* 3*35abff2fSClément Léger * Copyright 2022 Microchip 4*35abff2fSClément Léger * 5*35abff2fSClément Léger * Driver for AT91 RTC 6*35abff2fSClément Léger */ 7*35abff2fSClément Léger 8*35abff2fSClément Léger #include <assert.h> 9*35abff2fSClément Léger #include <drivers/rtc.h> 10*35abff2fSClément Léger #include <io.h> 11*35abff2fSClément Léger #include <kernel/dt.h> 12*35abff2fSClément Léger #include <matrix.h> 13*35abff2fSClément Léger #include <mm/core_memprot.h> 14*35abff2fSClément Léger #include <sama5d2.h> 15*35abff2fSClément Léger 16*35abff2fSClément Léger #define RTC_VAL(reg, val) (((val) >> RTC_## reg ## _SHIFT) & \ 17*35abff2fSClément Léger RTC_## reg ##_MASK) 18*35abff2fSClément Léger 19*35abff2fSClément Léger #define RTC_SET_VAL(reg, val) SHIFT_U32((val) & RTC_## reg ##_MASK, \ 20*35abff2fSClément Léger RTC_## reg ## _SHIFT) 21*35abff2fSClément Léger 22*35abff2fSClément Léger #define RTC_CR 0x0 23*35abff2fSClément Léger #define RTC_CR_UPDCAL BIT(1) 24*35abff2fSClément Léger #define RTC_CR_UPDTIM BIT(0) 25*35abff2fSClément Léger 26*35abff2fSClément Léger #define RTC_MR 0x4 27*35abff2fSClément Léger #define RTC_MR_HR_MODE BIT(0) 28*35abff2fSClément Léger #define RTC_MR_PERSIAN BIT(1) 29*35abff2fSClément Léger #define RTC_MR_UTC BIT(2) 30*35abff2fSClément Léger #define RTC_MR_NEGPPM BIT(4) 31*35abff2fSClément Léger #define RTC_MR_CORR_SHIFT 8 32*35abff2fSClément Léger #define RTC_MR_CORR_MASK GENMASK_32(6, 0) 33*35abff2fSClément Léger #define RTC_MR_CORR(val) RTC_VAL(val, MR_CORR) 34*35abff2fSClément Léger #define RTC_MR_HIGHPPM BIT(15) 35*35abff2fSClément Léger 36*35abff2fSClément Léger #define RTC_TIMR 0x8 37*35abff2fSClément Léger #define RTC_CALR 0xC 38*35abff2fSClément Léger 39*35abff2fSClément Léger #define RTC_SR 0x18 40*35abff2fSClément Léger #define RTC_SR_ACKUPD BIT(0) 41*35abff2fSClément Léger #define RTC_SR_SEC BIT(2) 42*35abff2fSClément Léger 43*35abff2fSClément Léger #define RTC_SCCR 0x1C 44*35abff2fSClément Léger #define RTC_SCCR_ACKCLR BIT(0) 45*35abff2fSClément Léger #define RTC_SCCR_SECCLR BIT(2) 46*35abff2fSClément Léger 47*35abff2fSClément Léger #define RTC_VER 0x2C 48*35abff2fSClément Léger #define RTC_VER_NVTIM BIT(0) 49*35abff2fSClément Léger #define RTC_VER_NVCAL BIT(1) 50*35abff2fSClément Léger 51*35abff2fSClément Léger #define RTC_TSTR0 0xB0 52*35abff2fSClément Léger #define RTC_TSDR0 0xB4 53*35abff2fSClément Léger 54*35abff2fSClément Léger #define RTC_TSSR0 0xB8 55*35abff2fSClément Léger #define RTC_TSSR_DET_OFFSET 16 56*35abff2fSClément Léger #define RTC_TSSR_DET_COUNT 8 57*35abff2fSClément Léger #define RTC_TSSR_TST_PIN BIT(2) 58*35abff2fSClément Léger #define RTC_TSSR_JTAG BIT(3) 59*35abff2fSClément Léger 60*35abff2fSClément Léger /* Layout of Time registers */ 61*35abff2fSClément Léger #define RTC_TIME_BACKUP BIT(31) 62*35abff2fSClément Léger #define RTC_TIME_HOUR_SHIFT 16 63*35abff2fSClément Léger #define RTC_TIME_HOUR_MASK GENMASK_32(5, 0) 64*35abff2fSClément Léger #define RTC_TIME_MIN_SHIFT 8 65*35abff2fSClément Léger #define RTC_TIME_MIN_MASK GENMASK_32(6, 0) 66*35abff2fSClément Léger #define RTC_TIME_SEC_SHIFT 0 67*35abff2fSClément Léger #define RTC_TIME_SEC_MASK GENMASK_32(6, 0) 68*35abff2fSClément Léger 69*35abff2fSClément Léger /* Layout of Calendar registers */ 70*35abff2fSClément Léger #define RTC_CAL_DATE_SHIFT 24 71*35abff2fSClément Léger #define RTC_CAL_DATE_MASK GENMASK_32(5, 0) 72*35abff2fSClément Léger #define RTC_CAL_DAY_SHIFT 21 73*35abff2fSClément Léger #define RTC_CAL_DAY_MASK GENMASK_32(2, 0) 74*35abff2fSClément Léger #define RTC_CAL_MONTH_SHIFT 16 75*35abff2fSClément Léger #define RTC_CAL_MONTH_MASK GENMASK_32(4, 0) 76*35abff2fSClément Léger #define RTC_CAL_YEAR_SHIFT 8 77*35abff2fSClément Léger #define RTC_CAL_YEAR_MASK GENMASK_32(7, 0) 78*35abff2fSClément Léger #define RTC_CAL_CENT_SHIFT 0 79*35abff2fSClément Léger #define RTC_CAL_CENT_MASK GENMASK_32(6, 0) 80*35abff2fSClément Léger 81*35abff2fSClément Léger #define ATMEL_RTC_CORR_DIVIDEND 3906000 82*35abff2fSClément Léger #define ATMEL_RTC_CORR_LOW_RATIO 20 83*35abff2fSClément Léger 84*35abff2fSClément Léger static vaddr_t rtc_base; 85*35abff2fSClément Léger 86*35abff2fSClément Léger static uint8_t bcd_decode(uint8_t dcb_val) 87*35abff2fSClément Léger { 88*35abff2fSClément Léger return (dcb_val & 0xF) + (dcb_val >> 4) * 10; 89*35abff2fSClément Léger } 90*35abff2fSClément Léger 91*35abff2fSClément Léger static uint8_t bcd_encode(uint32_t value) 92*35abff2fSClément Léger { 93*35abff2fSClément Léger return ((value / 10) << 4) + value % 10; 94*35abff2fSClément Léger } 95*35abff2fSClément Léger 96*35abff2fSClément Léger static uint32_t atmel_rtc_read(unsigned int offset) 97*35abff2fSClément Léger { 98*35abff2fSClément Léger return io_read32(rtc_base + offset); 99*35abff2fSClément Léger } 100*35abff2fSClément Léger 101*35abff2fSClément Léger static void atmel_rtc_write(unsigned int offset, uint32_t val) 102*35abff2fSClément Léger { 103*35abff2fSClément Léger return io_write32(rtc_base + offset, val); 104*35abff2fSClément Léger } 105*35abff2fSClément Léger 106*35abff2fSClément Léger static void atmel_decode_date(unsigned int time_reg, unsigned int cal_reg, 107*35abff2fSClément Léger struct optee_rtc_time *tm) 108*35abff2fSClément Léger { 109*35abff2fSClément Léger uint32_t time = 0; 110*35abff2fSClément Léger uint32_t date = 0; 111*35abff2fSClément Léger 112*35abff2fSClément Léger /* Must read twice in case it changes */ 113*35abff2fSClément Léger do { 114*35abff2fSClément Léger time = atmel_rtc_read(time_reg); 115*35abff2fSClément Léger date = atmel_rtc_read(cal_reg); 116*35abff2fSClément Léger } while ((time != atmel_rtc_read(time_reg)) || 117*35abff2fSClément Léger (date != atmel_rtc_read(cal_reg))); 118*35abff2fSClément Léger 119*35abff2fSClément Léger tm->tm_wday = bcd_decode(RTC_VAL(CAL_DAY, date)) - 1; 120*35abff2fSClément Léger tm->tm_mday = bcd_decode(RTC_VAL(CAL_DATE, date)); 121*35abff2fSClément Léger tm->tm_mon = bcd_decode(RTC_VAL(CAL_MONTH, date)) - 1; 122*35abff2fSClément Léger tm->tm_year = bcd_decode(RTC_VAL(CAL_CENT, date)) * 100; 123*35abff2fSClément Léger tm->tm_year += bcd_decode(RTC_VAL(CAL_YEAR, date)); 124*35abff2fSClément Léger 125*35abff2fSClément Léger tm->tm_hour = bcd_decode(RTC_VAL(TIME_HOUR, time)); 126*35abff2fSClément Léger tm->tm_min = bcd_decode(RTC_VAL(TIME_MIN, time)); 127*35abff2fSClément Léger tm->tm_sec = bcd_decode(RTC_VAL(TIME_SEC, time)); 128*35abff2fSClément Léger } 129*35abff2fSClément Léger 130*35abff2fSClément Léger static TEE_Result atmel_rtc_get_time(struct rtc *rtc __unused, 131*35abff2fSClément Léger struct optee_rtc_time *tm) 132*35abff2fSClément Léger { 133*35abff2fSClément Léger atmel_decode_date(RTC_TIMR, RTC_CALR, tm); 134*35abff2fSClément Léger 135*35abff2fSClément Léger return TEE_SUCCESS; 136*35abff2fSClément Léger } 137*35abff2fSClément Léger 138*35abff2fSClément Léger static TEE_Result atmel_rtc_set_time(struct rtc *rtc __unused, 139*35abff2fSClément Léger struct optee_rtc_time *tm) 140*35abff2fSClément Léger { 141*35abff2fSClément Léger uint32_t cr = 0; 142*35abff2fSClément Léger uint32_t sr = 0; 143*35abff2fSClément Léger uint32_t err = 0; 144*35abff2fSClément Léger 145*35abff2fSClément Léger /* First, wait for UPDCAL/UPDTIM to be 0 */ 146*35abff2fSClément Léger do { 147*35abff2fSClément Léger cr = atmel_rtc_read(RTC_CR); 148*35abff2fSClément Léger } while (cr & (RTC_CR_UPDCAL | RTC_CR_UPDTIM)); 149*35abff2fSClément Léger 150*35abff2fSClément Léger /* Stop Time/Calendar for update */ 151*35abff2fSClément Léger atmel_rtc_write(RTC_CR, cr | RTC_CR_UPDCAL | RTC_CR_UPDTIM); 152*35abff2fSClément Léger 153*35abff2fSClément Léger do { 154*35abff2fSClément Léger sr = atmel_rtc_read(RTC_SR); 155*35abff2fSClément Léger } while (!(sr & RTC_SR_ACKUPD)); 156*35abff2fSClément Léger 157*35abff2fSClément Léger atmel_rtc_write(RTC_SCCR, RTC_SCCR_ACKCLR); 158*35abff2fSClément Léger 159*35abff2fSClément Léger atmel_rtc_write(RTC_TIMR, 160*35abff2fSClément Léger RTC_SET_VAL(TIME_SEC, bcd_encode(tm->tm_sec)) | 161*35abff2fSClément Léger RTC_SET_VAL(TIME_MIN, bcd_encode(tm->tm_min)) | 162*35abff2fSClément Léger RTC_SET_VAL(TIME_HOUR, bcd_encode(tm->tm_hour))); 163*35abff2fSClément Léger 164*35abff2fSClément Léger atmel_rtc_write(RTC_CALR, 165*35abff2fSClément Léger RTC_SET_VAL(CAL_CENT, 166*35abff2fSClément Léger bcd_encode(tm->tm_year / 100)) | 167*35abff2fSClément Léger RTC_SET_VAL(CAL_YEAR, bcd_encode(tm->tm_year % 100)) | 168*35abff2fSClément Léger RTC_SET_VAL(CAL_MONTH, bcd_encode(tm->tm_mon + 1)) | 169*35abff2fSClément Léger RTC_SET_VAL(CAL_DAY, bcd_encode(tm->tm_wday + 1)) | 170*35abff2fSClément Léger RTC_SET_VAL(CAL_DATE, bcd_encode(tm->tm_mday))); 171*35abff2fSClément Léger 172*35abff2fSClément Léger err = atmel_rtc_read(RTC_VER); 173*35abff2fSClément Léger if (err) { 174*35abff2fSClément Léger if (err & RTC_VER_NVTIM) 175*35abff2fSClément Léger DMSG("Invalid time programmed"); 176*35abff2fSClément Léger if (err & RTC_VER_NVCAL) 177*35abff2fSClément Léger DMSG("Invalid date programmed"); 178*35abff2fSClément Léger 179*35abff2fSClément Léger return TEE_ERROR_BAD_PARAMETERS; 180*35abff2fSClément Léger } 181*35abff2fSClément Léger 182*35abff2fSClément Léger /* Restart Time/Calendar */ 183*35abff2fSClément Léger atmel_rtc_write(RTC_CR, cr); 184*35abff2fSClément Léger 185*35abff2fSClément Léger return TEE_SUCCESS; 186*35abff2fSClément Léger } 187*35abff2fSClément Léger 188*35abff2fSClément Léger static TEE_Result atmel_rtc_get_offset(struct rtc *rtc __unused, long *offset) 189*35abff2fSClément Léger { 190*35abff2fSClément Léger uint32_t mr = atmel_rtc_read(RTC_MR); 191*35abff2fSClément Léger long val = RTC_VAL(MR_CORR, mr); 192*35abff2fSClément Léger 193*35abff2fSClément Léger if (!val) { 194*35abff2fSClément Léger *offset = 0; 195*35abff2fSClément Léger return TEE_SUCCESS; 196*35abff2fSClément Léger } 197*35abff2fSClément Léger 198*35abff2fSClément Léger val++; 199*35abff2fSClément Léger 200*35abff2fSClément Léger if (!(mr & RTC_MR_HIGHPPM)) 201*35abff2fSClément Léger val *= ATMEL_RTC_CORR_LOW_RATIO; 202*35abff2fSClément Léger 203*35abff2fSClément Léger val = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND, val); 204*35abff2fSClément Léger 205*35abff2fSClément Léger if (!(mr & RTC_MR_NEGPPM)) 206*35abff2fSClément Léger val = -val; 207*35abff2fSClément Léger 208*35abff2fSClément Léger *offset = val; 209*35abff2fSClément Léger 210*35abff2fSClément Léger return TEE_SUCCESS; 211*35abff2fSClément Léger } 212*35abff2fSClément Léger 213*35abff2fSClément Léger static TEE_Result atmel_rtc_set_offset(struct rtc *rtc __unused, long offset) 214*35abff2fSClément Léger { 215*35abff2fSClément Léger long corr = 0; 216*35abff2fSClément Léger uint32_t mr = 0; 217*35abff2fSClément Léger 218*35abff2fSClément Léger if (offset > ATMEL_RTC_CORR_DIVIDEND / 2) 219*35abff2fSClément Léger return TEE_ERROR_BAD_PARAMETERS; 220*35abff2fSClément Léger if (offset < -ATMEL_RTC_CORR_DIVIDEND / 2) 221*35abff2fSClément Léger return TEE_ERROR_BAD_PARAMETERS; 222*35abff2fSClément Léger 223*35abff2fSClément Léger mr = atmel_rtc_read(RTC_MR); 224*35abff2fSClément Léger mr &= ~(RTC_MR_NEGPPM | RTC_MR_CORR_MASK | RTC_MR_HIGHPPM); 225*35abff2fSClément Léger 226*35abff2fSClément Léger if (offset > 0) 227*35abff2fSClément Léger mr |= RTC_MR_NEGPPM; 228*35abff2fSClément Léger else 229*35abff2fSClément Léger offset = -offset; 230*35abff2fSClément Léger 231*35abff2fSClément Léger /* offset less than 764 ppb, disable correction */ 232*35abff2fSClément Léger if (offset < 764) { 233*35abff2fSClément Léger atmel_rtc_write(RTC_MR, mr & ~RTC_MR_NEGPPM); 234*35abff2fSClément Léger 235*35abff2fSClément Léger return TEE_SUCCESS; 236*35abff2fSClément Léger } 237*35abff2fSClément Léger 238*35abff2fSClément Léger /* 239*35abff2fSClément Léger * 29208 ppb is the perfect cutoff between low range and high range 240*35abff2fSClément Léger * low range values are never better than high range value after that. 241*35abff2fSClément Léger */ 242*35abff2fSClément Léger if (offset < 29208) { 243*35abff2fSClément Léger corr = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND, 244*35abff2fSClément Léger offset * ATMEL_RTC_CORR_LOW_RATIO); 245*35abff2fSClément Léger } else { 246*35abff2fSClément Léger corr = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND, offset); 247*35abff2fSClément Léger mr |= RTC_MR_HIGHPPM; 248*35abff2fSClément Léger } 249*35abff2fSClément Léger 250*35abff2fSClément Léger corr = MIN(corr, 128); 251*35abff2fSClément Léger 252*35abff2fSClément Léger mr |= ((corr - 1) & RTC_MR_CORR_MASK) << RTC_MR_CORR_SHIFT; 253*35abff2fSClément Léger 254*35abff2fSClément Léger atmel_rtc_write(RTC_MR, mr); 255*35abff2fSClément Léger 256*35abff2fSClément Léger return TEE_SUCCESS; 257*35abff2fSClément Léger } 258*35abff2fSClément Léger 259*35abff2fSClément Léger static const struct rtc_ops atmel_rtc_ops = { 260*35abff2fSClément Léger .get_time = atmel_rtc_get_time, 261*35abff2fSClément Léger .set_time = atmel_rtc_set_time, 262*35abff2fSClément Léger .get_offset = atmel_rtc_get_offset, 263*35abff2fSClément Léger .set_offset = atmel_rtc_set_offset, 264*35abff2fSClément Léger }; 265*35abff2fSClément Léger 266*35abff2fSClément Léger static struct rtc atmel_rtc = { 267*35abff2fSClément Léger .ops = &atmel_rtc_ops, 268*35abff2fSClément Léger .range_min = { 1900, 1, 1, 0, 0, 0, 0 }, 269*35abff2fSClément Léger .range_max = { 2099, 12, 31, 23, 59, 59, 0 }, 270*35abff2fSClément Léger }; 271*35abff2fSClément Léger 272*35abff2fSClément Léger static TEE_Result atmel_rtc_probe(const void *fdt, int node, 273*35abff2fSClément Léger const void *compat_data __unused) 274*35abff2fSClément Léger { 275*35abff2fSClément Léger size_t size = 0; 276*35abff2fSClément Léger 277*35abff2fSClément Léger if (rtc_base) 278*35abff2fSClément Léger return TEE_ERROR_GENERIC; 279*35abff2fSClément Léger 280*35abff2fSClément Léger if (_fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 281*35abff2fSClément Léger return TEE_ERROR_BAD_PARAMETERS; 282*35abff2fSClément Léger 283*35abff2fSClément Léger matrix_configure_periph_secure(AT91C_ID_SYS); 284*35abff2fSClément Léger 285*35abff2fSClément Léger if (dt_map_dev(fdt, node, &rtc_base, &size) < 0) 286*35abff2fSClément Léger return TEE_ERROR_GENERIC; 287*35abff2fSClément Léger 288*35abff2fSClément Léger atmel_rtc_write(RTC_CR, 0); 289*35abff2fSClément Léger /* Enable 24 hours Gregorian mode (this is a clear bits operation !) */ 290*35abff2fSClément Léger io_clrbits32(rtc_base + RTC_MR, RTC_MR_PERSIAN | RTC_MR_UTC | 291*35abff2fSClément Léger RTC_MR_HR_MODE); 292*35abff2fSClément Léger 293*35abff2fSClément Léger rtc_register(&atmel_rtc); 294*35abff2fSClément Léger 295*35abff2fSClément Léger return TEE_SUCCESS; 296*35abff2fSClément Léger } 297*35abff2fSClément Léger 298*35abff2fSClément Léger static const struct dt_device_match atmel_rtc_match_table[] = { 299*35abff2fSClément Léger { .compatible = "atmel,sama5d2-rtc" }, 300*35abff2fSClément Léger { } 301*35abff2fSClément Léger }; 302*35abff2fSClément Léger 303*35abff2fSClément Léger DEFINE_DT_DRIVER(atmel_rtc_dt_driver) = { 304*35abff2fSClément Léger .name = "atmel_rtc", 305*35abff2fSClément Léger .type = DT_DRIVER_NOTYPE, 306*35abff2fSClément Léger .match_table = atmel_rtc_match_table, 307*35abff2fSClément Léger .probe = atmel_rtc_probe, 308*35abff2fSClément Léger }; 309*35abff2fSClément Léger 310