54b87e66a7ef7a2541632ccbba8ae35b5cc40c50
[dragonfly.git] / sys / dev / powermng / kate / kate.c
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 <bus/pci/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 < sizeof(kate_proc) / sizeof(kate_proc[0]); 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 < sizeof(kate_proc) / sizeof(kate_proc[0]) &&
169             sc->sc_rev == '\0'; i++)
170                 for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
171                         if ((c & ~0xf) == kate_proc[i].cpuid[j]) {
172                                 sc->sc_rev = kate_proc[i].rev[3];
173                                 device_printf(dev, "core rev %.4s%.1x\n",
174                                     kate_proc[i].rev, c & 0xf);
175                                 break;
176                         }
177
178         if (c != 0x0 && sc->sc_rev == '\0') {
179                 /* CPUID Family Model Register was introduced in Revision F */
180                 sc->sc_rev = 'G';       /* newer than E, assume G */
181                 device_printf(dev, "cpuid 0x%x\n", c);
182         }
183
184         d = pci_read_config(dev, K_NORTHBRIDGE_CAP_R, 4);
185         cmpcap = (d >> 12) & 0x3;
186
187 #ifndef KATE_STRICT
188         sc->sc_ii = 0;
189         sc->sc_in = 4;
190         kate_refresh(sc);
191         if (cmpcap == 0) {
192                 if ((sc->sc_sensors[0].flags & SENSOR_FINVALID) &&
193                     (sc->sc_sensors[1].flags & SENSOR_FINVALID))
194                         sc->sc_ii = 2;
195                 if ((sc->sc_sensors[4].flags & SENSOR_FINVALID))
196                         sc->sc_in = 3;
197         }
198 #else
199         sc->sc_ii = cmpcap ? 0 : 2;
200         sc->sc_in = 4;
201 #endif /* !KATE_STRICT */
202
203         strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
204             sizeof(sc->sc_sensordev.xname));
205
206         for (i = sc->sc_ii; i < sc->sc_in; i++) {
207                 sc->sc_sensors[i].type = SENSOR_TEMP;
208                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
209         }
210
211         if (sensor_task_register(sc, kate_refresh, 5)) {
212                 device_printf(dev, "unable to register update task\n");
213                 return ENXIO;
214         }
215
216         sensordev_install(&sc->sc_sensordev);
217         return 0;
218 }
219
220 static int
221 kate_detach(struct device *dev)
222 {
223         struct kate_softc       *sc = device_get_softc(dev);
224
225         sensordev_deinstall(&sc->sc_sensordev);
226         sensor_task_unregister(sc);
227         return 0;
228 }
229
230 void
231 kate_refresh(void *arg)
232 {
233         struct kate_softc       *sc = arg;
234         struct ksensor          *s = sc->sc_sensors;
235         uint32_t                t, m;
236         int                     i, v;
237
238         t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
239
240         for (i = sc->sc_ii; i < sc->sc_in; i++) {
241                 switch(i) {
242                 case 0:
243                         K_T_SEL_C0(t);
244                         K_T_SEL_S0(t);
245                         break;
246                 case 1:
247                         K_T_SEL_C0(t);
248                         K_T_SEL_S1(t);
249                         break;
250                 case 2:
251                         K_T_SEL_C1(t);
252                         K_T_SEL_S0(t);
253                         break;
254                 case 3:
255                         K_T_SEL_C1(t);
256                         K_T_SEL_S1(t);
257                         break;
258                 }
259                 m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
260                 pci_write_config(sc->sc_dev, K_THERMTRIP_STAT_R, t, 4);
261                 t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
262                 v = 0x3ff & (t >> 14);
263 #ifdef KATE_STRICT
264                 if (sc->sc_rev != 'G')
265                         v &= ~0x3;
266 #endif /* KATE_STRICT */
267                 if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
268                     (v & ~0x3) != 0)
269                         s[i].flags &= ~SENSOR_FINVALID;
270                 else
271                         s[i].flags |= SENSOR_FINVALID;
272                 s[i].value = (v * 250000 - 49000000) + 273150000;
273         }
274 }