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