kernel: Replace struct device* by device_t
[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 <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
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
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
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
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
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 }