xref: /dragonfly/sys/dev/powermng/kate/kate.c (revision 5d302545124b16bb6e9f48d720cba81afba1adb3)
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 <machine/specialreg.h>
25 
26 #include <bus/pci/pcivar.h>
27 #include "pcidevs.h"
28 
29 
30 /*
31  * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control
32  */
33 
34 /* Function 3 Registers */
35 #define K_THERMTRIP_STAT_R    0xe4
36 #define K_NORTHBRIDGE_CAP_R   0xe8
37 #define K_CPUID_FAMILY_MODEL_R          0xfc
38 
39 /* Bits within Thermtrip Status Register */
40 #define K_THERM_SENSE_SEL     (1 << 6)
41 #define K_THERM_SENSE_CORE_SEL          (1 << 2)
42 
43 /* Flip core and sensor selection bits */
44 #define K_T_SEL_C0(v)                   (v |= K_THERM_SENSE_CORE_SEL)
45 #define K_T_SEL_C1(v)                   (v &= ~(K_THERM_SENSE_CORE_SEL))
46 #define K_T_SEL_S0(v)                   (v &= ~(K_THERM_SENSE_SEL))
47 #define K_T_SEL_S1(v)                   (v |= K_THERM_SENSE_SEL)
48 
49 
50 /*
51  * Revision Guide for AMD NPT Family 0Fh Processors,
52  * Publication # 33610, Revision 3.30, February 2008
53  */
54 static const struct {
55           const char          rev[5];
56           const uint32_t      cpuid[5];
57 } kate_proc[] = {
58           { "BH-F", { 0x00040FB0, 0x00040F80, 0, 0, 0 } },  /* F2 */
59           { "DH-F", { 0x00040FF0, 0x00050FF0, 0x00040FC0, 0, 0 } }, /* F2, F3 */
60           { "JH-F", { 0x00040F10, 0x00040F30, 0x000C0F10, 0, 0 } }, /* F2, F3 */
61           { "BH-G", { 0x00060FB0, 0x00060F80, 0, 0, 0 } },  /* G1, G2 */
62           { "DH-G", { 0x00070FF0, 0x00060FF0,
63               0x00060FC0, 0x00070FC0, 0 } }       /* G1, G2 */
64 };
65 
66 
67 struct kate_softc {
68           device_t            sc_dev;
69 
70           struct ksensor                sc_sensors[4];
71           struct ksensordev   sc_sensordev;
72 
73           char                          sc_rev;
74           int8_t                        sc_ii;
75           int8_t                        sc_in;
76           int32_t                       sc_flags;
77 #define   KATE_FLAG_ALT_OFFSET          0x04      /* CurTmp starts at -28C. */
78 };
79 
80 static void         kate_identify(driver_t *, device_t);
81 static int          kate_probe(device_t);
82 static int          kate_attach(device_t);
83 static int          kate_detach(device_t);
84 static void         kate_refresh(void *);
85 
86 static device_method_t kate_methods[] = {
87           DEVMETHOD(device_identify,    kate_identify),
88           DEVMETHOD(device_probe,                 kate_probe),
89           DEVMETHOD(device_attach,      kate_attach),
90           DEVMETHOD(device_detach,      kate_detach),
91           { NULL, NULL }
92 };
93 
94 static driver_t kate_driver = {
95           "kate",
96           kate_methods,
97           sizeof(struct kate_softc)
98 };
99 
100 static devclass_t kate_devclass;
101 
102 DRIVER_MODULE(kate, hostb, kate_driver, kate_devclass, NULL, NULL);
103 
104 
105 static void
kate_identify(driver_t * driver,device_t parent)106 kate_identify(driver_t *driver, device_t parent)
107 {
108           if (kate_probe(parent) == ENXIO)
109                     return;
110           if (device_find_child(parent, driver->name, -1) != NULL)
111                     return;
112           device_add_child(parent, driver->name, -1);
113 }
114 
115 static int
kate_probe(device_t dev)116 kate_probe(device_t dev)
117 {
118 #ifndef KATE_STRICT
119           struct kate_softc   ks;
120           struct kate_softc   *sc = &ks;
121 #endif
122           uint32_t            c;
123           int                           i, j;
124 
125           if (pci_get_vendor(dev) != PCI_VENDOR_AMD ||
126               pci_get_device(dev) != PCI_PRODUCT_AMD_AMD64_MISC)
127                     return ENXIO;
128 
129           /* just in case we probe successfully, set the description */
130           if (device_get_desc(dev) == NULL)
131                     device_set_desc(dev,
132                         "AMD Family 0Fh temperature sensors");
133 
134           /*
135            * First, let's probe for chips at or after Revision F, which is
136            * when the temperature readings were officially introduced.
137            */
138           c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
139           for (i = 0; i < NELEM(kate_proc); i++)
140                     for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
141                               if ((c & ~0xf) == kate_proc[i].cpuid[j])
142                                         return 0;
143 
144 #ifndef KATE_STRICT
145           /*
146            * If the probe above was not successful, let's try to actually
147            * read the sensors from the chip, and see if they make any sense.
148            */
149           sc->sc_ii = 0;
150           sc->sc_in = 4;
151           sc->sc_dev = dev;
152           kate_refresh(sc);
153           for (i = 0; i < 4; i++)
154                     if (!(sc->sc_sensors[i].flags & SENSOR_FINVALID))
155                               return 0;
156 #endif /* !KATE_STRICT */
157 
158           return ENXIO;
159 }
160 
161 static int
kate_attach(device_t dev)162 kate_attach(device_t dev)
163 {
164           struct kate_softc   *sc;
165           uint32_t            c, d;
166           int                           i, j, cmpcap, model;
167           u_int                         regs[4], brand_id;
168 
169           sc = device_get_softc(dev);
170           sc->sc_dev = dev;
171 
172           c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
173           for (i = 0; i < NELEM(kate_proc) && sc->sc_rev == '\0'; i++)
174                     for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
175                               if ((c & ~0xf) == kate_proc[i].cpuid[j]) {
176                                         sc->sc_rev = kate_proc[i].rev[3];
177                                         device_printf(dev, "core rev %.4s%.1x\n",
178                                             kate_proc[i].rev, c & 0xf);
179                                         break;
180                               }
181 
182           if (c != 0x0 && sc->sc_rev == '\0') {
183                     /* CPUID Family Model Register was introduced in Revision F */
184                     sc->sc_rev = 'G';   /* newer than E, assume G */
185                     device_printf(dev, "cpuid 0x%x\n", c);
186           }
187 
188           model = CPUID_TO_MODEL(c);
189           if (model >= 0x60 && model != 0xc1) {
190                     do_cpuid(0x80000001, regs);
191                     brand_id = (regs[1] >> 9) & 0x1f;
192 
193                     switch (model) {
194                     case 0x68: /* Socket S1g1 */
195                     case 0x6c:
196                     case 0x7c:
197                               break;
198                     case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
199                               if (brand_id != 0x0b && brand_id != 0x0c)
200                                         sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
201                               break;
202                     case 0x6f: /* Socket AM2 and ASB1 (1 core) */
203                     case 0x7f:
204                               if (brand_id != 0x07 && brand_id != 0x09 &&
205                                   brand_id != 0x0c)
206                                         sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
207                               break;
208                     default:
209                               sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
210                     }
211           }
212 
213           d = pci_read_config(dev, K_NORTHBRIDGE_CAP_R, 4);
214           cmpcap = (d >> 12) & 0x3;
215 
216 #ifndef KATE_STRICT
217           sc->sc_ii = 0;
218           sc->sc_in = 4;
219           kate_refresh(sc);
220           if (cmpcap == 0) {
221                     if ((sc->sc_sensors[0].flags & SENSOR_FINVALID) &&
222                         (sc->sc_sensors[1].flags & SENSOR_FINVALID))
223                               sc->sc_ii = 2;
224                     if ((sc->sc_sensors[3].flags & SENSOR_FINVALID))
225                               sc->sc_in = 3;
226           }
227 #else
228           sc->sc_ii = cmpcap ? 0 : 2;
229           sc->sc_in = 4;
230 #endif /* !KATE_STRICT */
231 
232           strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
233               sizeof(sc->sc_sensordev.xname));
234 
235           for (i = sc->sc_ii; i < sc->sc_in; i++) {
236                     sc->sc_sensors[i].type = SENSOR_TEMP;
237                     sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
238           }
239 
240           sensor_task_register(sc, kate_refresh, 5);
241 
242           sensordev_install(&sc->sc_sensordev);
243           return 0;
244 }
245 
246 static int
kate_detach(device_t dev)247 kate_detach(device_t dev)
248 {
249           struct kate_softc   *sc = device_get_softc(dev);
250 
251           sensordev_deinstall(&sc->sc_sensordev);
252           sensor_task_unregister(sc);
253           return 0;
254 }
255 
256 static void
kate_refresh(void * arg)257 kate_refresh(void *arg)
258 {
259           struct kate_softc   *sc = arg;
260           struct ksensor                *s = sc->sc_sensors;
261           uint32_t            t, m;
262           int64_t                       temp;
263           int                           i, v;
264 
265           t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
266 
267           for (i = sc->sc_ii; i < sc->sc_in; i++) {
268                     switch(i) {
269                     case 0:
270                               K_T_SEL_C0(t);
271                               K_T_SEL_S0(t);
272                               break;
273                     case 1:
274                               K_T_SEL_C0(t);
275                               K_T_SEL_S1(t);
276                               break;
277                     case 2:
278                               K_T_SEL_C1(t);
279                               K_T_SEL_S0(t);
280                               break;
281                     case 3:
282                               K_T_SEL_C1(t);
283                               K_T_SEL_S1(t);
284                               break;
285                     }
286                     m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
287                     pci_write_config(sc->sc_dev, K_THERMTRIP_STAT_R, t, 4);
288                     t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
289                     v = 0x3ff & (t >> 14);
290 #ifdef KATE_STRICT
291                     if (sc->sc_rev != 'G')
292                               v &= ~0x3;
293 #endif /* KATE_STRICT */
294                     if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
295                         (v & ~0x3) != 0)
296                               s[i].flags &= ~SENSOR_FINVALID;
297                     else
298                               s[i].flags |= SENSOR_FINVALID;
299                     temp = v * 250000;
300                     temp -= (sc->sc_flags & KATE_FLAG_ALT_OFFSET) != 0 ?
301                         28000000 : 49000000;
302                     temp += 273150000;
303                     s[i].value = temp;
304           }
305 }
306