xref: /openbsd-src/sys/dev/fdt/imxtmu.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1*9fdf0c62Smpi /*	$OpenBSD: imxtmu.c,v 1.3 2021/10/24 17:52:26 mpi Exp $	*/
2a315094dSpatrick /*
3a315094dSpatrick  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
4a315094dSpatrick  *
5a315094dSpatrick  * Permission to use, copy, modify, and distribute this software for any
6a315094dSpatrick  * purpose with or without fee is hereby granted, provided that the above
7a315094dSpatrick  * copyright notice and this permission notice appear in all copies.
8a315094dSpatrick  *
9a315094dSpatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a315094dSpatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a315094dSpatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a315094dSpatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a315094dSpatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a315094dSpatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a315094dSpatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a315094dSpatrick  */
17a315094dSpatrick 
18a315094dSpatrick #include <sys/param.h>
19a315094dSpatrick #include <sys/systm.h>
20a315094dSpatrick #include <sys/malloc.h>
21a315094dSpatrick #include <sys/device.h>
22a315094dSpatrick #include <sys/sensors.h>
23a315094dSpatrick #include <sys/timeout.h>
24a315094dSpatrick 
25a315094dSpatrick #include <machine/bus.h>
26a315094dSpatrick #include <machine/fdt.h>
27a315094dSpatrick 
28a315094dSpatrick #include <dev/ofw/openfirm.h>
29a315094dSpatrick #include <dev/ofw/fdt.h>
302ee9f557Spatrick #include <dev/ofw/ofw_clock.h>
31a315094dSpatrick 
322ee9f557Spatrick /* i.MX8MQ registers */
332ee9f557Spatrick #define TMU_MQ_TMR				0x000
342ee9f557Spatrick #define  TMU_MQ_TMR_ME					(1U << 31)
352ee9f557Spatrick #define  TMU_MQ_TMR_ALPF				(0x3 << 26)
362ee9f557Spatrick #define  TMU_MQ_TMR_SENSOR(x)				(1 << (15 - (x)))
372ee9f557Spatrick #define TMU_MQ_TMTMIR				0x008
382ee9f557Spatrick #define  TMU_MQ_TMTMIR_DEFAULT				0xf
392ee9f557Spatrick #define TMU_MQ_TIER				0x020
402ee9f557Spatrick #define TMU_MQ_TTCFGR				0x080
412ee9f557Spatrick #define TMU_MQ_TSCFGR				0x084
422ee9f557Spatrick #define TMU_MQ_TRITSR(x)			(0x100 + ((x) * 0x10))
432ee9f557Spatrick #define TMU_MQ_TTR0CR				0xf10
442ee9f557Spatrick #define TMU_MQ_TTR1CR				0xf14
452ee9f557Spatrick #define TMU_MQ_TTR2CR				0xf18
462ee9f557Spatrick #define TMU_MQ_TTR3CR				0xf1c
472ee9f557Spatrick 
482ee9f557Spatrick /* i.MX8MM registers */
492ee9f557Spatrick #define TMU_MM_TER				0x000
502ee9f557Spatrick #define  TMU_MM_TER_EN					(1U << 31)
512ee9f557Spatrick #define TMU_MM_TRITSR				0x020
522ee9f557Spatrick #define  TMU_MM_TRITSR_LOW_LIMIT			10
53a315094dSpatrick 
54a315094dSpatrick #define HREAD4(sc, reg)							\
55a315094dSpatrick 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
56a315094dSpatrick #define HWRITE4(sc, reg, val)						\
57a315094dSpatrick 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
58a315094dSpatrick #define HSET4(sc, reg, bits)						\
59a315094dSpatrick 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
60a315094dSpatrick #define HCLR4(sc, reg, bits)						\
61a315094dSpatrick 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
62a315094dSpatrick 
63a315094dSpatrick struct imxtmu_softc {
64a315094dSpatrick 	struct device		sc_dev;
65a315094dSpatrick 	bus_space_tag_t		sc_iot;
66a315094dSpatrick 	bus_space_handle_t	sc_ioh;
67a315094dSpatrick 	int			sc_sensorid;
68a315094dSpatrick 
69a315094dSpatrick 	struct ksensor		sc_sensor;
70a315094dSpatrick 	struct ksensordev	sc_sensordev;
71a315094dSpatrick 	struct timeout		sc_sensorto;
72a315094dSpatrick };
73a315094dSpatrick 
74a315094dSpatrick int	imxtmu_match(struct device *, void *, void *);
75a315094dSpatrick void	imxtmu_attach(struct device *, struct device *, void *);
762ee9f557Spatrick 
772ee9f557Spatrick void	imxtmu_mm_refresh_sensors(void *);
782ee9f557Spatrick void	imxtmu_mq_refresh_sensors(void *);
79a315094dSpatrick 
80*9fdf0c62Smpi const struct cfattach imxtmu_ca = {
81a315094dSpatrick 	sizeof(struct imxtmu_softc), imxtmu_match, imxtmu_attach
82a315094dSpatrick };
83a315094dSpatrick 
84a315094dSpatrick struct cfdriver imxtmu_cd = {
85a315094dSpatrick 	NULL, "imxtmu", DV_DULL
86a315094dSpatrick };
87a315094dSpatrick 
88a315094dSpatrick int
imxtmu_match(struct device * parent,void * match,void * aux)89a315094dSpatrick imxtmu_match(struct device *parent, void *match, void *aux)
90a315094dSpatrick {
91a315094dSpatrick 	struct fdt_attach_args *faa = aux;
92a315094dSpatrick 
932ee9f557Spatrick 	return OF_is_compatible(faa->fa_node, "fsl,imx8mm-tmu") ||
942ee9f557Spatrick 	    OF_is_compatible(faa->fa_node, "fsl,imx8mq-tmu");
95a315094dSpatrick }
96a315094dSpatrick 
97a315094dSpatrick void
imxtmu_attach(struct device * parent,struct device * self,void * aux)98a315094dSpatrick imxtmu_attach(struct device *parent, struct device *self, void *aux)
99a315094dSpatrick {
100a315094dSpatrick 	struct imxtmu_softc *sc = (struct imxtmu_softc *)self;
101a315094dSpatrick 	struct fdt_attach_args *faa = aux;
102a315094dSpatrick 	uint32_t range[4], *calibration;
103a315094dSpatrick 	int i, len;
104a315094dSpatrick 
105a315094dSpatrick 	if (faa->fa_nreg < 1)
106a315094dSpatrick 		return;
107a315094dSpatrick 
108a315094dSpatrick 	sc->sc_iot = faa->fa_iot;
109a315094dSpatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
110a315094dSpatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
111a315094dSpatrick 		panic("%s: bus_space_map failed!", __func__);
112a315094dSpatrick 
113a315094dSpatrick 	printf("\n");
114a315094dSpatrick 
1152ee9f557Spatrick 	clock_enable_all(faa->fa_node);
116a315094dSpatrick 
117a315094dSpatrick 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
118a315094dSpatrick 	    sizeof(sc->sc_sensordev.xname));
119a315094dSpatrick 	strlcpy(sc->sc_sensor.desc, "core",
120a315094dSpatrick 	    sizeof(sc->sc_sensor.desc));
121a315094dSpatrick 	sc->sc_sensor.type = SENSOR_TEMP;
122a315094dSpatrick 	sc->sc_sensor.flags = SENSOR_FINVALID;
123a315094dSpatrick 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
124a315094dSpatrick 	sensordev_install(&sc->sc_sensordev);
1252ee9f557Spatrick 
1262ee9f557Spatrick 	if (OF_is_compatible(faa->fa_node, "fsl,imx8mm-tmu")) {
1272ee9f557Spatrick 		HSET4(sc, TMU_MM_TER, TMU_MM_TER_EN);
1282ee9f557Spatrick 		sensor_task_register(sc, imxtmu_mm_refresh_sensors, 5);
1292ee9f557Spatrick 	}
1302ee9f557Spatrick 
1312ee9f557Spatrick 	if (OF_is_compatible(faa->fa_node, "fsl,imx8mq-tmu")) {
1322ee9f557Spatrick 		/*
1332ee9f557Spatrick 		 * XXX: This thermal unit can show temperatures per node, and
1342ee9f557Spatrick 		 * XXX: the thermal-zones can reference this.  But since we do
1352ee9f557Spatrick 		 * XXX: not register ourselves with such a infrastructure we can
1362ee9f557Spatrick 		 * XXX: live with just extracting sensor 0: the CPU.
1372ee9f557Spatrick 		 */
1382ee9f557Spatrick 		sc->sc_sensorid = 0;
1392ee9f557Spatrick 
1402ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TIER, 0);
1412ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TMTMIR, TMU_MQ_TMTMIR_DEFAULT);
1422ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TMR, 0);
1432ee9f557Spatrick 
1442ee9f557Spatrick 		if (OF_getpropintarray(faa->fa_node, "fsl,tmu-range", range,
1452ee9f557Spatrick 		    sizeof(range)) != sizeof(range))
1462ee9f557Spatrick 			return;
1472ee9f557Spatrick 
1482ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TTR0CR, range[0]);
1492ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TTR1CR, range[1]);
1502ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TTR2CR, range[2]);
1512ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TTR3CR, range[3]);
1522ee9f557Spatrick 
1532ee9f557Spatrick 		len = OF_getproplen(faa->fa_node, "fsl,tmu-calibration");
1542ee9f557Spatrick 		if (len <= 0 || (len % 8) != 0)
1552ee9f557Spatrick 			return;
1562ee9f557Spatrick 
1572ee9f557Spatrick 		calibration = malloc(len, M_TEMP, M_WAITOK);
1582ee9f557Spatrick 		OF_getpropintarray(faa->fa_node, "fsl,tmu-calibration", calibration,
1592ee9f557Spatrick 		    len);
1602ee9f557Spatrick 		for (i = 0; i < (len / 4); i += 2) {
1612ee9f557Spatrick 			HWRITE4(sc, TMU_MQ_TTCFGR, calibration[i + 0]);
1622ee9f557Spatrick 			HWRITE4(sc, TMU_MQ_TSCFGR, calibration[i + 1]);
1632ee9f557Spatrick 		}
1642ee9f557Spatrick 		free(calibration, M_TEMP, len);
1652ee9f557Spatrick 
1662ee9f557Spatrick 		HWRITE4(sc, TMU_MQ_TMR, TMU_MQ_TMR_SENSOR(sc->sc_sensorid) |
1672ee9f557Spatrick 		    TMU_MQ_TMR_ME | TMU_MQ_TMR_ALPF);
1682ee9f557Spatrick 
1692ee9f557Spatrick 		sensor_task_register(sc, imxtmu_mq_refresh_sensors, 5);
1702ee9f557Spatrick 	}
171a315094dSpatrick }
172a315094dSpatrick 
173a315094dSpatrick void
imxtmu_mm_refresh_sensors(void * arg)1742ee9f557Spatrick imxtmu_mm_refresh_sensors(void *arg)
175a315094dSpatrick {
176a315094dSpatrick 	struct imxtmu_softc *sc = (struct imxtmu_softc *)arg;
177a315094dSpatrick 	uint32_t value;
178a315094dSpatrick 
1792ee9f557Spatrick 	value = HREAD4(sc, TMU_MM_TRITSR);
1802ee9f557Spatrick 	if (value < TMU_MM_TRITSR_LOW_LIMIT)
1812ee9f557Spatrick 		return;
1822ee9f557Spatrick 	value = (value & 0xff) * 1000000;
1832ee9f557Spatrick 
1842ee9f557Spatrick 	sc->sc_sensor.value = value + 273150000;
1852ee9f557Spatrick 	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
1862ee9f557Spatrick }
1872ee9f557Spatrick 
1882ee9f557Spatrick void
imxtmu_mq_refresh_sensors(void * arg)1892ee9f557Spatrick imxtmu_mq_refresh_sensors(void *arg)
1902ee9f557Spatrick {
1912ee9f557Spatrick 	struct imxtmu_softc *sc = (struct imxtmu_softc *)arg;
1922ee9f557Spatrick 	uint32_t value;
1932ee9f557Spatrick 
1942ee9f557Spatrick 	value = HREAD4(sc, TMU_MQ_TRITSR(sc->sc_sensorid));
195a315094dSpatrick 	value = (value & 0xff) * 1000000;
196a315094dSpatrick 
197a315094dSpatrick 	sc->sc_sensor.value = value + 273150000;
198a315094dSpatrick 	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
199a315094dSpatrick }
200