xref: /dragonfly/sys/dev/powermng/kate/kate.c (revision 0ca59c34)
1 /*	$OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $	*/
2 
3 /*
4  * Copyright (c) 2008/2010 Constantine A. Murenin <cnst+dfly@bugmail.mojo.ru>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/bus.h>
22 #include <sys/sensors.h>
23 
24 #include <bus/pci/pcivar.h>
25 #include "pcidevs.h"
26 
27 
28 /*
29  * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control
30  */
31 
32 /* Function 3 Registers */
33 #define K_THERMTRIP_STAT_R	0xe4
34 #define K_NORTHBRIDGE_CAP_R	0xe8
35 #define K_CPUID_FAMILY_MODEL_R	0xfc
36 
37 /* Bits within Thermtrip Status Register */
38 #define K_THERM_SENSE_SEL	(1 << 6)
39 #define K_THERM_SENSE_CORE_SEL	(1 << 2)
40 
41 /* Flip core and sensor selection bits */
42 #define K_T_SEL_C0(v)		(v |= K_THERM_SENSE_CORE_SEL)
43 #define K_T_SEL_C1(v)		(v &= ~(K_THERM_SENSE_CORE_SEL))
44 #define K_T_SEL_S0(v)		(v &= ~(K_THERM_SENSE_SEL))
45 #define K_T_SEL_S1(v)		(v |= K_THERM_SENSE_SEL)
46 
47 
48 /*
49  * Revision Guide for AMD NPT Family 0Fh Processors,
50  * Publication # 33610, Revision 3.30, February 2008
51  */
52 static const struct {
53 	const char	rev[5];
54 	const uint32_t	cpuid[5];
55 } kate_proc[] = {
56 	{ "BH-F", { 0x00040FB0, 0x00040F80, 0, 0, 0 } },	/* F2 */
57 	{ "DH-F", { 0x00040FF0, 0x00050FF0, 0x00040FC0, 0, 0 } }, /* F2, F3 */
58 	{ "JH-F", { 0x00040F10, 0x00040F30, 0x000C0F10, 0, 0 } }, /* F2, F3 */
59 	{ "BH-G", { 0x00060FB0, 0x00060F80, 0, 0, 0 } },	/* G1, G2 */
60 	{ "DH-G", { 0x00070FF0, 0x00060FF0,
61 	    0x00060FC0, 0x00070FC0, 0 } }	/* G1, G2 */
62 };
63 
64 
65 struct kate_softc {
66 	struct device		*sc_dev;
67 
68 	struct ksensor		sc_sensors[4];
69 	struct ksensordev	sc_sensordev;
70 
71 	char			sc_rev;
72 	int8_t			sc_ii;
73 	int8_t			sc_in;
74 };
75 
76 static void	kate_identify(driver_t *, struct device *);
77 static int	kate_probe(struct device *);
78 static int	kate_attach(struct device *);
79 static int	kate_detach(struct device *);
80 static void	kate_refresh(void *);
81 
82 static device_method_t kate_methods[] = {
83 	DEVMETHOD(device_identify,	kate_identify),
84 	DEVMETHOD(device_probe,		kate_probe),
85 	DEVMETHOD(device_attach,	kate_attach),
86 	DEVMETHOD(device_detach,	kate_detach),
87 	{ NULL, NULL }
88 };
89 
90 static driver_t kate_driver = {
91 	"kate",
92 	kate_methods,
93 	sizeof(struct kate_softc)
94 };
95 
96 static devclass_t kate_devclass;
97 
98 DRIVER_MODULE(kate, hostb, kate_driver, kate_devclass, NULL, NULL);
99 
100 
101 static void
102 kate_identify(driver_t *driver, struct device *parent)
103 {
104 	if (kate_probe(parent) == ENXIO)
105 		return;
106 	if (device_find_child(parent, driver->name, -1) != NULL)
107 		return;
108 	device_add_child(parent, driver->name, -1);
109 }
110 
111 static int
112 kate_probe(struct device *dev)
113 {
114 #ifndef KATE_STRICT
115 	struct kate_softc	ks;
116 	struct kate_softc	*sc = &ks;
117 #endif
118 	uint32_t		c;
119 	int			i, j;
120 
121 	if (pci_get_vendor(dev) != PCI_VENDOR_AMD ||
122 	    pci_get_device(dev) != PCI_PRODUCT_AMD_AMD64_MISC)
123 		return ENXIO;
124 
125 	/* just in case we probe successfully, set the description */
126 	if (device_get_desc(dev) == NULL)
127 		device_set_desc(dev,
128 		    "AMD Family 0Fh temperature sensors");
129 
130 	/*
131 	 * First, let's probe for chips at or after Revision F, which is
132 	 * when the temperature readings were officially introduced.
133 	 */
134 	c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
135 	for (i = 0; i < NELEM(kate_proc); i++)
136 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
137 			if ((c & ~0xf) == kate_proc[i].cpuid[j])
138 				return 0;
139 
140 #ifndef KATE_STRICT
141 	/*
142 	 * If the probe above was not successful, let's try to actually
143 	 * read the sensors from the chip, and see if they make any sense.
144 	 */
145 	sc->sc_ii = 0;
146 	sc->sc_in = 4;
147 	sc->sc_dev = dev;
148 	kate_refresh(sc);
149 	for (i = 0; i < 4; i++)
150 		if (!(sc->sc_sensors[i].flags & SENSOR_FINVALID))
151 			return 0;
152 #endif /* !KATE_STRICT */
153 
154 	return ENXIO;
155 }
156 
157 static int
158 kate_attach(struct device *dev)
159 {
160 	struct kate_softc	*sc;
161 	uint32_t		c, d;
162 	int			i, j, cmpcap;
163 
164 	sc = device_get_softc(dev);
165 	sc->sc_dev = dev;
166 
167 	c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
168 	for (i = 0; i < NELEM(kate_proc) && sc->sc_rev == '\0'; i++)
169 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
170 			if ((c & ~0xf) == kate_proc[i].cpuid[j]) {
171 				sc->sc_rev = kate_proc[i].rev[3];
172 				device_printf(dev, "core rev %.4s%.1x\n",
173 				    kate_proc[i].rev, c & 0xf);
174 				break;
175 			}
176 
177 	if (c != 0x0 && sc->sc_rev == '\0') {
178 		/* CPUID Family Model Register was introduced in Revision F */
179 		sc->sc_rev = 'G';	/* newer than E, assume G */
180 		device_printf(dev, "cpuid 0x%x\n", c);
181 	}
182 
183 	d = pci_read_config(dev, K_NORTHBRIDGE_CAP_R, 4);
184 	cmpcap = (d >> 12) & 0x3;
185 
186 #ifndef KATE_STRICT
187 	sc->sc_ii = 0;
188 	sc->sc_in = 4;
189 	kate_refresh(sc);
190 	if (cmpcap == 0) {
191 		if ((sc->sc_sensors[0].flags & SENSOR_FINVALID) &&
192 		    (sc->sc_sensors[1].flags & SENSOR_FINVALID))
193 			sc->sc_ii = 2;
194 		if ((sc->sc_sensors[4].flags & SENSOR_FINVALID))
195 			sc->sc_in = 3;
196 	}
197 #else
198 	sc->sc_ii = cmpcap ? 0 : 2;
199 	sc->sc_in = 4;
200 #endif /* !KATE_STRICT */
201 
202 	strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
203 	    sizeof(sc->sc_sensordev.xname));
204 
205 	for (i = sc->sc_ii; i < sc->sc_in; i++) {
206 		sc->sc_sensors[i].type = SENSOR_TEMP;
207 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
208 	}
209 
210 	sensor_task_register(sc, kate_refresh, 5);
211 
212 	sensordev_install(&sc->sc_sensordev);
213 	return 0;
214 }
215 
216 static int
217 kate_detach(struct device *dev)
218 {
219 	struct kate_softc	*sc = device_get_softc(dev);
220 
221 	sensordev_deinstall(&sc->sc_sensordev);
222 	sensor_task_unregister(sc);
223 	return 0;
224 }
225 
226 void
227 kate_refresh(void *arg)
228 {
229 	struct kate_softc	*sc = arg;
230 	struct ksensor		*s = sc->sc_sensors;
231 	uint32_t		t, m;
232 	int			i, v;
233 
234 	t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
235 
236 	for (i = sc->sc_ii; i < sc->sc_in; i++) {
237 		switch(i) {
238 		case 0:
239 			K_T_SEL_C0(t);
240 			K_T_SEL_S0(t);
241 			break;
242 		case 1:
243 			K_T_SEL_C0(t);
244 			K_T_SEL_S1(t);
245 			break;
246 		case 2:
247 			K_T_SEL_C1(t);
248 			K_T_SEL_S0(t);
249 			break;
250 		case 3:
251 			K_T_SEL_C1(t);
252 			K_T_SEL_S1(t);
253 			break;
254 		}
255 		m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
256 		pci_write_config(sc->sc_dev, K_THERMTRIP_STAT_R, t, 4);
257 		t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
258 		v = 0x3ff & (t >> 14);
259 #ifdef KATE_STRICT
260 		if (sc->sc_rev != 'G')
261 			v &= ~0x3;
262 #endif /* KATE_STRICT */
263 		if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
264 		    (v & ~0x3) != 0)
265 			s[i].flags &= ~SENSOR_FINVALID;
266 		else
267 			s[i].flags |= SENSOR_FINVALID;
268 		s[i].value = (v * 250000 - 49000000) + 273150000;
269 	}
270 }
271