Annotation of sys/arch/i386/pci/ichpcib.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ichpcib.c,v 1.19 2007/06/02 18:39:57 jsg Exp $ */
2: /*
3: * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /*
19: * Special driver for the Intel ICHx/ICHx-M LPC bridges that attaches
20: * instead of pcib(4). In addition to the core pcib(4) functionality this
21: * driver provides support for the Intel SpeedStep technology and
22: * power management timer.
23: */
24:
25: #include <sys/param.h>
26: #include <sys/systm.h>
27: #include <sys/device.h>
28: #include <sys/sysctl.h>
29: #ifdef __HAVE_TIMECOUNTER
30: #include <sys/timetc.h>
31: #endif
32:
33: #include <machine/bus.h>
34:
35: #include <dev/pci/pcireg.h>
36: #include <dev/pci/pcivar.h>
37: #include <dev/pci/pcidevs.h>
38:
39: #include <dev/pci/ichreg.h>
40:
41: #include <machine/cpu.h>
42: #include <machine/cpufunc.h>
43:
44: struct ichpcib_softc {
45: struct device sc_dev;
46:
47: bus_space_tag_t sc_pm_iot;
48: bus_space_handle_t sc_pm_ioh;
49: };
50:
51: int ichpcib_match(struct device *, void *, void *);
52: void ichpcib_attach(struct device *, struct device *, void *);
53:
54: int ichss_present(struct pci_attach_args *);
55: void ichss_setperf(int);
56:
57: /* arch/i386/pci/pcib.c */
58: void pcibattach(struct device *, struct device *, void *);
59:
60: #ifdef __HAVE_TIMECOUNTER
61: u_int ichpcib_get_timecount(struct timecounter *tc);
62:
63: struct timecounter ichpcib_timecounter = {
64: ichpcib_get_timecount, /* get_timecount */
65: 0, /* no poll_pps */
66: 0xffffff, /* counter_mask */
67: 3579545, /* frequency */
68: "ICHPM", /* name */
69: 1000 /* quality */
70: };
71: #endif /* __HAVE_TIMECOUNTER */
72:
73: struct cfattach ichpcib_ca = {
74: sizeof(struct ichpcib_softc),
75: ichpcib_match,
76: ichpcib_attach
77: };
78:
79: struct cfdriver ichpcib_cd = {
80: NULL, "ichpcib", DV_DULL
81: };
82:
83: #ifndef SMALL_KERNEL
84: static const char p4hint[] = "Mobile Intel(R) Pentium(R) 4";
85: struct ichpcib_softc *ichss_sc;
86: extern int setperf_prio;
87: #endif /* !SMALL_KERNEL */
88:
89: const struct pci_matchid ichpcib_devices[] = {
90: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_LPC },
91: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_LPC },
92: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC },
93: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC },
94: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC },
95: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC },
96: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC },
97: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC },
98: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC },
99: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DBM_LPC },
100: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_LPC },
101: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC },
102: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_LPC },
103: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC },
104: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_LPC },
105: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GBM_LPC },
106: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GH_LPC },
107: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GHM_LPC },
108: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_LPC },
109: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801HBM_LPC }
110: };
111:
112: int
113: ichpcib_match(struct device *parent, void *match, void *aux)
114: {
115: if (pci_matchbyid((struct pci_attach_args *)aux, ichpcib_devices,
116: sizeof(ichpcib_devices) / sizeof(ichpcib_devices[0])))
117: return (2); /* supersede pcib(4) */
118: return (0);
119: }
120:
121: void
122: ichpcib_attach(struct device *parent, struct device *self, void *aux)
123: {
124: struct ichpcib_softc *sc = (struct ichpcib_softc *)self;
125: struct pci_attach_args *pa = aux;
126: pcireg_t cntl, pmbase;
127:
128: /* Check if power management I/O space is enabled */
129: cntl = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_ACPI_CNTL);
130: if ((cntl & ICH_ACPI_CNTL_ACPI_EN) == 0) {
131: printf(": PM disabled");
132: goto corepcib;
133: }
134:
135: /* Map power management I/O space */
136: sc->sc_pm_iot = pa->pa_iot;
137: pmbase = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PMBASE);
138: if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(pmbase),
139: ICH_PMSIZE, 0, &sc->sc_pm_ioh) != 0)
140: goto corepcib;
141:
142: #ifdef __HAVE_TIMECOUNTER
143: /* Register new timecounter */
144: ichpcib_timecounter.tc_priv = sc;
145: tc_init(&ichpcib_timecounter);
146:
147: printf(": %s-bit timer at %lluHz",
148: (ichpcib_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"),
149: (unsigned long long)ichpcib_timecounter.tc_frequency);
150: #endif /* __HAVE_TIMECOUNTER */
151:
152: #ifndef SMALL_KERNEL
153: /* Check for SpeedStep */
154: if (ichss_present(pa)) {
155: printf(": SpeedStep");
156:
157: /* Enable SpeedStep */
158: pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1,
159: pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_GEN_PMCON1) |
160: ICH_GEN_PMCON1_SS_EN);
161:
162: /* Hook into hw.setperf sysctl */
163: ichss_sc = sc;
164: cpu_setperf = ichss_setperf;
165: setperf_prio = 2;
166: }
167: #endif /* !SMALL_KERNEL */
168:
169: corepcib:
170: /* Provide core pcib(4) functionality */
171: pcibattach(parent, self, aux);
172: }
173:
174: #ifndef SMALL_KERNEL
175: int
176: ichss_present(struct pci_attach_args *pa)
177: {
178: pcitag_t br_tag;
179: pcireg_t br_id, br_class;
180: struct cpu_info *ci;
181: int family, model, stepping, brandid;
182:
183: if (setperf_prio > 2)
184: return (0);
185:
186: ci = curcpu();
187: family = (ci->ci_signature >> 8) & 15;
188: model = (ci->ci_signature >> 4) & 15;
189: stepping = ci->ci_signature & 15;
190: brandid = cpu_miscinfo & 0xff; /* XXX should put this in ci */
191:
192: /*
193: * This form of SpeedStep works only on Intel Mobile Pentium 4.
194: * Intel Celeron processors don't support it. However, they
195: * can be coupled with ICH southbridges that do, causing false
196: * positives. So we ensure that we are running on Intel Mobile
197: * Pentium 4.
198: * This heuristic comes from the Linux speedstep-ich driver.
199: */
200: if (!(family == 15 && model == 2 &&
201: ((stepping == 4 && (brandid == 14 || brandid == 15)) ||
202: (stepping == 7 && brandid == 14) ||
203: (stepping == 9 && (brandid == 14 || strncasecmp(cpu_model, p4hint,
204: sizeof(p4hint) - 1) == 0)))))
205: return (0);
206:
207: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DBM_LPC ||
208: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801CAM_LPC)
209: return (1);
210: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801BAM_LPC) {
211: /*
212: * Old revisions of the 82815 hostbridge found on
213: * Dell Inspirons 8000 and 8100 don't support
214: * SpeedStep.
215: */
216: /*
217: * XXX: dev 0 func 0 is not always a hostbridge,
218: * should be converted to use pchb(4) hook.
219: */
220: br_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, 0, 0);
221: br_id = pci_conf_read(pa->pa_pc, br_tag, PCI_ID_REG);
222: br_class = pci_conf_read(pa->pa_pc, br_tag, PCI_CLASS_REG);
223:
224: if (PCI_PRODUCT(br_id) == PCI_PRODUCT_INTEL_82815_FULL_HUB &&
225: PCI_REVISION(br_class) < 5)
226: return (0);
227: return (1);
228: }
229:
230: return (0);
231: }
232:
233: void
234: ichss_setperf(int level)
235: {
236: struct ichpcib_softc *sc = ichss_sc;
237: u_int8_t state, ostate, cntl;
238: int s;
239:
240: #ifdef DIAGNOSTIC
241: if (sc == NULL) {
242: printf("%s: no ichss_sc", __func__);
243: return;
244: }
245: #endif
246:
247: s = splhigh();
248: state = bus_space_read_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_SS_CNTL);
249: ostate = state;
250:
251: /* Only two states are available */
252: if (level <= 50)
253: state |= ICH_PM_SS_STATE_LOW;
254: else
255: state &= ~ICH_PM_SS_STATE_LOW;
256:
257: /*
258: * An Intel SpeedStep technology transition _always_ occur on
259: * writes to the ICH_PM_SS_CNTL register, even if the value
260: * written is the same as the previous value. So do the write
261: * only if the state has changed.
262: */
263: if (state != ostate) {
264: /* Disable bus mastering arbitration */
265: cntl = bus_space_read_1(sc->sc_pm_iot, sc->sc_pm_ioh,
266: ICH_PM_CNTL);
267: bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_CNTL,
268: cntl | ICH_PM_ARB_DIS);
269:
270: /* Do the transition */
271: bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_SS_CNTL,
272: state);
273:
274: /* Restore bus mastering arbitration state */
275: bus_space_write_1(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_CNTL,
276: cntl);
277:
278: #ifdef I686_CPU
279: if (update_cpuspeed != NULL)
280: update_cpuspeed();
281: #endif
282: }
283: splx(s);
284: }
285: #endif /* !SMALL_KERNEL */
286:
287: #ifdef __HAVE_TIMECOUNTER
288: u_int
289: ichpcib_get_timecount(struct timecounter *tc)
290: {
291: struct ichpcib_softc *sc = tc->tc_priv;
292: u_int u1, u2, u3;
293:
294: u2 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_TMR);
295: u3 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh, ICH_PM_TMR);
296: do {
297: u1 = u2;
298: u2 = u3;
299: u3 = bus_space_read_4(sc->sc_pm_iot, sc->sc_pm_ioh,
300: ICH_PM_TMR);
301: } while (u1 > u2 || u2 > u3);
302:
303: return (u2);
304: }
305: #endif /* __HAVE_TIMECOUNTER */
CVSweb