1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * rtc-efi: RTC Class Driver for EFI-based systems 4 * 5 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 6 * 7 * Author: dann frazier <dannf@dannf.org> 8 * Based on efirtc.c by Stephane Eranian 9 */ 10 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/stringify.h> 16 #include <linux/time.h> 17 #include <linux/platform_device.h> 18 #include <linux/rtc.h> 19 #include <linux/efi.h> 20 21 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) 22 23 /* 24 * returns day of the year [0-365] 25 */ 26 static inline int 27 compute_yday(efi_time_t *eft) 28 { 29 /* efi_time_t.month is in the [1-12] so, we need -1 */ 30 return rtc_year_days(eft->day, eft->month - 1, eft->year); 31 } 32 33 /* 34 * returns day of the week [0-6] 0=Sunday 35 */ 36 static int 37 compute_wday(efi_time_t *eft, int yday) 38 { 39 int ndays = eft->year * (365 % 7) 40 + (eft->year - 1) / 4 41 - (eft->year - 1) / 100 42 + (eft->year - 1) / 400 43 + yday; 44 45 /* 46 * 1/1/0000 may or may not have been a Sunday (if it ever existed at 47 * all) but assuming it was makes this calculation work correctly. 48 */ 49 return ndays % 7; 50 } 51 52 static void 53 convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) 54 { 55 memset(eft, 0, sizeof(*eft)); 56 eft->year = wtime->tm_year + 1900; 57 eft->month = wtime->tm_mon + 1; 58 eft->day = wtime->tm_mday; 59 eft->hour = wtime->tm_hour; 60 eft->minute = wtime->tm_min; 61 eft->second = wtime->tm_sec; 62 eft->nanosecond = 0; 63 eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; 64 eft->timezone = EFI_UNSPECIFIED_TIMEZONE; 65 } 66 67 static bool 68 convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) 69 { 70 memset(wtime, 0, sizeof(*wtime)); 71 72 if (eft->second >= 60) 73 return false; 74 wtime->tm_sec = eft->second; 75 76 if (eft->minute >= 60) 77 return false; 78 wtime->tm_min = eft->minute; 79 80 if (eft->hour >= 24) 81 return false; 82 wtime->tm_hour = eft->hour; 83 84 if (!eft->day || eft->day > 31) 85 return false; 86 wtime->tm_mday = eft->day; 87 88 if (!eft->month || eft->month > 12) 89 return false; 90 wtime->tm_mon = eft->month - 1; 91 92 if (eft->year < 1900 || eft->year > 9999) 93 return false; 94 wtime->tm_year = eft->year - 1900; 95 96 /* day in the year [1-365]*/ 97 wtime->tm_yday = compute_yday(eft); 98 99 /* day of the week [0-6], Sunday=0 */ 100 wtime->tm_wday = compute_wday(eft, wtime->tm_yday); 101 102 switch (eft->daylight & EFI_ISDST) { 103 case EFI_ISDST: 104 wtime->tm_isdst = 1; 105 break; 106 case EFI_TIME_ADJUST_DAYLIGHT: 107 wtime->tm_isdst = 0; 108 break; 109 default: 110 wtime->tm_isdst = -1; 111 } 112 113 return true; 114 } 115 116 static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) 117 { 118 efi_time_t eft; 119 efi_status_t status; 120 121 memset(&eft, 0, sizeof(eft)); 122 status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled, 123 (efi_bool_t *)&wkalrm->pending, &eft); 124 if (status != EFI_SUCCESS) 125 return -EINVAL; 126 127 if (!convert_from_efi_time(&eft, &wkalrm->time)) 128 return -EIO; 129 130 return rtc_valid_tm(&wkalrm->time); 131 } 132 133 static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) 134 { 135 efi_time_t eft; 136 efi_status_t status; 137 138 convert_to_efi_time(&wkalrm->time, &eft); 139 140 status = efi.set_wakeup_time((efi_bool_t)!!wkalrm->enabled, &eft); 141 142 return status == EFI_SUCCESS ? 0 : -EINVAL; 143 } 144 145 static int efi_read_time(struct device *dev, struct rtc_time *tm) 146 { 147 efi_status_t status; 148 efi_time_t eft; 149 efi_time_cap_t cap; 150 151 status = efi.get_time(&eft, &cap); 152 153 if (status != EFI_SUCCESS) { 154 /* should never happen */ 155 dev_err_once(dev, "can't read time\n"); 156 return -EINVAL; 157 } 158 159 if (!convert_from_efi_time(&eft, tm)) 160 return -EIO; 161 162 return 0; 163 } 164 165 static int efi_set_time(struct device *dev, struct rtc_time *tm) 166 { 167 efi_status_t status; 168 efi_time_t eft; 169 170 convert_to_efi_time(tm, &eft); 171 172 status = efi.set_time(&eft); 173 174 return status == EFI_SUCCESS ? 0 : -EINVAL; 175 } 176 177 static int efi_procfs(struct device *dev, struct seq_file *seq) 178 { 179 efi_time_t eft, alm; 180 efi_time_cap_t cap; 181 efi_bool_t enabled, pending; 182 struct rtc_device *rtc = dev_get_drvdata(dev); 183 184 memset(&eft, 0, sizeof(eft)); 185 memset(&alm, 0, sizeof(alm)); 186 memset(&cap, 0, sizeof(cap)); 187 188 efi.get_time(&eft, &cap); 189 if (test_bit(RTC_FEATURE_ALARM, rtc->features) && 190 efi.get_wakeup_time(&enabled, &pending, &alm) != EFI_SUCCESS) { 191 enabled = 0; 192 pending = 0; 193 } 194 195 seq_printf(seq, 196 "Time\t\t: %u:%u:%u.%09u\n" 197 "Date\t\t: %u-%u-%u\n" 198 "Daylight\t: %u\n", 199 eft.hour, eft.minute, eft.second, eft.nanosecond, 200 eft.year, eft.month, eft.day, 201 eft.daylight); 202 203 if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) 204 seq_puts(seq, "Timezone\t: unspecified\n"); 205 else 206 /* XXX fixme: convert to string? */ 207 seq_printf(seq, "Timezone\t: %u\n", eft.timezone); 208 209 if (test_bit(RTC_FEATURE_ALARM, rtc->features)) { 210 seq_printf(seq, 211 "Alarm Time\t: %u:%u:%u.%09u\n" 212 "Alarm Date\t: %u-%u-%u\n" 213 "Alarm Daylight\t: %u\n" 214 "Enabled\t\t: %s\n" 215 "Pending\t\t: %s\n", 216 alm.hour, alm.minute, alm.second, alm.nanosecond, 217 alm.year, alm.month, alm.day, 218 alm.daylight, 219 enabled == 1 ? "yes" : "no", 220 pending == 1 ? "yes" : "no"); 221 222 if (alm.timezone == EFI_UNSPECIFIED_TIMEZONE) 223 seq_puts(seq, "Alarm Timezone\t: unspecified\n"); 224 else 225 seq_printf(seq, "Alarm Timezone\t: %d\n", alm.timezone); 226 } 227 228 /* 229 * now prints the capabilities 230 */ 231 seq_printf(seq, 232 "Resolution\t: %u\n" 233 "Accuracy\t: %u\n" 234 "SetstoZero\t: %u\n", 235 cap.resolution, cap.accuracy, cap.sets_to_zero); 236 237 return 0; 238 } 239 240 static const struct rtc_class_ops efi_rtc_ops = { 241 .read_time = efi_read_time, 242 .set_time = efi_set_time, 243 .read_alarm = efi_read_alarm, 244 .set_alarm = efi_set_alarm, 245 .proc = efi_procfs, 246 }; 247 248 static int __init efi_rtc_probe(struct platform_device *dev) 249 { 250 struct rtc_device *rtc; 251 efi_time_t eft; 252 efi_time_cap_t cap; 253 efi_bool_t enabled, pending; 254 255 /* First check if the RTC is usable */ 256 if (efi.get_time(&eft, &cap) != EFI_SUCCESS) 257 return -ENODEV; 258 259 rtc = devm_rtc_allocate_device(&dev->dev); 260 if (IS_ERR(rtc)) 261 return PTR_ERR(rtc); 262 263 platform_set_drvdata(dev, rtc); 264 265 rtc->ops = &efi_rtc_ops; 266 clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); 267 268 /* 269 * The EFI_RT_SUPPORTED_WAKEUP_SERVICES bit defaults to enabled 270 * and only gets cleared when the RT_PROP table explicitly says 271 * wakeup is unsupported. Many platforms lack an RT_PROP table 272 * even though they don't implement the wakeup runtime service, 273 * so probe by actually calling GetWakeupTime() to avoid exposing 274 * a broken alarm to userspace. 275 */ 276 if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES) && 277 efi.get_wakeup_time(&enabled, &pending, &eft) == EFI_SUCCESS) { 278 set_bit(RTC_FEATURE_ALARM, rtc->features); 279 set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); 280 } else { 281 clear_bit(RTC_FEATURE_ALARM, rtc->features); 282 } 283 284 device_init_wakeup(&dev->dev, true); 285 286 return devm_rtc_register_device(rtc); 287 } 288 289 static struct platform_driver efi_rtc_driver = { 290 .driver = { 291 .name = "rtc-efi", 292 }, 293 }; 294 295 module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); 296 297 MODULE_AUTHOR("dann frazier <dannf@dannf.org>"); 298 MODULE_LICENSE("GPL"); 299 MODULE_DESCRIPTION("EFI RTC driver"); 300 MODULE_ALIAS("platform:rtc-efi"); 301