1 /*- 2 * Copyright (c) 2017 Andrew Turner 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 #include <sys/clock.h> 38 #include <sys/efi.h> 39 #include <sys/kernel.h> 40 #include <sys/module.h> 41 42 #include "clock_if.h" 43 44 static void 45 efirtc_identify(driver_t *driver, device_t parent) 46 { 47 struct efi_tm tm; 48 int error; 49 50 /* 51 * Check if we can read the time. This will stop us attaching when 52 * there is no EFI Runtime support, or the gettime function is 53 * unimplemented, e.g. on some builds of U-Boot. 54 */ 55 error = efi_get_time(&tm); 56 if (error != 0) 57 return; 58 59 if (device_find_child(parent, "efirtc", -1) != NULL) 60 return; 61 if (BUS_ADD_CHILD(parent, 0, "efirtc", -1) == NULL) 62 device_printf(parent, "add child failed\n"); 63 } 64 65 static int 66 efirtc_probe(device_t dev) 67 { 68 69 device_quiet(dev); 70 return (0); 71 } 72 73 static int 74 efirtc_attach(device_t dev) 75 { 76 77 clock_register(dev, 1000000); 78 return (0); 79 } 80 81 static int 82 efirtc_detach(device_t dev) 83 { 84 85 clock_unregister(dev); 86 return (0); 87 } 88 89 static int 90 efirtc_gettime(device_t dev, struct timespec *ts) 91 { 92 struct clocktime ct; 93 struct efi_tm tm; 94 int error; 95 96 error = efi_get_time(&tm); 97 if (error != 0) 98 return (error); 99 100 ct.sec = tm.tm_sec; 101 ct.min = tm.tm_min; 102 ct.hour = tm.tm_hour; 103 ct.day = tm.tm_mday; 104 ct.mon = tm.tm_mon; 105 ct.year = tm.tm_year; 106 ct.nsec = tm.tm_nsec; 107 108 return (clock_ct_to_ts(&ct, ts)); 109 } 110 111 static int 112 efirtc_settime(device_t dev, struct timespec *ts) 113 { 114 struct clocktime ct; 115 struct efi_tm tm; 116 117 clock_ts_to_ct(ts, &ct); 118 119 bzero(&tm, sizeof(tm)); 120 tm.tm_sec = ct.sec; 121 tm.tm_min = ct.min; 122 tm.tm_hour = ct.hour; 123 tm.tm_mday = ct.day; 124 tm.tm_mon = ct.mon; 125 tm.tm_year = ct.year; 126 tm.tm_nsec = ct.nsec; 127 128 return (efi_set_time(&tm)); 129 } 130 131 static device_method_t efirtc_methods[] = { 132 /* Device interface */ 133 DEVMETHOD(device_identify, efirtc_identify), 134 DEVMETHOD(device_probe, efirtc_probe), 135 DEVMETHOD(device_attach, efirtc_attach), 136 DEVMETHOD(device_detach, efirtc_detach), 137 138 /* Clock interface */ 139 DEVMETHOD(clock_gettime, efirtc_gettime), 140 DEVMETHOD(clock_settime, efirtc_settime), 141 142 DEVMETHOD_END 143 }; 144 145 static devclass_t efirtc_devclass; 146 static driver_t efirtc_driver = { 147 "efirtc", 148 efirtc_methods, 149 0 150 }; 151 152 DRIVER_MODULE(efirtc, nexus, efirtc_driver, efirtc_devclass, 0, 0); 153