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