xref: /openbsd-src/sys/arch/sparc64/dev/clkbrd.c (revision eb7eaf8de3ff431d305450f61b441e5460c82246)
1*eb7eaf8dSmpi /*	$OpenBSD: clkbrd.c,v 1.7 2021/10/24 17:05:03 mpi Exp $	*/
203c059c8Sjason 
303c059c8Sjason /*
403c059c8Sjason  * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
503c059c8Sjason  * All rights reserved.
603c059c8Sjason  *
703c059c8Sjason  * Redistribution and use in source and binary forms, with or without
803c059c8Sjason  * modification, are permitted provided that the following conditions
903c059c8Sjason  * are met:
1003c059c8Sjason  * 1. Redistributions of source code must retain the above copyright
1103c059c8Sjason  *    notice, this list of conditions and the following disclaimer.
1203c059c8Sjason  * 2. Redistributions in binary form must reproduce the above copyright
1303c059c8Sjason  *    notice, this list of conditions and the following disclaimer in the
1403c059c8Sjason  *    documentation and/or other materials provided with the distribution.
1503c059c8Sjason  *
1603c059c8Sjason  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1703c059c8Sjason  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1803c059c8Sjason  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1903c059c8Sjason  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2003c059c8Sjason  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2103c059c8Sjason  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2203c059c8Sjason  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2303c059c8Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2403c059c8Sjason  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2503c059c8Sjason  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2603c059c8Sjason  * POSSIBILITY OF SUCH DAMAGE.
2703c059c8Sjason  */
2803c059c8Sjason 
2903c059c8Sjason #include <sys/param.h>
3003c059c8Sjason #include <sys/conf.h>
31a244e471Skettenis #include <sys/device.h>
32a244e471Skettenis #include <sys/kernel.h>
3303c059c8Sjason #include <sys/malloc.h>
34a244e471Skettenis #include <sys/sensors.h>
35a244e471Skettenis #include <sys/systm.h>
36a244e471Skettenis #include <sys/timeout.h>
3703c059c8Sjason 
3803c059c8Sjason #include <machine/bus.h>
3903c059c8Sjason #include <machine/autoconf.h>
4003c059c8Sjason #include <machine/openfirm.h>
4103c059c8Sjason 
4203c059c8Sjason #include <sparc64/dev/fhcvar.h>
4303c059c8Sjason #include <sparc64/dev/clkbrdreg.h>
4403c059c8Sjason #include <sparc64/dev/clkbrdvar.h>
4503c059c8Sjason 
4603c059c8Sjason int clkbrd_match(struct device *, void *, void *);
4703c059c8Sjason void clkbrd_attach(struct device *, struct device *, void *);
489f31f4f7Sjason void clkbrd_led_blink(void *, int);
49a244e471Skettenis void clkbrd_refresh(void *);
5003c059c8Sjason 
51*eb7eaf8dSmpi const struct cfattach clkbrd_ca = {
5203c059c8Sjason 	sizeof(struct clkbrd_softc), clkbrd_match, clkbrd_attach
5303c059c8Sjason };
5403c059c8Sjason 
5503c059c8Sjason struct cfdriver clkbrd_cd = {
5603c059c8Sjason 	NULL, "clkbrd", DV_DULL
5703c059c8Sjason };
5803c059c8Sjason 
5903c059c8Sjason int
clkbrd_match(struct device * parent,void * match,void * aux)60a244e471Skettenis clkbrd_match(struct device *parent, void *match, void *aux)
6103c059c8Sjason {
6203c059c8Sjason 	struct fhc_attach_args *fa = aux;
6303c059c8Sjason 
6403c059c8Sjason 	if (strcmp(fa->fa_name, "clock-board") == 0)
6503c059c8Sjason 		return (1);
6603c059c8Sjason 	return (0);
6703c059c8Sjason }
6803c059c8Sjason 
6903c059c8Sjason void
clkbrd_attach(struct device * parent,struct device * self,void * aux)70a244e471Skettenis clkbrd_attach(struct device *parent, struct device *self, void *aux)
7103c059c8Sjason {
7203c059c8Sjason 	struct clkbrd_softc *sc = (struct clkbrd_softc *)self;
7303c059c8Sjason 	struct fhc_attach_args *fa = aux;
7411d22280Sjason 	int slots;
7503c059c8Sjason 	u_int8_t r;
7603c059c8Sjason 
7703c059c8Sjason 	sc->sc_bt = fa->fa_bustag;
7803c059c8Sjason 
793cbd0accSjason 	if (fa->fa_nreg < 2) {
8003c059c8Sjason 		printf(": no registers\n");
8103c059c8Sjason 		return;
8203c059c8Sjason 	}
8303c059c8Sjason 
843cbd0accSjason 	if (fhc_bus_map(sc->sc_bt, fa->fa_reg[1].fbr_slot,
853cbd0accSjason 	    fa->fa_reg[1].fbr_offset, fa->fa_reg[1].fbr_size, 0,
8603c059c8Sjason 	    &sc->sc_creg)) {
8703c059c8Sjason 		printf(": can't map ctrl regs\n");
8803c059c8Sjason 		return;
8903c059c8Sjason 	}
9003c059c8Sjason 
9103c059c8Sjason 	if (fa->fa_nreg > 2) {
9203c059c8Sjason 		if (fhc_bus_map(sc->sc_bt, fa->fa_reg[2].fbr_slot,
9303c059c8Sjason 		    fa->fa_reg[2].fbr_offset, fa->fa_reg[2].fbr_size, 0,
9403c059c8Sjason 		    &sc->sc_vreg)) {
9503c059c8Sjason 			printf(": can't map vreg\n");
9603c059c8Sjason 			return;
9703c059c8Sjason 		}
9803c059c8Sjason 		sc->sc_has_vreg = 1;
9903c059c8Sjason 	}
10003c059c8Sjason 
1013cbd0accSjason 	slots = 4;
10203c059c8Sjason 	r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_STS1);
10303c059c8Sjason 	switch (r & 0xc0) {
10403c059c8Sjason 	case 0x40:
10503c059c8Sjason 		slots = 16;
10603c059c8Sjason 		break;
10703c059c8Sjason 	case 0xc0:
10803c059c8Sjason 		slots = 8;
10903c059c8Sjason 		break;
11003c059c8Sjason 	case 0x80:
11103c059c8Sjason 		if (sc->sc_has_vreg) {
11203c059c8Sjason 			r = bus_space_read_1(sc->sc_bt, sc->sc_vreg, 0);
1133cbd0accSjason 			if (r != 0 && (r & 0x80) == 0)
11403c059c8Sjason 					slots = 5;
11503c059c8Sjason 		}
11603c059c8Sjason 	}
11703c059c8Sjason 
1189f31f4f7Sjason 	sc->sc_blink.bl_func = clkbrd_led_blink;
1199f31f4f7Sjason 	sc->sc_blink.bl_arg = sc;
1209f31f4f7Sjason 	blink_led_register(&sc->sc_blink);
121a244e471Skettenis 
122a244e471Skettenis 	/* Initialize sensor data. */
123a244e471Skettenis 	strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
124a244e471Skettenis 	    sizeof(sc->sc_sensordev.xname));
125a244e471Skettenis 	sc->sc_sensor.type = SENSOR_TEMP;
126a244e471Skettenis 
127a244e471Skettenis 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
128a244e471Skettenis 
129a244e471Skettenis 	if (sensor_task_register(sc, clkbrd_refresh, 5) == NULL) {
130a244e471Skettenis 		printf(": unable to register update task\n");
131a244e471Skettenis 		return;
132a244e471Skettenis 	}
133a244e471Skettenis 
134a244e471Skettenis 	sensordev_install(&sc->sc_sensordev);
135a244e471Skettenis 
136a244e471Skettenis 	printf(": %d slots\n", slots);
13703c059c8Sjason }
13803c059c8Sjason 
13903c059c8Sjason void
clkbrd_led_blink(void * vsc,int on)1409f31f4f7Sjason clkbrd_led_blink(void *vsc, int on)
14103c059c8Sjason {
14203c059c8Sjason 	struct clkbrd_softc *sc = vsc;
1439f31f4f7Sjason 	int s;
14403c059c8Sjason 	u_int8_t r;
14503c059c8Sjason 
14603c059c8Sjason 	s = splhigh();
14703c059c8Sjason 	r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
1489f31f4f7Sjason 	if (on)
1499f31f4f7Sjason 		r |= CLK_CTRL_RLED;
1509f31f4f7Sjason 	else
1519f31f4f7Sjason 		r &= ~CLK_CTRL_RLED;
15203c059c8Sjason 	bus_space_write_1(sc->sc_bt, sc->sc_creg, CLK_CTRL, r);
15303c059c8Sjason 	bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
15403c059c8Sjason 	splx(s);
15503c059c8Sjason }
156a244e471Skettenis 
157a244e471Skettenis /*
158a244e471Skettenis  * Calibration table for temperature sensor.
159a244e471Skettenis  */
160a244e471Skettenis int8_t clkbrd_temp[] = {
161a244e471Skettenis 	 0,  0,  0,  0,  0,  0,  0,  0,
162a244e471Skettenis 	 0,  0,  0,  0,  1,  2,  4,  5,
163a244e471Skettenis 	 7,  8, 10, 11, 12, 13, 14, 15,
164a244e471Skettenis 	17, 18, 19, 20, 21, 22, 23, 24,
165a244e471Skettenis 	24, 25, 26, 27, 28, 29, 29, 30,
166a244e471Skettenis 	31, 32, 32, 33, 34, 35, 35, 36,
167a244e471Skettenis 	37, 38, 38, 39, 40, 40, 41, 42,
168a244e471Skettenis 	42, 43, 44, 44, 45, 46, 46, 47,
169a244e471Skettenis 	48, 48, 49, 50, 50, 51, 52, 52,
170a244e471Skettenis 	53, 54, 54, 55, 56, 57, 57, 58,
171a244e471Skettenis 	59, 59, 60, 60, 61, 62, 63, 63,
172a244e471Skettenis 	64, 65, 65, 66, 67, 68, 68, 69,
173a244e471Skettenis 	70, 70, 71, 72, 73, 74, 74, 75,
174a244e471Skettenis 	76, 77, 78, 78, 79, 80, 81, 82
175a244e471Skettenis };
176a244e471Skettenis 
177a244e471Skettenis const int8_t clkbrd_temp_warn = 60;
178a244e471Skettenis const int8_t clkbrd_temp_crit = 68;
179a244e471Skettenis 
180a244e471Skettenis void
clkbrd_refresh(void * arg)181a244e471Skettenis clkbrd_refresh(void *arg)
182a244e471Skettenis {
183a244e471Skettenis 	struct clkbrd_softc *sc = arg;
184a244e471Skettenis 	u_int8_t val;
185a244e471Skettenis 	int8_t temp;
186a244e471Skettenis 
187a244e471Skettenis 	val = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_TEMP);
188a244e471Skettenis 	if (val == 0xff) {
189a244e471Skettenis 		sc->sc_sensor.flags |= SENSOR_FINVALID;
190a244e471Skettenis 		return;
191a244e471Skettenis 	}
192a244e471Skettenis 
193a244e471Skettenis 	if (val < sizeof(clkbrd_temp))
194a244e471Skettenis 		temp = clkbrd_temp[val];
195a244e471Skettenis 	else
196a244e471Skettenis 		temp = clkbrd_temp[sizeof(clkbrd_temp) - 1];
197a244e471Skettenis 
198a244e471Skettenis 	sc->sc_sensor.value = val * 1000000 + 273150000;
199a244e471Skettenis 	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
200a244e471Skettenis 	sc->sc_sensor.status = SENSOR_S_OK;
201a244e471Skettenis 	if (temp >= clkbrd_temp_warn)
202a244e471Skettenis 		sc->sc_sensor.status = SENSOR_S_WARN;
203a244e471Skettenis 	if (temp >= clkbrd_temp_crit)
204a244e471Skettenis 		sc->sc_sensor.status = SENSOR_S_CRIT;
205a244e471Skettenis }
206