1 /* $OpenBSD: stftemp.c,v 1.3 2024/10/17 01:57:18 jsg Exp $ */ 2 /* 3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/sensors.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/ofw_clock.h> 28 #include <dev/ofw/ofw_thermal.h> 29 #include <dev/ofw/fdt.h> 30 31 /* Registers */ 32 #define TEMP 0x0000 33 #define TEMP_PD (1 << 1) 34 #define TEMP_RSTN (1 << 0) 35 #define TEMP_RUN (1 << 2) 36 #define TEMP_DOUT_MASK 0x0fff0000 37 #define TEMP_DOUT_SHIFT 16 38 39 #define HREAD4(sc, reg) \ 40 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 41 #define HWRITE4(sc, reg, val) \ 42 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 43 44 struct stftemp_softc { 45 struct device sc_dev; 46 bus_space_tag_t sc_iot; 47 bus_space_handle_t sc_ioh; 48 49 struct ksensor sc_sensor; 50 struct ksensordev sc_sensordev; 51 52 struct thermal_sensor sc_ts; 53 }; 54 55 int stftemp_match(struct device *, void *, void *); 56 void stftemp_attach(struct device *, struct device *, void *); 57 58 const struct cfattach stftemp_ca = { 59 sizeof (struct stftemp_softc), stftemp_match, stftemp_attach 60 }; 61 62 struct cfdriver stftemp_cd = { 63 NULL, "stftemp", DV_DULL 64 }; 65 66 void stftemp_refresh_sensors(void *); 67 int32_t stftemp_get_temperature(void *, uint32_t *); 68 69 int 70 stftemp_match(struct device *parent, void *match, void *aux) 71 { 72 struct fdt_attach_args *faa = aux; 73 74 return OF_is_compatible(faa->fa_node, "starfive,jh7100-temp") || 75 OF_is_compatible(faa->fa_node, "starfive,jh7110-temp"); 76 } 77 78 void 79 stftemp_attach(struct device *parent, struct device *self, void *aux) 80 { 81 struct stftemp_softc *sc = (struct stftemp_softc *)self; 82 struct fdt_attach_args *faa = aux; 83 84 if (faa->fa_nreg < 1) { 85 printf(": no registers\n"); 86 return; 87 } 88 89 sc->sc_iot = faa->fa_iot; 90 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 91 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 92 printf(": can't map registers\n"); 93 return; 94 } 95 96 printf("\n"); 97 98 clock_enable(faa->fa_node, "bus"); 99 reset_deassert(faa->fa_node, "bus"); 100 101 clock_enable(faa->fa_node, "sense"); 102 reset_deassert(faa->fa_node, "sense"); 103 104 /* Power down */ 105 HWRITE4(sc, TEMP, TEMP_PD); 106 delay(1); 107 108 /* Power up with reset asserted */ 109 HWRITE4(sc, TEMP, 0); 110 delay(60); 111 112 /* Deassert reset */ 113 HWRITE4(sc, TEMP, TEMP_RSTN); 114 delay(1); 115 116 /* Start measuring */ 117 HWRITE4(sc, TEMP, TEMP_RSTN | TEMP_RUN); 118 119 /* Register sensor */ 120 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 121 sizeof(sc->sc_sensordev.xname)); 122 sc->sc_sensor.type = SENSOR_TEMP; 123 sc->sc_sensor.flags = SENSOR_FINVALID; 124 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 125 sensordev_install(&sc->sc_sensordev); 126 sensor_task_register(sc, stftemp_refresh_sensors, 5); 127 128 sc->sc_ts.ts_node = faa->fa_node; 129 sc->sc_ts.ts_cookie = sc; 130 sc->sc_ts.ts_get_temperature = stftemp_get_temperature; 131 thermal_sensor_register(&sc->sc_ts); 132 } 133 134 int32_t 135 stftemp_get_temp(struct stftemp_softc *sc) 136 { 137 int32_t value; 138 139 value = HREAD4(sc, TEMP); 140 value = (value & TEMP_DOUT_MASK) >> TEMP_DOUT_SHIFT; 141 142 return (value * 237500) / 4094 - 81100; 143 } 144 145 void 146 stftemp_refresh_sensors(void *arg) 147 { 148 struct stftemp_softc *sc = arg; 149 150 sc->sc_sensor.value = 273150000 + 1000 * stftemp_get_temp(sc); 151 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 152 } 153 154 int32_t 155 stftemp_get_temperature(void *cookie, uint32_t *cells) 156 { 157 return stftemp_get_temp(cookie); 158 } 159