1 /* $OpenBSD: imxtmu.c,v 1.1 2019/08/27 12:51:57 patrick Exp $ */ 2 /* 3 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 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/malloc.h> 21 #include <sys/device.h> 22 #include <sys/sensors.h> 23 #include <sys/timeout.h> 24 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/fdt.h> 30 31 /* registers */ 32 #define TMU_TMR 0x000 33 #define TMU_TMR_ME (1U << 31) 34 #define TMU_TMR_ALPF (0x3 << 26) 35 #define TMU_TMR_SENSOR(x) (1 << (15 - (x))) 36 #define TMU_TMTMIR 0x008 37 #define TMU_TMTMIR_DEFAULT 0xf 38 #define TMU_TIER 0x020 39 #define TMU_TTCFGR 0x080 40 #define TMU_TSCFGR 0x084 41 #define TMU_TRITSR(x) (0x100 + ((x) * 0x10)) 42 #define TMU_TTR0CR 0xf10 43 #define TMU_TTR1CR 0xf14 44 #define TMU_TTR2CR 0xf18 45 #define TMU_TTR3CR 0xf1c 46 47 #define HREAD4(sc, reg) \ 48 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 49 #define HWRITE4(sc, reg, val) \ 50 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 51 #define HSET4(sc, reg, bits) \ 52 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 53 #define HCLR4(sc, reg, bits) \ 54 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 55 56 struct imxtmu_softc { 57 struct device sc_dev; 58 bus_space_tag_t sc_iot; 59 bus_space_handle_t sc_ioh; 60 int sc_sensorid; 61 62 struct ksensor sc_sensor; 63 struct ksensordev sc_sensordev; 64 struct timeout sc_sensorto; 65 }; 66 67 int imxtmu_match(struct device *, void *, void *); 68 void imxtmu_attach(struct device *, struct device *, void *); 69 void imxtmu_refresh_sensors(void *); 70 71 struct cfattach imxtmu_ca = { 72 sizeof(struct imxtmu_softc), imxtmu_match, imxtmu_attach 73 }; 74 75 struct cfdriver imxtmu_cd = { 76 NULL, "imxtmu", DV_DULL 77 }; 78 79 int 80 imxtmu_match(struct device *parent, void *match, void *aux) 81 { 82 struct fdt_attach_args *faa = aux; 83 84 return OF_is_compatible(faa->fa_node, "fsl,imx8mq-tmu"); 85 } 86 87 void 88 imxtmu_attach(struct device *parent, struct device *self, void *aux) 89 { 90 struct imxtmu_softc *sc = (struct imxtmu_softc *)self; 91 struct fdt_attach_args *faa = aux; 92 uint32_t range[4], *calibration; 93 int i, len; 94 95 if (faa->fa_nreg < 1) 96 return; 97 98 sc->sc_iot = faa->fa_iot; 99 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 100 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 101 panic("%s: bus_space_map failed!", __func__); 102 103 printf("\n"); 104 105 /* 106 * XXX: This thermal unit can show temperatures per node, and 107 * XXX: the thermal-zones can reference this. But since we do 108 * XXX: not register ourselves with such a infrastructure we can 109 * XXX: live with just extracting sensor 0: the CPU. 110 */ 111 sc->sc_sensorid = 0; 112 113 HWRITE4(sc, TMU_TIER, 0); 114 HWRITE4(sc, TMU_TMTMIR, TMU_TMTMIR_DEFAULT); 115 HWRITE4(sc, TMU_TMR, 0); 116 117 if (OF_getpropintarray(faa->fa_node, "fsl,tmu-range", range, 118 sizeof(range)) != sizeof(range)) 119 return; 120 121 HWRITE4(sc, TMU_TTR0CR, range[0]); 122 HWRITE4(sc, TMU_TTR1CR, range[1]); 123 HWRITE4(sc, TMU_TTR2CR, range[2]); 124 HWRITE4(sc, TMU_TTR3CR, range[3]); 125 126 len = OF_getproplen(faa->fa_node, "fsl,tmu-calibration"); 127 if (len <= 0 || (len % 8) != 0) 128 return; 129 130 calibration = malloc(len, M_TEMP, M_WAITOK); 131 OF_getpropintarray(faa->fa_node, "fsl,tmu-calibration", calibration, 132 len); 133 for (i = 0; i < (len / 4); i += 2) { 134 HWRITE4(sc, TMU_TTCFGR, calibration[i + 0]); 135 HWRITE4(sc, TMU_TSCFGR, calibration[i + 1]); 136 } 137 free(calibration, M_TEMP, len); 138 139 HWRITE4(sc, TMU_TMR, TMU_TMR_SENSOR(sc->sc_sensorid) | 140 TMU_TMR_ME | TMU_TMR_ALPF); 141 142 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 143 sizeof(sc->sc_sensordev.xname)); 144 strlcpy(sc->sc_sensor.desc, "core", 145 sizeof(sc->sc_sensor.desc)); 146 sc->sc_sensor.type = SENSOR_TEMP; 147 sc->sc_sensor.flags = SENSOR_FINVALID; 148 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 149 sensordev_install(&sc->sc_sensordev); 150 sensor_task_register(sc, imxtmu_refresh_sensors, 5); 151 } 152 153 void 154 imxtmu_refresh_sensors(void *arg) 155 { 156 struct imxtmu_softc *sc = (struct imxtmu_softc *)arg; 157 uint32_t value; 158 159 value = HREAD4(sc, TMU_TRITSR(sc->sc_sensorid)); 160 value = (value & 0xff) * 1000000; 161 162 sc->sc_sensor.value = value + 273150000; 163 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 164 } 165