1 1.1 jdc /* $NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $ */ 2 1.1 jdc 3 1.1 jdc /*- 4 1.1 jdc * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 1.1 jdc * All rights reserved. 6 1.1 jdc * 7 1.1 jdc * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdc * by Julian Coleman. 9 1.1 jdc * 10 1.1 jdc * Redistribution and use in source and binary forms, with or without 11 1.1 jdc * modification, are permitted provided that the following conditions 12 1.1 jdc * are met: 13 1.1 jdc * 1. Redistributions of source code must retain the above copyright 14 1.1 jdc * notice, this list of conditions and the following disclaimer. 15 1.1 jdc * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdc * notice, this list of conditions and the following disclaimer in the 17 1.1 jdc * documentation and/or other materials provided with the distribution. 18 1.1 jdc * 19 1.1 jdc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jdc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jdc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jdc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jdc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jdc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jdc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jdc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jdc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jdc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jdc * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jdc */ 31 1.1 jdc 32 1.1 jdc #include <sys/cdefs.h> 33 1.1 jdc __KERNEL_RCSID(0, "$NetBSD: envmon_ebus.c,v 1.1 2026/09/07 07:35:13 jdc Exp $"); 34 1.1 jdc 35 1.1 jdc #include <sys/param.h> 36 1.1 jdc #include <sys/kernel.h> 37 1.1 jdc #include <sys/device.h> 38 1.1 jdc #include <sys/proc.h> 39 1.1 jdc #include <sys/types.h> 40 1.1 jdc 41 1.1 jdc #include <sys/bus.h> 42 1.1 jdc #include <machine/autoconf.h> 43 1.1 jdc 44 1.1 jdc #include <dev/ebus/ebusreg.h> 45 1.1 jdc #include <dev/ebus/ebusvar.h> 46 1.1 jdc 47 1.1 jdc #include <dev/led.h> 48 1.1 jdc #include <dev/sysmon/sysmonvar.h> 49 1.1 jdc 50 1.1 jdc #include <arch/sparc64/dev/envmon_ebusreg.h> 51 1.1 jdc 52 1.1 jdc #define ENVMON_MACHINE_U25 0x19 53 1.1 jdc #define ENVMON_MACHINE_U45 0x2d 54 1.1 jdc #define ENVMON_MACHINE_V215 0xd7 55 1.1 jdc #define ENVMON_MACHINE_V245 0xf5 56 1.1 jdc 57 1.1 jdc #define ENVMON_PIC_MAX_TEMPS 1 58 1.1 jdc #define ENVMON_PIC_WMIN_TEMP 273150000 /* 0C from Solaris */ 59 1.1 jdc #define ENVMON_PIC_WMAX_TEMP 318150000 /* 45C from Solaris */ 60 1.1 jdc #define ENVMON_PIC_CRIT_TEMP 338150000 /* 65C from Solaris */ 61 1.1 jdc 62 1.1 jdc struct envmon_epic_fans { 63 1.1 jdc const uint8_t reg; 64 1.1 jdc const char *desc; 65 1.1 jdc }; 66 1.1 jdc static struct envmon_epic_fans envmon_epic_fans_table[] = { 67 1.1 jdc { ENVMON_EPC_FAN_FT0_F0, "FT0.F0" }, 68 1.1 jdc { ENVMON_EPC_FAN_FT1_F0, "FT1.F0" }, 69 1.1 jdc { ENVMON_EPC_FAN_FT2_F0, "FT2.F0" }, 70 1.1 jdc { ENVMON_EPC_FAN_FT3_F0, "FT3.F0" }, 71 1.1 jdc { ENVMON_EPC_FAN_FT4_F0, "FT4.F0" }, 72 1.1 jdc { ENVMON_EPC_FAN_FT5_F0, "FT5.F0" }, 73 1.1 jdc { ENVMON_EPC_FAN_FT0_F1, "FT0.F1" }, 74 1.1 jdc { ENVMON_EPC_FAN_FT1_F1, "FT1.F1" }, 75 1.1 jdc { ENVMON_EPC_FAN_FT2_F1, "FT2.F1" }, 76 1.1 jdc { ENVMON_EPC_FAN_FT3_F1, "FT3.F1" }, 77 1.1 jdc { ENVMON_EPC_FAN_FT4_F1, "FT4.F1" }, 78 1.1 jdc { ENVMON_EPC_FAN_FT5_F1, "FT5.F1" }, 79 1.1 jdc }; 80 1.1 jdc #define ENVMON_EPC_MAX_FANS (sizeof(envmon_epic_fans_table) / \ 81 1.1 jdc sizeof(envmon_epic_fans_table[0])) 82 1.1 jdc #define ENVMON_EPC_DIV_V245 5625 83 1.1 jdc #define ENVMON_EPC_DIV_V215 11250 84 1.1 jdc #define ENVMON_EPC_CRIT_SPEED_V245 2022 /* From ALOM */ 85 1.1 jdc #define ENVMON_EPC_CRIT_SPEED_V215 5012 /* From ALOM */ 86 1.1 jdc #define ENVMON_EPC_WMIN_TEMP 273150000 /* 0C from ALOM */ 87 1.1 jdc #define ENVMON_EPC_WMAX_TEMP 318150000 /* 45C from ALOM */ 88 1.1 jdc #define ENVMON_EPC_CRIT_TEMP 323150000 /* 50C from ALOM */ 89 1.1 jdc #define ENVMON_EPC_VAL_TO_SPEED(div, val) ((div * 60) / val) 90 1.1 jdc 91 1.1 jdc #define ENVMON_EPC_MAX_FAULTS 1 92 1.1 jdc 93 1.1 jdc #define ENVMON_EPC_MAX_TEMPS 1 94 1.1 jdc 95 1.1 jdc struct envmon_epic_ind { 96 1.1 jdc uint8_t reg, set; 97 1.1 jdc const char *desc; 98 1.1 jdc }; 99 1.1 jdc static struct envmon_epic_ind envmon_epic_inds_table[] = { 100 1.1 jdc { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_NORM, "keyswitch normal/diag" }, 101 1.1 jdc { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_LOCK, "keyswitch locked" }, 102 1.1 jdc }; 103 1.1 jdc 104 1.1 jdc #define ENVMON_EPC_MAX_INDS (sizeof(envmon_epic_inds_table) / \ 105 1.1 jdc sizeof(envmon_epic_inds_table[0])) 106 1.1 jdc 107 1.1 jdc struct envmon_epic_led { 108 1.1 jdc uint8_t reg, v_on; 109 1.1 jdc const char *desc; 110 1.1 jdc }; 111 1.1 jdc static struct envmon_epic_led envmon_epic_led_table[] = { 112 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_LOC, "locator" }, 113 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV, "service" }, 114 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV_FSH, "service_flash" }, 115 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_PWR, "power" }, 116 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT, "top_fan_fault" }, 117 1.1 jdc { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT_FSH, "top_fan_fault_flash" }, 118 1.1 jdc { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU, "psu_fault" }, 119 1.1 jdc { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU_FSH, "psu_fault_flash" }, 120 1.1 jdc { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP, "cpu_overtemp" }, 121 1.1 jdc { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP_FSH, "cpu_overtemp_flash" }, 122 1.1 jdc }; 123 1.1 jdc #define ENVMON_EPC_MAX_LEDS (sizeof(envmon_epic_led_table) / \ 124 1.1 jdc sizeof(envmon_epic_led_table[0])) 125 1.1 jdc 126 1.1 jdc #define ENVMON_EPC_MAX_SENSORS \ 127 1.1 jdc (ENVMON_EPC_MAX_FANS + ENVMON_EPC_MAX_FAULTS + \ 128 1.1 jdc ENVMON_EPC_MAX_TEMPS + ENVMON_EPC_MAX_INDS) 129 1.1 jdc 130 1.1 jdc #define ENVMON_MAX_TEMPS \ 131 1.1 jdc MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_TEMPS) 132 1.1 jdc #define ENVMON_MAX_SENSORS \ 133 1.1 jdc MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_SENSORS) 134 1.1 jdc 135 1.1 jdc struct envmon_sc_fan { 136 1.1 jdc uint8_t reg; 137 1.1 jdc int cmin; 138 1.1 jdc }; 139 1.1 jdc 140 1.1 jdc struct envmon_sc_temp { 141 1.1 jdc uint8_t reg; 142 1.1 jdc int wmin, wmax, cmax; 143 1.1 jdc }; 144 1.1 jdc 145 1.1 jdc struct envmon_sc_ind { 146 1.1 jdc uint8_t reg, set; 147 1.1 jdc }; 148 1.1 jdc struct envmon_sc_led { 149 1.1 jdc void *cookie; 150 1.1 jdc struct led_device *led; 151 1.1 jdc uint8_t reg, v_on; 152 1.1 jdc }; 153 1.1 jdc 154 1.1 jdc struct envmon_softc { 155 1.1 jdc device_t sc_dev; 156 1.1 jdc 157 1.1 jdc bus_space_tag_t sc_bst; 158 1.1 jdc bus_space_handle_t sc_bsh; 159 1.1 jdc 160 1.1 jdc int sc_machine_type, sc_nfans; 161 1.1 jdc struct envmon_sc_fan sc_fan[ENVMON_EPC_MAX_FANS]; 162 1.1 jdc struct envmon_sc_temp sc_temp[ENVMON_MAX_TEMPS]; 163 1.1 jdc struct envmon_sc_ind sc_ind[ENVMON_EPC_MAX_INDS]; 164 1.1 jdc struct envmon_sc_led sc_led[ENVMON_EPC_MAX_LEDS]; 165 1.1 jdc struct sysmon_envsys *sc_sme; 166 1.1 jdc envsys_data_t sc_sensor[ENVMON_MAX_SENSORS]; 167 1.1 jdc 168 1.1 jdc #ifdef ENVMON_DEBUG 169 1.1 jdc #define ENVMON_MAX_REG 0x3d 170 1.1 jdc uint8_t sc_reg[ENVMON_MAX_REG]; 171 1.1 jdc #define ENVMON_TIMER 60 172 1.1 jdc callout_t sc_timer; 173 1.1 jdc #endif 174 1.1 jdc }; 175 1.1 jdc 176 1.1 jdc static int envmon_ebus_match(device_t, cfdata_t, void *); 177 1.1 jdc static void envmon_ebus_attach(device_t, device_t, void *); 178 1.1 jdc static void envmon_pic_attach(struct envmon_softc *, int); 179 1.1 jdc static void envmon_epic_attach(struct envmon_softc *, int); 180 1.1 jdc void envmon_pic_refresh(struct sysmon_envsys *, envsys_data_t *); 181 1.1 jdc void envmon_epic_refresh(struct sysmon_envsys *, envsys_data_t *); 182 1.1 jdc void envmon_epic_refresh_fan(struct envmon_softc *, envsys_data_t *); 183 1.1 jdc void envmon_epic_refresh_fault(struct envmon_softc *, envsys_data_t *); 184 1.1 jdc void envmon_refresh_temp(struct envmon_softc *, envsys_data_t *); 185 1.1 jdc void envmon_epic_refresh_ind(struct envmon_softc *, envsys_data_t *); 186 1.1 jdc void envmon_pic_get_limits(struct sysmon_envsys *, envsys_data_t *, 187 1.1 jdc sysmon_envsys_lim_t *, uint32_t *); 188 1.1 jdc void envmon_pic_set_limits(struct sysmon_envsys *, envsys_data_t *, 189 1.1 jdc sysmon_envsys_lim_t *, uint32_t *); 190 1.1 jdc void envmon_epic_get_limits(struct sysmon_envsys *, envsys_data_t *, 191 1.1 jdc sysmon_envsys_lim_t *, uint32_t *); 192 1.1 jdc void envmon_epic_set_limits(struct sysmon_envsys *, envsys_data_t *, 193 1.1 jdc sysmon_envsys_lim_t *, uint32_t *); 194 1.1 jdc static void envmon_epic_get_fan_limits(struct envmon_softc *, 195 1.1 jdc envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 196 1.1 jdc static void envmon_get_temp_limits(struct envmon_softc *, 197 1.1 jdc envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 198 1.1 jdc static void envmon_epic_set_fan_limits(struct envmon_softc *, 199 1.1 jdc envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 200 1.1 jdc static void envmon_set_temp_limits(struct envmon_softc *, 201 1.1 jdc envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); 202 1.1 jdc int envmon_epic_get_led(void *); 203 1.1 jdc void envmon_epic_set_led(void *, int); 204 1.1 jdc #ifdef ENVMON_DEBUG 205 1.1 jdc static void envmon_timeout(void *); 206 1.1 jdc #endif 207 1.1 jdc 208 1.1 jdc CFATTACH_DECL_NEW(envmon_ebus, sizeof(struct envmon_softc), 209 1.1 jdc envmon_ebus_match, envmon_ebus_attach, NULL, NULL); 210 1.1 jdc 211 1.1 jdc #define envmon_read(sc, reg) \ 212 1.1 jdc bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg) 213 1.1 jdc #define envmon_write(sc, reg, val) \ 214 1.1 jdc bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val) 215 1.1 jdc 216 1.1 jdc static int 217 1.1 jdc envmon_ebus_match(device_t parent, cfdata_t cf, void *aux) 218 1.1 jdc { 219 1.1 jdc struct ebus_attach_args *ea = aux; 220 1.1 jdc char *compat; 221 1.1 jdc 222 1.1 jdc if (strcmp("env-monitor", ea->ea_name) != 0) 223 1.1 jdc return 0; 224 1.1 jdc 225 1.1 jdc compat = prom_getpropstring(ea->ea_node, "compatible"); 226 1.1 jdc if (compat != NULL && (!strcmp(compat, "SUNW,ebus-pic16f747-env") || 227 1.1 jdc !strcmp(compat, "epic"))) 228 1.1 jdc return 1; 229 1.1 jdc 230 1.1 jdc return 0; 231 1.1 jdc } 232 1.1 jdc 233 1.1 jdc static void 234 1.1 jdc envmon_ebus_attach(device_t parent, device_t self, void *aux) 235 1.1 jdc { 236 1.1 jdc struct envmon_softc *sc = device_private(self); 237 1.1 jdc struct ebus_attach_args *ea = aux; 238 1.1 jdc char compat[32]; 239 1.1 jdc int sz; 240 1.1 jdc #ifdef ENVMON_DEBUG 241 1.1 jdc uint8_t reg; 242 1.1 jdc #endif 243 1.1 jdc 244 1.1 jdc sc->sc_dev = self; 245 1.1 jdc sc->sc_bst = ea->ea_bustag; 246 1.1 jdc 247 1.1 jdc sz = ea->ea_reg[0].size; 248 1.1 jdc 249 1.1 jdc if (bus_space_map(sc->sc_bst, 250 1.1 jdc EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 251 1.1 jdc sz, 0, 252 1.1 jdc &sc->sc_bsh) != 0) { 253 1.1 jdc aprint_error(": can't map register\n"); 254 1.1 jdc return; 255 1.1 jdc } 256 1.1 jdc 257 1.1 jdc sc->sc_sme = sysmon_envsys_create(); 258 1.1 jdc sc->sc_sme->sme_name = device_xname(self); 259 1.1 jdc sc->sc_sme->sme_cookie = sc; 260 1.1 jdc 261 1.1 jdc OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)); 262 1.1 jdc 263 1.1 jdc if (!strcmp(compat, "SUNW,ebus-pic16f747-env")) { 264 1.1 jdc envmon_pic_attach(sc, ea->ea_node); 265 1.1 jdc } 266 1.1 jdc if (!strcmp(compat, "epic")) { 267 1.1 jdc envmon_epic_attach(sc, ea->ea_node); 268 1.1 jdc } 269 1.1 jdc 270 1.1 jdc #ifdef ENVMON_DEBUG 271 1.1 jdc for (reg = 0; reg < ENVMON_MAX_REG; reg++) { 272 1.1 jdc envmon_write(sc, ENVMON_ADDR, reg); 273 1.1 jdc sc->sc_reg[reg] = envmon_read(sc, ENVMON_DATA); 274 1.1 jdc } 275 1.1 jdc callout_init(&sc->sc_timer, CALLOUT_MPSAFE); 276 1.1 jdc callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); 277 1.1 jdc #endif 278 1.1 jdc } 279 1.1 jdc 280 1.1 jdc /* 281 1.1 jdc * We only add the front panel temperature here. 282 1.1 jdc * Other U45 sensors are handled by the ADT7462 driver. 283 1.1 jdc */ 284 1.1 jdc static void 285 1.1 jdc envmon_pic_attach(struct envmon_softc *sc, int node) 286 1.1 jdc { 287 1.1 jdc int32_t vers; 288 1.1 jdc 289 1.1 jdc vers = prom_getpropint(node, "version", 0); 290 1.1 jdc aprint_normal(": pic16f747 (ver. %d)\n", vers); 291 1.1 jdc 292 1.1 jdc if (!strcmp(machine_model, "SUNW,A70")) { 293 1.1 jdc sc->sc_machine_type = ENVMON_MACHINE_U45; 294 1.1 jdc } else if (!strcmp(machine_model, "SUNW,Ultra-25")) { 295 1.1 jdc sc->sc_machine_type = ENVMON_MACHINE_U25; 296 1.1 jdc } else { 297 1.1 jdc aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); 298 1.1 jdc return; 299 1.1 jdc } 300 1.1 jdc 301 1.1 jdc sc->sc_sme->sme_refresh = envmon_pic_refresh; 302 1.1 jdc sc->sc_sme->sme_get_limits = envmon_pic_get_limits; 303 1.1 jdc sc->sc_sme->sme_set_limits = envmon_pic_set_limits; 304 1.1 jdc 305 1.1 jdc strlcpy(sc->sc_sensor[0].desc, "Front_panel", 306 1.1 jdc sizeof(sc->sc_sensor[0].desc)); 307 1.1 jdc sc->sc_sensor[0].units = ENVSYS_STEMP; 308 1.1 jdc sc->sc_sensor[0].state = ENVSYS_SINVALID; 309 1.1 jdc sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS | 310 1.1 jdc ENVSYS_FMONCRITICAL; 311 1.1 jdc sc->sc_temp[0].reg = ENVMON_PIC_TEMP_FP; 312 1.1 jdc sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP; 313 1.1 jdc sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP; 314 1.1 jdc sc->sc_temp[0].cmax = ENVMON_PIC_CRIT_TEMP; 315 1.1 jdc if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0])) { 316 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 317 1.1 jdc sc->sc_sme = NULL; 318 1.1 jdc aprint_error_dev(sc->sc_dev, 319 1.1 jdc "unable to attach sensor to sysmon\n"); 320 1.1 jdc return; 321 1.1 jdc } 322 1.1 jdc 323 1.1 jdc if (sysmon_envsys_register(sc->sc_sme)) { 324 1.1 jdc aprint_error_dev(sc->sc_dev, 325 1.1 jdc "unable to register with sysmon\n"); 326 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 327 1.1 jdc sc->sc_sme = NULL; 328 1.1 jdc return; 329 1.1 jdc } 330 1.1 jdc 331 1.1 jdc return; 332 1.1 jdc } 333 1.1 jdc 334 1.1 jdc static void 335 1.1 jdc envmon_epic_attach(struct envmon_softc *sc, int node) 336 1.1 jdc { 337 1.1 jdc const char *vers; 338 1.1 jdc int cmin, i, j; 339 1.1 jdc 340 1.1 jdc vers = prom_getpropstring(node, "version"); 341 1.1 jdc aprint_normal(": epic (ver. %s)\n", vers); 342 1.1 jdc 343 1.1 jdc /* Fans */ 344 1.1 jdc if (!strcmp(machine_model, "SUNW,Sun-Fire-V245")) { 345 1.1 jdc sc->sc_machine_type = ENVMON_MACHINE_V245; 346 1.1 jdc sc->sc_nfans = 6; 347 1.1 jdc cmin = ENVMON_EPC_CRIT_SPEED_V245; 348 1.1 jdc } else if (!strcmp(machine_model, "SUNW,Sun-Fire-V215")) { 349 1.1 jdc sc->sc_machine_type = ENVMON_MACHINE_V215; 350 1.1 jdc sc->sc_nfans = 12; 351 1.1 jdc cmin = ENVMON_EPC_CRIT_SPEED_V215; 352 1.1 jdc } else { 353 1.1 jdc aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); 354 1.1 jdc return; 355 1.1 jdc } 356 1.1 jdc 357 1.1 jdc sc->sc_sme->sme_refresh = envmon_epic_refresh; 358 1.1 jdc sc->sc_sme->sme_get_limits = envmon_epic_get_limits; 359 1.1 jdc sc->sc_sme->sme_set_limits = envmon_epic_set_limits; 360 1.1 jdc 361 1.1 jdc for (i = 0; i < sc->sc_nfans; i++) { 362 1.1 jdc strlcpy(sc->sc_sensor[i].desc, envmon_epic_fans_table[i].desc, 363 1.1 jdc sizeof(sc->sc_sensor[i].desc)); 364 1.1 jdc sc->sc_sensor[i].units = ENVSYS_SFANRPM; 365 1.1 jdc sc->sc_sensor[i].state = ENVSYS_SINVALID; 366 1.1 jdc sc->sc_sensor[i].flags = ENVSYS_FMONLIMITS | 367 1.1 jdc ENVSYS_FMONCRITICAL; 368 1.1 jdc sc->sc_fan[i].reg = envmon_epic_fans_table[i].reg; 369 1.1 jdc sc->sc_fan[i].cmin = cmin; 370 1.1 jdc if (sysmon_envsys_sensor_attach(sc->sc_sme, 371 1.1 jdc &sc->sc_sensor[i])) { 372 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 373 1.1 jdc sc->sc_sme = NULL; 374 1.1 jdc aprint_error_dev(sc->sc_dev, 375 1.1 jdc "unable to attach sensor to sysmon\n"); 376 1.1 jdc goto leds; 377 1.1 jdc } 378 1.1 jdc } 379 1.1 jdc 380 1.1 jdc /* Fan fault */ 381 1.1 jdc i = sc->sc_nfans; 382 1.1 jdc strlcpy(sc->sc_sensor[i].desc, "fan fault", 383 1.1 jdc sizeof(sc->sc_sensor[i].desc)); 384 1.1 jdc sc->sc_sensor[i].units = ENVSYS_INTEGER; 385 1.1 jdc sc->sc_sensor[i].state = ENVSYS_SINVALID; 386 1.1 jdc sc->sc_sensor[i].flags = ENVSYS_FMONCRITICAL; 387 1.1 jdc if (sysmon_envsys_sensor_attach( 388 1.1 jdc sc->sc_sme, &sc->sc_sensor[i])) { 389 1.1 jdc aprint_error_dev(sc->sc_dev, 390 1.1 jdc "unable to attach fan fault at sysmon\n"); 391 1.1 jdc goto leds; 392 1.1 jdc } 393 1.1 jdc i++; 394 1.1 jdc 395 1.1 jdc /* Temperature */ 396 1.1 jdc strlcpy(sc->sc_sensor[i].desc, "FIOB.T_AMB", 397 1.1 jdc sizeof(sc->sc_sensor[i].desc)); 398 1.1 jdc sc->sc_sensor[i].units = ENVSYS_STEMP; 399 1.1 jdc sc->sc_sensor[i].state = ENVSYS_SINVALID; 400 1.1 jdc sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONLIMITS | 401 1.1 jdc ENVSYS_FMONCRITICAL; 402 1.1 jdc sc->sc_temp[0].reg = ENVMON_EPC_TEMP_FP; 403 1.1 jdc sc->sc_temp[0].wmin = ENVMON_EPC_WMIN_TEMP; 404 1.1 jdc sc->sc_temp[0].wmax = ENVMON_EPC_WMAX_TEMP; 405 1.1 jdc sc->sc_temp[0].cmax = ENVMON_EPC_CRIT_TEMP; 406 1.1 jdc if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) { 407 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 408 1.1 jdc sc->sc_sme = NULL; 409 1.1 jdc aprint_error_dev(sc->sc_dev, 410 1.1 jdc "unable to attach sensor to sysmon\n"); 411 1.1 jdc goto leds; 412 1.1 jdc } 413 1.1 jdc i++; 414 1.1 jdc 415 1.1 jdc /* Indicators */ 416 1.1 jdc for (j = 0; j < ENVMON_EPC_MAX_INDS; j++, i++) { 417 1.1 jdc strlcpy(sc->sc_sensor[i].desc, envmon_epic_inds_table[j].desc, 418 1.1 jdc sizeof(sc->sc_sensor[i].desc)); 419 1.1 jdc sc->sc_sensor[i].units = ENVSYS_INDICATOR; 420 1.1 jdc sc->sc_sensor[i].state = ENVSYS_SINVALID; 421 1.1 jdc sc->sc_ind[j].reg = envmon_epic_inds_table[j].reg; 422 1.1 jdc sc->sc_ind[j].set = envmon_epic_inds_table[j].set; 423 1.1 jdc if (sysmon_envsys_sensor_attach(sc->sc_sme, 424 1.1 jdc &sc->sc_sensor[i])) { 425 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 426 1.1 jdc sc->sc_sme = NULL; 427 1.1 jdc aprint_error_dev(sc->sc_dev, 428 1.1 jdc "unable to attach sensor to sysmon\n"); 429 1.1 jdc goto leds; 430 1.1 jdc } 431 1.1 jdc } 432 1.1 jdc 433 1.1 jdc if (sysmon_envsys_register(sc->sc_sme)) { 434 1.1 jdc aprint_error_dev(sc->sc_dev, 435 1.1 jdc "unable to register with sysmon\n"); 436 1.1 jdc sysmon_envsys_destroy(sc->sc_sme); 437 1.1 jdc sc->sc_sme = NULL; 438 1.1 jdc } 439 1.1 jdc 440 1.1 jdc leds: 441 1.1 jdc /* LED's */ 442 1.1 jdc for (i = 0; i < ENVMON_EPC_MAX_LEDS; i++) { 443 1.1 jdc sc->sc_led[i].cookie = sc; 444 1.1 jdc sc->sc_led[i].reg = envmon_epic_led_table[i].reg; 445 1.1 jdc sc->sc_led[i].v_on = envmon_epic_led_table[i].v_on; 446 1.1 jdc led_attach(envmon_epic_led_table[i].desc, 447 1.1 jdc &sc->sc_led[i], envmon_epic_get_led, envmon_epic_set_led); 448 1.1 jdc } 449 1.1 jdc 450 1.1 jdc return; 451 1.1 jdc } 452 1.1 jdc 453 1.1 jdc void 454 1.1 jdc envmon_pic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 455 1.1 jdc { 456 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 457 1.1 jdc 458 1.1 jdc envmon_refresh_temp(sc, edata); 459 1.1 jdc } 460 1.1 jdc 461 1.1 jdc void 462 1.1 jdc envmon_epic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 463 1.1 jdc { 464 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 465 1.1 jdc 466 1.1 jdc if (edata->sensor < sc->sc_nfans) 467 1.1 jdc envmon_epic_refresh_fan(sc, edata); 468 1.1 jdc else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_FAULTS) 469 1.1 jdc envmon_epic_refresh_fault(sc, edata); 470 1.1 jdc else if (edata->sensor < 471 1.1 jdc sc->sc_nfans + ENVMON_EPC_MAX_FAULTS + ENVMON_EPC_MAX_TEMPS) 472 1.1 jdc envmon_refresh_temp(sc, edata); 473 1.1 jdc else 474 1.1 jdc envmon_epic_refresh_ind(sc, edata); 475 1.1 jdc 476 1.1 jdc return; 477 1.1 jdc } 478 1.1 jdc 479 1.1 jdc void 480 1.1 jdc envmon_epic_refresh_fan(struct envmon_softc *sc, envsys_data_t *edata) 481 1.1 jdc { 482 1.1 jdc uint8_t val; 483 1.1 jdc int div; 484 1.1 jdc 485 1.1 jdc if (sc->sc_machine_type == ENVMON_MACHINE_V245) 486 1.1 jdc div = ENVMON_EPC_DIV_V245; 487 1.1 jdc else 488 1.1 jdc div = ENVMON_EPC_DIV_V215; 489 1.1 jdc 490 1.1 jdc envmon_write(sc, ENVMON_ADDR, sc->sc_fan[edata->sensor].reg); 491 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 492 1.1 jdc if (val == 0xff || val == 0x0) 493 1.1 jdc edata->value_cur = 0; 494 1.1 jdc else { 495 1.1 jdc edata->value_cur = ENVMON_EPC_VAL_TO_SPEED(div, val); 496 1.1 jdc } 497 1.1 jdc if (edata->value_cur < sc->sc_fan[edata->sensor].cmin) 498 1.1 jdc edata->state = ENVSYS_SCRITICAL; 499 1.1 jdc else 500 1.1 jdc edata->state = ENVSYS_SVALID; 501 1.1 jdc } 502 1.1 jdc 503 1.1 jdc void 504 1.1 jdc envmon_epic_refresh_fault(struct envmon_softc *sc, envsys_data_t *edata) 505 1.1 jdc { 506 1.1 jdc uint8_t val; 507 1.1 jdc int32_t which, total; 508 1.1 jdc int i, j; 509 1.1 jdc 510 1.1 jdc envmon_write(sc, ENVMON_ADDR, ENVMON_EPC_FAN_FLT); 511 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 512 1.1 jdc 513 1.1 jdc total = 0; 514 1.1 jdc if (val == ENVMON_EPC_FAN_FLT_NONE) { 515 1.1 jdc edata->state = ENVSYS_SVALID; 516 1.1 jdc } else { 517 1.1 jdc edata->state = ENVSYS_SCRITICAL; 518 1.1 jdc for (i = 0; i < ENVMON_EPC_NUM_FAN_FLTS; i++) { 519 1.1 jdc if (!(val & __BIT(i))) { 520 1.1 jdc which = 1; 521 1.1 jdc for (j = 0; j < i; j++) 522 1.1 jdc which *= 10; 523 1.1 jdc total += which; 524 1.1 jdc } 525 1.1 jdc } 526 1.1 jdc } 527 1.1 jdc edata->value_cur = total; 528 1.1 jdc } 529 1.1 jdc 530 1.1 jdc void 531 1.1 jdc envmon_refresh_temp(struct envmon_softc *sc, envsys_data_t *edata) 532 1.1 jdc { 533 1.1 jdc uint8_t val; 534 1.1 jdc 535 1.1 jdc /* We currently only have 1 temperature sensor */ 536 1.1 jdc envmon_write(sc, ENVMON_ADDR, sc->sc_temp[0].reg); 537 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 538 1.1 jdc edata->value_cur = ENVMON_TEMP_BASE + val * 1000000; 539 1.1 jdc if (edata->value_cur > sc->sc_temp[0].cmax) 540 1.1 jdc edata->state = ENVSYS_SCRITICAL; 541 1.1 jdc else 542 1.1 jdc edata->state = ENVSYS_SVALID; 543 1.1 jdc } 544 1.1 jdc 545 1.1 jdc void 546 1.1 jdc envmon_epic_refresh_ind(struct envmon_softc *sc, envsys_data_t *edata) 547 1.1 jdc { 548 1.1 jdc int ind = edata->sensor - 549 1.1 jdc sc->sc_nfans - ENVMON_EPC_MAX_TEMPS - ENVMON_EPC_MAX_FAULTS; 550 1.1 jdc uint8_t val; 551 1.1 jdc 552 1.1 jdc envmon_write(sc, ENVMON_ADDR, sc->sc_ind[ind].reg); 553 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 554 1.1 jdc 555 1.1 jdc if (val == sc->sc_ind[ind].set) 556 1.1 jdc edata->value_cur = TRUE; 557 1.1 jdc else 558 1.1 jdc edata->value_cur = FALSE; 559 1.1 jdc edata->state = ENVSYS_SVALID; 560 1.1 jdc } 561 1.1 jdc 562 1.1 jdc void 563 1.1 jdc envmon_pic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 564 1.1 jdc sysmon_envsys_lim_t *limits, uint32_t *props) 565 1.1 jdc { 566 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 567 1.1 jdc 568 1.1 jdc envmon_get_temp_limits(sc, edata, limits, props); 569 1.1 jdc } 570 1.1 jdc 571 1.1 jdc void 572 1.1 jdc envmon_pic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 573 1.1 jdc sysmon_envsys_lim_t *limits, uint32_t *props) 574 1.1 jdc { 575 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 576 1.1 jdc 577 1.1 jdc envmon_set_temp_limits(sc, edata, limits, props); 578 1.1 jdc } 579 1.1 jdc 580 1.1 jdc void 581 1.1 jdc envmon_epic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 582 1.1 jdc sysmon_envsys_lim_t *limits, uint32_t *props) 583 1.1 jdc { 584 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 585 1.1 jdc 586 1.1 jdc if (edata->sensor < sc->sc_nfans) 587 1.1 jdc envmon_epic_get_fan_limits(sc, edata, limits, props); 588 1.1 jdc else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) 589 1.1 jdc envmon_get_temp_limits(sc, edata, limits, props); 590 1.1 jdc } 591 1.1 jdc 592 1.1 jdc void 593 1.1 jdc envmon_epic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 594 1.1 jdc sysmon_envsys_lim_t *limits, uint32_t *props) 595 1.1 jdc { 596 1.1 jdc struct envmon_softc *sc = sme->sme_cookie; 597 1.1 jdc 598 1.1 jdc if (edata->sensor < sc->sc_nfans) 599 1.1 jdc envmon_epic_set_fan_limits(sc, edata, limits, props); 600 1.1 jdc else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) 601 1.1 jdc envmon_set_temp_limits(sc, edata, limits, props); 602 1.1 jdc } 603 1.1 jdc 604 1.1 jdc static void 605 1.1 jdc envmon_epic_get_fan_limits(struct envmon_softc *sc, 606 1.1 jdc envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 607 1.1 jdc { 608 1.1 jdc 609 1.1 jdc *props = PROP_CRITMIN; 610 1.1 jdc limits->sel_critmin = sc->sc_fan[edata->sensor].cmin; 611 1.1 jdc } 612 1.1 jdc 613 1.1 jdc static void 614 1.1 jdc envmon_get_temp_limits(struct envmon_softc *sc, 615 1.1 jdc envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 616 1.1 jdc { 617 1.1 jdc 618 1.1 jdc *props = PROP_WARNMIN | PROP_WARNMAX | PROP_CRITMAX; 619 1.1 jdc limits->sel_warnmin = sc->sc_temp[0].wmin; 620 1.1 jdc limits->sel_warnmax = sc->sc_temp[0].wmax; 621 1.1 jdc limits->sel_critmax = sc->sc_temp[0].cmax; 622 1.1 jdc } 623 1.1 jdc 624 1.1 jdc static void 625 1.1 jdc envmon_epic_set_fan_limits(struct envmon_softc *sc, 626 1.1 jdc envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 627 1.1 jdc { 628 1.1 jdc 629 1.1 jdc if (limits == NULL || *props & PROP_CRITMIN) { 630 1.1 jdc if (limits == NULL) /* Restore defaults */ 631 1.1 jdc switch (sc->sc_machine_type) { 632 1.1 jdc case ENVMON_MACHINE_V215: 633 1.1 jdc sc->sc_fan[edata->sensor].cmin = 634 1.1 jdc ENVMON_EPC_CRIT_SPEED_V215; 635 1.1 jdc break; 636 1.1 jdc case ENVMON_MACHINE_V245: 637 1.1 jdc sc->sc_fan[edata->sensor].cmin = 638 1.1 jdc ENVMON_EPC_CRIT_SPEED_V245; 639 1.1 jdc break; 640 1.1 jdc } 641 1.1 jdc else 642 1.1 jdc sc->sc_fan[edata->sensor].cmin = limits->sel_critmin; 643 1.1 jdc } 644 1.1 jdc } 645 1.1 jdc 646 1.1 jdc static void 647 1.1 jdc envmon_set_temp_limits(struct envmon_softc *sc, 648 1.1 jdc envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) 649 1.1 jdc { 650 1.1 jdc 651 1.1 jdc if (limits == NULL || *props & PROP_CRITMAX) { 652 1.1 jdc if (limits == NULL) /* Restore defaults */ 653 1.1 jdc switch (sc->sc_machine_type) { 654 1.1 jdc case ENVMON_MACHINE_U25: 655 1.1 jdc case ENVMON_MACHINE_U45: 656 1.1 jdc sc->sc_temp[0].cmax = 657 1.1 jdc ENVMON_PIC_CRIT_TEMP; 658 1.1 jdc break; 659 1.1 jdc case ENVMON_MACHINE_V215: 660 1.1 jdc case ENVMON_MACHINE_V245: 661 1.1 jdc sc->sc_temp[0].cmax = 662 1.1 jdc ENVMON_EPC_CRIT_TEMP; 663 1.1 jdc break; 664 1.1 jdc } 665 1.1 jdc else 666 1.1 jdc sc->sc_temp[edata->sensor].cmax = limits->sel_critmax; 667 1.1 jdc } 668 1.1 jdc 669 1.1 jdc if (limits == NULL || *props & PROP_WARNMAX) { 670 1.1 jdc if (limits == NULL) /* Restore defaults */ 671 1.1 jdc switch (sc->sc_machine_type) { 672 1.1 jdc case ENVMON_MACHINE_U25: 673 1.1 jdc case ENVMON_MACHINE_U45: 674 1.1 jdc sc->sc_temp[0].wmax = 675 1.1 jdc ENVMON_PIC_WMAX_TEMP; 676 1.1 jdc break; 677 1.1 jdc case ENVMON_MACHINE_V215: 678 1.1 jdc case ENVMON_MACHINE_V245: 679 1.1 jdc sc->sc_temp[0].wmax = 680 1.1 jdc ENVMON_EPC_WMAX_TEMP; 681 1.1 jdc break; 682 1.1 jdc } 683 1.1 jdc else 684 1.1 jdc sc->sc_temp[edata->sensor].wmax = limits->sel_warnmax; 685 1.1 jdc } 686 1.1 jdc 687 1.1 jdc if (limits == NULL || *props & PROP_WARNMIN) { 688 1.1 jdc if (limits == NULL) /* Restore defaults */ 689 1.1 jdc switch (sc->sc_machine_type) { 690 1.1 jdc case ENVMON_MACHINE_U25: 691 1.1 jdc case ENVMON_MACHINE_U45: 692 1.1 jdc sc->sc_temp[0].wmin = 693 1.1 jdc ENVMON_PIC_WMIN_TEMP; 694 1.1 jdc break; 695 1.1 jdc case ENVMON_MACHINE_V215: 696 1.1 jdc case ENVMON_MACHINE_V245: 697 1.1 jdc sc->sc_temp[0].wmin = 698 1.1 jdc ENVMON_EPC_WMIN_TEMP; 699 1.1 jdc break; 700 1.1 jdc } 701 1.1 jdc else 702 1.1 jdc sc->sc_temp[edata->sensor].wmin = limits->sel_warnmin; 703 1.1 jdc } 704 1.1 jdc 705 1.1 jdc } 706 1.1 jdc 707 1.1 jdc int 708 1.1 jdc envmon_epic_get_led(void *cookie) 709 1.1 jdc { 710 1.1 jdc struct envmon_sc_led *l = cookie; 711 1.1 jdc struct envmon_softc *sc = l->cookie; 712 1.1 jdc uint8_t val; 713 1.1 jdc 714 1.1 jdc envmon_write(sc, ENVMON_ADDR, l->reg); 715 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 716 1.1 jdc return ((val & l->v_on) == l->v_on); 717 1.1 jdc } 718 1.1 jdc 719 1.1 jdc void 720 1.1 jdc envmon_epic_set_led(void *cookie, int val) 721 1.1 jdc { 722 1.1 jdc struct envmon_sc_led *l = cookie; 723 1.1 jdc struct envmon_softc *sc = l->cookie; 724 1.1 jdc uint8_t oldval, newval; 725 1.1 jdc 726 1.1 jdc envmon_write(sc, ENVMON_ADDR, l->reg); 727 1.1 jdc oldval = envmon_read(sc, ENVMON_DATA); 728 1.1 jdc newval = oldval & ~(l->v_on); 729 1.1 jdc newval |= val ? l->v_on : 0x0; 730 1.1 jdc if (newval != oldval) { 731 1.1 jdc envmon_write(sc, ENVMON_EPC_LED_MASK, l->v_on); 732 1.1 jdc envmon_write(sc, ENVMON_ADDR, l->reg); 733 1.1 jdc delay(10000); 734 1.1 jdc envmon_write(sc, ENVMON_DATA, newval); 735 1.1 jdc } 736 1.1 jdc } 737 1.1 jdc 738 1.1 jdc #ifdef ENVMON_DEBUG 739 1.1 jdc static void 740 1.1 jdc envmon_timeout(void *v) 741 1.1 jdc { 742 1.1 jdc struct envmon_softc *sc = v; 743 1.1 jdc uint8_t reg, val; 744 1.1 jdc 745 1.1 jdc for (reg = 0; reg < ENVMON_MAX_REG; reg++) { 746 1.1 jdc envmon_write(sc, ENVMON_ADDR, reg); 747 1.1 jdc val = envmon_read(sc, ENVMON_DATA); 748 1.1 jdc if (val != sc->sc_reg[reg]) { 749 1.1 jdc printf("%s: reg 0x%02x: 0x%02x > 0x%02x\n", 750 1.1 jdc device_xname(sc->sc_dev), reg, 751 1.1 jdc sc->sc_reg[reg], val); 752 1.1 jdc sc->sc_reg[reg] = val; 753 1.1 jdc } 754 1.1 jdc } 755 1.1 jdc callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); 756 1.1 jdc } 757 1.1 jdc #endif 758