1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2024 Bojan Novković <bnovkov@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * Driver for cvitek's poweroff/restart controller. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/types.h> 35 #include <sys/eventhandler.h> 36 #include <sys/kernel.h> 37 #include <sys/module.h> 38 #include <sys/reboot.h> 39 #include <sys/rman.h> 40 41 #include <machine/bus.h> 42 #include <machine/resource.h> 43 44 #include <dev/ofw/ofw_bus.h> 45 #include <dev/ofw/ofw_bus_subr.h> 46 #include <dev/ofw/openfirm.h> 47 48 #define RTC_CTRL0_UNLOCK 0x4 49 #define RTC_CTRL0_UNLOCK_KEY 0xAB18 50 51 #define RTC_CTRL0 0x8 52 #define RTC_CTRL0_RESERVED_MASK 0xFFFF0800 53 #define RTC_CTRL0_REQ_SHUTDOWN 0x01 54 #define RTC_CTRL0_REQ_POWERCYCLE 0x08 55 #define RTC_CTRL0_REQ_WARM_RESET 0x10 56 57 #define RTC_BASE_OFFSET 0x1000 58 #define RTC_EN_SHDN_REQ (RTC_BASE_OFFSET + 0xC0) 59 #define RTC_EN_PWR_CYC_REQ (RTC_BASE_OFFSET + 0xC8) 60 #define RTC_EN_WARM_RST_REQ (RTC_BASE_OFFSET + 0xCC) 61 62 struct cvitek_restart_softc { 63 int reg_rid; 64 struct resource *reg; 65 eventhandler_tag tag; 66 }; 67 68 static void 69 cvitek_restart_shutdown_final(device_t dev, int howto) 70 { 71 struct cvitek_restart_softc *sc; 72 uint32_t val; 73 74 sc = device_get_softc(dev); 75 val = RTC_CTRL0_RESERVED_MASK; 76 if ((howto & RB_POWEROFF) != 0) 77 val |= RTC_CTRL0_REQ_SHUTDOWN; 78 else if ((howto & RB_POWERCYCLE) != 0) 79 val |= RTC_CTRL0_REQ_POWERCYCLE; 80 else 81 val |= RTC_CTRL0_REQ_WARM_RESET; 82 83 /* Unlock writes to 'rtc_ctrl0'. */ 84 bus_write_4(sc->reg, RTC_CTRL0_UNLOCK, RTC_CTRL0_UNLOCK_KEY); 85 bus_write_4(sc->reg, RTC_CTRL0, val); 86 DELAY(1000); 87 88 device_printf(dev, "Poweroff request failed\n"); 89 } 90 91 static int 92 cvitek_restart_probe(device_t dev) 93 { 94 95 if (!ofw_bus_status_okay(dev)) 96 return (ENXIO); 97 98 if (ofw_bus_is_compatible(dev, "cvitek,restart")) { 99 device_set_desc(dev, "Cvitek restart controller"); 100 return (BUS_PROBE_DEFAULT); 101 } 102 return (ENXIO); 103 } 104 105 static int 106 cvitek_restart_attach(device_t dev) 107 { 108 struct cvitek_restart_softc *sc; 109 110 sc = device_get_softc(dev); 111 sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->reg_rid, 112 RF_ACTIVE); 113 if (sc->reg == NULL) { 114 device_printf(dev, "can't map RTC regs\n"); 115 return (ENXIO); 116 } 117 118 /* Enable requests for various poweroff methods. */ 119 bus_write_4(sc->reg, RTC_EN_SHDN_REQ, 0x1); 120 bus_write_4(sc->reg, RTC_EN_PWR_CYC_REQ, 0x1); 121 bus_write_4(sc->reg, RTC_EN_WARM_RST_REQ, 0x1); 122 123 sc->tag = EVENTHANDLER_REGISTER(shutdown_final, 124 cvitek_restart_shutdown_final, dev, SHUTDOWN_PRI_LAST); 125 126 return (0); 127 } 128 129 static int 130 cvitek_restart_detach(device_t dev) 131 { 132 struct cvitek_restart_softc *sc; 133 134 sc = device_get_softc(dev); 135 if (sc->reg == NULL) 136 return (0); 137 138 bus_write_4(sc->reg, RTC_EN_SHDN_REQ, 0x0); 139 bus_write_4(sc->reg, RTC_EN_PWR_CYC_REQ, 0x0); 140 bus_write_4(sc->reg, RTC_EN_WARM_RST_REQ, 0x0); 141 142 bus_release_resource(dev, SYS_RES_MEMORY, sc->reg_rid, sc->reg); 143 EVENTHANDLER_DEREGISTER(shutdown_final, sc->tag); 144 145 return (0); 146 } 147 148 static device_method_t cvitek_restart_methods[] = { 149 DEVMETHOD(device_probe, cvitek_restart_probe), 150 DEVMETHOD(device_attach, cvitek_restart_attach), 151 DEVMETHOD(device_detach, cvitek_restart_detach), 152 153 DEVMETHOD_END 154 }; 155 156 DEFINE_CLASS_0(cvitek_restart, cvitek_restart_driver, cvitek_restart_methods, 157 sizeof(struct cvitek_restart_softc)); 158 DRIVER_MODULE(cvitek_restart, simplebus, cvitek_restart_driver, NULL, NULL); 159