kernel: Generate miidevs.h, pccarddevs.h and pcidevs.h on the fly.
[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 "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         if (sensor_task_register(sc, kate_refresh, 5)) {
211                 device_printf(dev, "unable to register update task\n");
212                 return ENXIO;
213         }
214
215         sensordev_install(&sc->sc_sensordev);
216         return 0;
217 }
218
219 static int
220 kate_detach(struct device *dev)
221 {
222         struct kate_softc       *sc = device_get_softc(dev);
223
224         sensordev_deinstall(&sc->sc_sensordev);
225         sensor_task_unregister(sc);
226         return 0;
227 }
228
229 void
230 kate_refresh(void *arg)
231 {
232         struct kate_softc       *sc = arg;
233         struct ksensor          *s = sc->sc_sensors;
234         uint32_t                t, m;
235         int                     i, v;
236
237         t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
238
239         for (i = sc->sc_ii; i < sc->sc_in; i++) {
240                 switch(i) {
241                 case 0:
242                         K_T_SEL_C0(t);
243                         K_T_SEL_S0(t);
244                         break;
245                 case 1:
246                         K_T_SEL_C0(t);
247                         K_T_SEL_S1(t);
248                         break;
249                 case 2:
250                         K_T_SEL_C1(t);
251                         K_T_SEL_S0(t);
252                         break;
253                 case 3:
254                         K_T_SEL_C1(t);
255                         K_T_SEL_S1(t);
256                         break;
257                 }
258                 m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
259                 pci_write_config(sc->sc_dev, K_THERMTRIP_STAT_R, t, 4);
260                 t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
261                 v = 0x3ff & (t >> 14);
262 #ifdef KATE_STRICT
263                 if (sc->sc_rev != 'G')
264                         v &= ~0x3;
265 #endif /* KATE_STRICT */
266                 if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
267                     (v & ~0x3) != 0)
268                         s[i].flags &= ~SENSOR_FINVALID;
269                 else
270                         s[i].flags |= SENSOR_FINVALID;
271                 s[i].value = (v * 250000 - 49000000) + 273150000;
272         }
273 }