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