xref: /openbsd/sys/dev/pci/kate.c (revision 5dea098c)
1 /*	$OpenBSD: kate.c,v 1.8 2022/03/11 18:00:50 mpi Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@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/device.h>
22 #include <sys/sensors.h>
23 
24 #include <dev/pci/pcireg.h>
25 #include <dev/pci/pcivar.h>
26 #include <dev/pci/pcidevs.h>
27 
28 
29 /*
30  * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control
31  */
32 
33 /* Function 3 Registers */
34 #define K_THERMTRIP_STAT_R	0xe4
35 #define K_NORTHBRIDGE_CAP_R	0xe8
36 #define K_CPUID_FAMILY_MODEL_R	0xfc
37 
38 /* Bits within Thermtrip Status Register */
39 #define K_THERM_SENSE_SEL	(1 << 6)
40 #define K_THERM_SENSE_CORE_SEL	(1 << 2)
41 
42 /* Flip core and sensor selection bits */
43 #define K_T_SEL_C0(v)		(v |= K_THERM_SENSE_CORE_SEL)
44 #define K_T_SEL_C1(v)		(v &= ~(K_THERM_SENSE_CORE_SEL))
45 #define K_T_SEL_S0(v)		(v &= ~(K_THERM_SENSE_SEL))
46 #define K_T_SEL_S1(v)		(v |= K_THERM_SENSE_SEL)
47 
48 
49 /*
50  * Revision Guide for AMD NPT Family 0Fh Processors,
51  * Publication # 33610, Revision 3.30, February 2008
52  */
53 static const struct {
54 	const char	rev[5];
55 	const pcireg_t	cpuid[5];
56 } kate_proc[] = {
57 	{ "BH-F", { 0x00040FB0, 0x00040F80, 0, 0, 0 } },	/* F2 */
58 	{ "DH-F", { 0x00040FF0, 0x00050FF0, 0x00040FC0, 0, 0 } }, /* F2, F3 */
59 	{ "JH-F", { 0x00040F10, 0x00040F30, 0x000C0F10, 0, 0 } }, /* F2, F3 */
60 	{ "BH-G", { 0x00060FB0, 0x00060F80, 0, 0, 0 } },	/* G1, G2 */
61 	{ "DH-G", { 0x00070FF0, 0x00060FF0,
62 	    0x00060FC0, 0x00070FC0, 0 } }	/* G1, G2 */
63 };
64 
65 
66 struct kate_softc {
67 	struct device		sc_dev;
68 
69 	pci_chipset_tag_t	sc_pc;
70 	pcitag_t		sc_pcitag;
71 
72 	struct ksensor		sc_sensors[4];
73 	struct ksensordev	sc_sensordev;
74 
75 	char			sc_rev;
76 	int8_t			sc_numsensors;
77 };
78 
79 int	kate_match(struct device *, void *, void *);
80 void	kate_attach(struct device *, struct device *, void *);
81 void	kate_refresh(void *);
82 
83 const struct cfattach kate_ca = {
84 	sizeof(struct kate_softc), kate_match, kate_attach
85 };
86 
87 struct cfdriver kate_cd = {
88 	NULL, "kate", DV_DULL
89 };
90 
91 
92 int
93 kate_match(struct device *parent, void *match, void *aux)
94 {
95 	struct pci_attach_args	*pa = aux;
96 #ifndef KATE_STRICT
97 	struct kate_softc	ks;
98 	struct kate_softc	*sc = &ks;
99 #endif /* !KATE_STRICT */
100 	pcireg_t		c;
101 	int			i, j;
102 
103 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD ||
104 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_AMD_0F_MISC)
105 		return 0;
106 
107 	/*
108 	 * First, let's probe for chips at or after Revision F, which is
109 	 * when the temperature readings were officially introduced.
110 	 */
111 	c = pci_conf_read(pa->pa_pc, pa->pa_tag, K_CPUID_FAMILY_MODEL_R);
112 	for (i = 0; i < sizeof(kate_proc) / sizeof(kate_proc[0]); i++)
113 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
114 			if ((c & ~0xf) == kate_proc[i].cpuid[j])
115 				return 2;	/* supersede pchb(4) */
116 
117 #ifndef KATE_STRICT
118 	/*
119 	 * If the probe above was not successful, let's try to actually
120 	 * read the sensors from the chip, and see if they make any sense.
121 	 */
122 	sc->sc_numsensors = 4;
123 	sc->sc_pc = pa->pa_pc;
124 	sc->sc_pcitag = pa->pa_tag;
125 	kate_refresh(sc);
126 	for (i = 0; i < sc->sc_numsensors; i++)
127 		if (!(sc->sc_sensors[i].flags & SENSOR_FINVALID))
128 			return 2;	/* supersede pchb(4) */
129 #endif /* !KATE_STRICT */
130 
131 	return 0;
132 }
133 
134 void
135 kate_attach(struct device *parent, struct device *self, void *aux)
136 {
137 	struct kate_softc	*sc = (struct kate_softc *)self;
138 	struct pci_attach_args	*pa = aux;
139 	pcireg_t		c, d;
140 	int			i, j, cmpcap;
141 
142 	c = pci_conf_read(pa->pa_pc, pa->pa_tag, K_CPUID_FAMILY_MODEL_R);
143 	for (i = 0; i < sizeof(kate_proc) / sizeof(kate_proc[0]) &&
144 	    sc->sc_rev == '\0'; i++)
145 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
146 			if ((c & ~0xf) == kate_proc[i].cpuid[j]) {
147 				sc->sc_rev = kate_proc[i].rev[3];
148 				printf(": core rev %.4s%.1x",
149 				    kate_proc[i].rev, c & 0xf);
150 			}
151 
152 	if (c != 0x0 && sc->sc_rev == '\0') {
153 		/* CPUID Family Model Register was introduced in Revision F */
154 		sc->sc_rev = 'G';	/* newer than E, assume G */
155 		printf(": cpuid 0x%x", c);
156 	}
157 
158 	d = pci_conf_read(pa->pa_pc, pa->pa_tag, K_NORTHBRIDGE_CAP_R);
159 	cmpcap = (d >> 12) & 0x3;
160 
161 	sc->sc_pc = pa->pa_pc;
162 	sc->sc_pcitag = pa->pa_tag;
163 
164 #ifndef KATE_STRICT
165 	sc->sc_numsensors = 4;
166 	kate_refresh(sc);
167 	if (cmpcap == 0 &&
168 	    (sc->sc_sensors[2].flags & SENSOR_FINVALID) &&
169 	    (sc->sc_sensors[3].flags & SENSOR_FINVALID))
170 		sc->sc_numsensors = 2;
171 #else
172 	sc->sc_numsensors = cmpcap ? 4 : 2;
173 #endif /* !KATE_STRICT */
174 
175 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
176 	    sizeof(sc->sc_sensordev.xname));
177 
178 	for (i = 0; i < sc->sc_numsensors; i++) {
179 		sc->sc_sensors[i].type = SENSOR_TEMP;
180 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
181 	}
182 
183 	if (sensor_task_register(sc, kate_refresh, 5) == NULL) {
184 		printf(": unable to register update task\n");
185 		return;
186 	}
187 
188 	sensordev_install(&sc->sc_sensordev);
189 
190 	printf("\n");
191 }
192 
193 void
194 kate_refresh(void *arg)
195 {
196 	struct kate_softc	*sc = arg;
197 	struct ksensor		*s = sc->sc_sensors;
198 	int8_t			n = sc->sc_numsensors;
199 	pcireg_t		t, m;
200 	int			i, v;
201 
202 	t = pci_conf_read(sc->sc_pc, sc->sc_pcitag, K_THERMTRIP_STAT_R);
203 
204 	for (i = 0; i < n; i++) {
205 		switch(i) {
206 		case 0:
207 			K_T_SEL_C0(t);
208 			K_T_SEL_S0(t);
209 			break;
210 		case 1:
211 			K_T_SEL_C0(t);
212 			K_T_SEL_S1(t);
213 			break;
214 		case 2:
215 			K_T_SEL_C1(t);
216 			K_T_SEL_S0(t);
217 			break;
218 		case 3:
219 			K_T_SEL_C1(t);
220 			K_T_SEL_S1(t);
221 			break;
222 		}
223 		m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
224 		pci_conf_write(sc->sc_pc, sc->sc_pcitag, K_THERMTRIP_STAT_R, t);
225 		t = pci_conf_read(sc->sc_pc, sc->sc_pcitag, K_THERMTRIP_STAT_R);
226 		v = 0x3ff & (t >> 14);
227 #ifdef KATE_STRICT
228 		if (sc->sc_rev != 'G')
229 			v &= ~0x3;
230 #endif /* KATE_STRICT */
231 		if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
232 		    (v & ~0x3) != 0)
233 			s[i].flags &= ~SENSOR_FINVALID;
234 		else
235 			s[i].flags |= SENSOR_FINVALID;
236 		s[i].value = (v * 250000 - 49000000) + 273150000;
237 	}
238 }
239