1 /* $OpenBSD: clkbrd.c,v 1.7 2021/10/24 17:05:03 mpi Exp $ */
2
3 /*
4 * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/conf.h>
31 #include <sys/device.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/sensors.h>
35 #include <sys/systm.h>
36 #include <sys/timeout.h>
37
38 #include <machine/bus.h>
39 #include <machine/autoconf.h>
40 #include <machine/openfirm.h>
41
42 #include <sparc64/dev/fhcvar.h>
43 #include <sparc64/dev/clkbrdreg.h>
44 #include <sparc64/dev/clkbrdvar.h>
45
46 int clkbrd_match(struct device *, void *, void *);
47 void clkbrd_attach(struct device *, struct device *, void *);
48 void clkbrd_led_blink(void *, int);
49 void clkbrd_refresh(void *);
50
51 const struct cfattach clkbrd_ca = {
52 sizeof(struct clkbrd_softc), clkbrd_match, clkbrd_attach
53 };
54
55 struct cfdriver clkbrd_cd = {
56 NULL, "clkbrd", DV_DULL
57 };
58
59 int
clkbrd_match(struct device * parent,void * match,void * aux)60 clkbrd_match(struct device *parent, void *match, void *aux)
61 {
62 struct fhc_attach_args *fa = aux;
63
64 if (strcmp(fa->fa_name, "clock-board") == 0)
65 return (1);
66 return (0);
67 }
68
69 void
clkbrd_attach(struct device * parent,struct device * self,void * aux)70 clkbrd_attach(struct device *parent, struct device *self, void *aux)
71 {
72 struct clkbrd_softc *sc = (struct clkbrd_softc *)self;
73 struct fhc_attach_args *fa = aux;
74 int slots;
75 u_int8_t r;
76
77 sc->sc_bt = fa->fa_bustag;
78
79 if (fa->fa_nreg < 2) {
80 printf(": no registers\n");
81 return;
82 }
83
84 if (fhc_bus_map(sc->sc_bt, fa->fa_reg[1].fbr_slot,
85 fa->fa_reg[1].fbr_offset, fa->fa_reg[1].fbr_size, 0,
86 &sc->sc_creg)) {
87 printf(": can't map ctrl regs\n");
88 return;
89 }
90
91 if (fa->fa_nreg > 2) {
92 if (fhc_bus_map(sc->sc_bt, fa->fa_reg[2].fbr_slot,
93 fa->fa_reg[2].fbr_offset, fa->fa_reg[2].fbr_size, 0,
94 &sc->sc_vreg)) {
95 printf(": can't map vreg\n");
96 return;
97 }
98 sc->sc_has_vreg = 1;
99 }
100
101 slots = 4;
102 r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_STS1);
103 switch (r & 0xc0) {
104 case 0x40:
105 slots = 16;
106 break;
107 case 0xc0:
108 slots = 8;
109 break;
110 case 0x80:
111 if (sc->sc_has_vreg) {
112 r = bus_space_read_1(sc->sc_bt, sc->sc_vreg, 0);
113 if (r != 0 && (r & 0x80) == 0)
114 slots = 5;
115 }
116 }
117
118 sc->sc_blink.bl_func = clkbrd_led_blink;
119 sc->sc_blink.bl_arg = sc;
120 blink_led_register(&sc->sc_blink);
121
122 /* Initialize sensor data. */
123 strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
124 sizeof(sc->sc_sensordev.xname));
125 sc->sc_sensor.type = SENSOR_TEMP;
126
127 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
128
129 if (sensor_task_register(sc, clkbrd_refresh, 5) == NULL) {
130 printf(": unable to register update task\n");
131 return;
132 }
133
134 sensordev_install(&sc->sc_sensordev);
135
136 printf(": %d slots\n", slots);
137 }
138
139 void
clkbrd_led_blink(void * vsc,int on)140 clkbrd_led_blink(void *vsc, int on)
141 {
142 struct clkbrd_softc *sc = vsc;
143 int s;
144 u_int8_t r;
145
146 s = splhigh();
147 r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
148 if (on)
149 r |= CLK_CTRL_RLED;
150 else
151 r &= ~CLK_CTRL_RLED;
152 bus_space_write_1(sc->sc_bt, sc->sc_creg, CLK_CTRL, r);
153 bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
154 splx(s);
155 }
156
157 /*
158 * Calibration table for temperature sensor.
159 */
160 int8_t clkbrd_temp[] = {
161 0, 0, 0, 0, 0, 0, 0, 0,
162 0, 0, 0, 0, 1, 2, 4, 5,
163 7, 8, 10, 11, 12, 13, 14, 15,
164 17, 18, 19, 20, 21, 22, 23, 24,
165 24, 25, 26, 27, 28, 29, 29, 30,
166 31, 32, 32, 33, 34, 35, 35, 36,
167 37, 38, 38, 39, 40, 40, 41, 42,
168 42, 43, 44, 44, 45, 46, 46, 47,
169 48, 48, 49, 50, 50, 51, 52, 52,
170 53, 54, 54, 55, 56, 57, 57, 58,
171 59, 59, 60, 60, 61, 62, 63, 63,
172 64, 65, 65, 66, 67, 68, 68, 69,
173 70, 70, 71, 72, 73, 74, 74, 75,
174 76, 77, 78, 78, 79, 80, 81, 82
175 };
176
177 const int8_t clkbrd_temp_warn = 60;
178 const int8_t clkbrd_temp_crit = 68;
179
180 void
clkbrd_refresh(void * arg)181 clkbrd_refresh(void *arg)
182 {
183 struct clkbrd_softc *sc = arg;
184 u_int8_t val;
185 int8_t temp;
186
187 val = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_TEMP);
188 if (val == 0xff) {
189 sc->sc_sensor.flags |= SENSOR_FINVALID;
190 return;
191 }
192
193 if (val < sizeof(clkbrd_temp))
194 temp = clkbrd_temp[val];
195 else
196 temp = clkbrd_temp[sizeof(clkbrd_temp) - 1];
197
198 sc->sc_sensor.value = val * 1000000 + 273150000;
199 sc->sc_sensor.flags &= ~SENSOR_FINVALID;
200 sc->sc_sensor.status = SENSOR_S_OK;
201 if (temp >= clkbrd_temp_warn)
202 sc->sc_sensor.status = SENSOR_S_WARN;
203 if (temp >= clkbrd_temp_crit)
204 sc->sc_sensor.status = SENSOR_S_CRIT;
205 }
206