1 /* $OpenBSD: clkbrd.c,v 1.7 2021/10/24 17:05:03 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/conf.h> 31 #include <sys/device.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/sensors.h> 35 #include <sys/systm.h> 36 #include <sys/timeout.h> 37 38 #include <machine/bus.h> 39 #include <machine/autoconf.h> 40 #include <machine/openfirm.h> 41 42 #include <sparc64/dev/fhcvar.h> 43 #include <sparc64/dev/clkbrdreg.h> 44 #include <sparc64/dev/clkbrdvar.h> 45 46 int clkbrd_match(struct device *, void *, void *); 47 void clkbrd_attach(struct device *, struct device *, void *); 48 void clkbrd_led_blink(void *, int); 49 void clkbrd_refresh(void *); 50 51 const struct cfattach clkbrd_ca = { 52 sizeof(struct clkbrd_softc), clkbrd_match, clkbrd_attach 53 }; 54 55 struct cfdriver clkbrd_cd = { 56 NULL, "clkbrd", DV_DULL 57 }; 58 59 int 60 clkbrd_match(struct device *parent, void *match, void *aux) 61 { 62 struct fhc_attach_args *fa = aux; 63 64 if (strcmp(fa->fa_name, "clock-board") == 0) 65 return (1); 66 return (0); 67 } 68 69 void 70 clkbrd_attach(struct device *parent, struct device *self, void *aux) 71 { 72 struct clkbrd_softc *sc = (struct clkbrd_softc *)self; 73 struct fhc_attach_args *fa = aux; 74 int slots; 75 u_int8_t r; 76 77 sc->sc_bt = fa->fa_bustag; 78 79 if (fa->fa_nreg < 2) { 80 printf(": no registers\n"); 81 return; 82 } 83 84 if (fhc_bus_map(sc->sc_bt, fa->fa_reg[1].fbr_slot, 85 fa->fa_reg[1].fbr_offset, fa->fa_reg[1].fbr_size, 0, 86 &sc->sc_creg)) { 87 printf(": can't map ctrl regs\n"); 88 return; 89 } 90 91 if (fa->fa_nreg > 2) { 92 if (fhc_bus_map(sc->sc_bt, fa->fa_reg[2].fbr_slot, 93 fa->fa_reg[2].fbr_offset, fa->fa_reg[2].fbr_size, 0, 94 &sc->sc_vreg)) { 95 printf(": can't map vreg\n"); 96 return; 97 } 98 sc->sc_has_vreg = 1; 99 } 100 101 slots = 4; 102 r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_STS1); 103 switch (r & 0xc0) { 104 case 0x40: 105 slots = 16; 106 break; 107 case 0xc0: 108 slots = 8; 109 break; 110 case 0x80: 111 if (sc->sc_has_vreg) { 112 r = bus_space_read_1(sc->sc_bt, sc->sc_vreg, 0); 113 if (r != 0 && (r & 0x80) == 0) 114 slots = 5; 115 } 116 } 117 118 sc->sc_blink.bl_func = clkbrd_led_blink; 119 sc->sc_blink.bl_arg = sc; 120 blink_led_register(&sc->sc_blink); 121 122 /* Initialize sensor data. */ 123 strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname, 124 sizeof(sc->sc_sensordev.xname)); 125 sc->sc_sensor.type = SENSOR_TEMP; 126 127 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 128 129 if (sensor_task_register(sc, clkbrd_refresh, 5) == NULL) { 130 printf(": unable to register update task\n"); 131 return; 132 } 133 134 sensordev_install(&sc->sc_sensordev); 135 136 printf(": %d slots\n", slots); 137 } 138 139 void 140 clkbrd_led_blink(void *vsc, int on) 141 { 142 struct clkbrd_softc *sc = vsc; 143 int s; 144 u_int8_t r; 145 146 s = splhigh(); 147 r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL); 148 if (on) 149 r |= CLK_CTRL_RLED; 150 else 151 r &= ~CLK_CTRL_RLED; 152 bus_space_write_1(sc->sc_bt, sc->sc_creg, CLK_CTRL, r); 153 bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL); 154 splx(s); 155 } 156 157 /* 158 * Calibration table for temperature sensor. 159 */ 160 int8_t clkbrd_temp[] = { 161 0, 0, 0, 0, 0, 0, 0, 0, 162 0, 0, 0, 0, 1, 2, 4, 5, 163 7, 8, 10, 11, 12, 13, 14, 15, 164 17, 18, 19, 20, 21, 22, 23, 24, 165 24, 25, 26, 27, 28, 29, 29, 30, 166 31, 32, 32, 33, 34, 35, 35, 36, 167 37, 38, 38, 39, 40, 40, 41, 42, 168 42, 43, 44, 44, 45, 46, 46, 47, 169 48, 48, 49, 50, 50, 51, 52, 52, 170 53, 54, 54, 55, 56, 57, 57, 58, 171 59, 59, 60, 60, 61, 62, 63, 63, 172 64, 65, 65, 66, 67, 68, 68, 69, 173 70, 70, 71, 72, 73, 74, 74, 75, 174 76, 77, 78, 78, 79, 80, 81, 82 175 }; 176 177 const int8_t clkbrd_temp_warn = 60; 178 const int8_t clkbrd_temp_crit = 68; 179 180 void 181 clkbrd_refresh(void *arg) 182 { 183 struct clkbrd_softc *sc = arg; 184 u_int8_t val; 185 int8_t temp; 186 187 val = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_TEMP); 188 if (val == 0xff) { 189 sc->sc_sensor.flags |= SENSOR_FINVALID; 190 return; 191 } 192 193 if (val < sizeof(clkbrd_temp)) 194 temp = clkbrd_temp[val]; 195 else 196 temp = clkbrd_temp[sizeof(clkbrd_temp) - 1]; 197 198 sc->sc_sensor.value = val * 1000000 + 273150000; 199 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 200 sc->sc_sensor.status = SENSOR_S_OK; 201 if (temp >= clkbrd_temp_warn) 202 sc->sc_sensor.status = SENSOR_S_WARN; 203 if (temp >= clkbrd_temp_crit) 204 sc->sc_sensor.status = SENSOR_S_CRIT; 205 } 206