| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ichlpcib.c,v 1.15 2009/03/03 06:05:28 mrg Exp $ */ | | 1 | /* $NetBSD: ichlpcib.c,v 1.16 2009/04/04 23:13:18 joerg Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2004 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2004 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Minoura Makoto and Matthew R. Green. | | 8 | * by Minoura Makoto and Matthew R. Green. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -29,27 +29,27 @@ | | | @@ -29,27 +29,27 @@ |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Intel I/O Controller Hub (ICHn) LPC Interface Bridge driver | | 33 | * Intel I/O Controller Hub (ICHn) LPC Interface Bridge driver |
34 | * | | 34 | * |
35 | * LPC Interface Bridge is basically a pcib (PCI-ISA Bridge), but has | | 35 | * LPC Interface Bridge is basically a pcib (PCI-ISA Bridge), but has |
36 | * some power management and monitoring functions. | | 36 | * some power management and monitoring functions. |
37 | * Currently we support the watchdog timer, SpeedStep (on some systems) | | 37 | * Currently we support the watchdog timer, SpeedStep (on some systems) |
38 | * and the power management timer. | | 38 | * and the power management timer. |
39 | */ | | 39 | */ |
40 | | | 40 | |
41 | #include <sys/cdefs.h> | | 41 | #include <sys/cdefs.h> |
42 | __KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.15 2009/03/03 06:05:28 mrg Exp $"); | | 42 | __KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.16 2009/04/04 23:13:18 joerg Exp $"); |
43 | | | 43 | |
44 | #include <sys/types.h> | | 44 | #include <sys/types.h> |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/systm.h> | | 46 | #include <sys/systm.h> |
47 | #include <sys/device.h> | | 47 | #include <sys/device.h> |
48 | #include <sys/sysctl.h> | | 48 | #include <sys/sysctl.h> |
49 | #include <sys/timetc.h> | | 49 | #include <sys/timetc.h> |
50 | #include <machine/bus.h> | | 50 | #include <machine/bus.h> |
51 | | | 51 | |
52 | #include <dev/pci/pcivar.h> | | 52 | #include <dev/pci/pcivar.h> |
53 | #include <dev/pci/pcireg.h> | | 53 | #include <dev/pci/pcireg.h> |
54 | #include <dev/pci/pcidevs.h> | | 54 | #include <dev/pci/pcidevs.h> |
55 | | | 55 | |
| @@ -76,36 +76,40 @@ struct lpcib_softc { | | | @@ -76,36 +76,40 @@ struct lpcib_softc { |
76 | bus_space_handle_t sc_rcbah; | | 76 | bus_space_handle_t sc_rcbah; |
77 | pcireg_t sc_rcba_reg; | | 77 | pcireg_t sc_rcba_reg; |
78 | | | 78 | |
79 | /* Watchdog variables. */ | | 79 | /* Watchdog variables. */ |
80 | struct sysmon_wdog sc_smw; | | 80 | struct sysmon_wdog sc_smw; |
81 | bus_space_tag_t sc_iot; | | 81 | bus_space_tag_t sc_iot; |
82 | bus_space_handle_t sc_ioh; | | 82 | bus_space_handle_t sc_ioh; |
83 | | | 83 | |
84 | #if NHPET > 0 | | 84 | #if NHPET > 0 |
85 | /* HPET variables. */ | | 85 | /* HPET variables. */ |
86 | uint32_t sc_hpet_reg; | | 86 | uint32_t sc_hpet_reg; |
87 | #endif | | 87 | #endif |
88 | | | 88 | |
| | | 89 | /* Speedstep */ |
| | | 90 | pcireg_t sc_pmcon_orig; |
| | | 91 | |
89 | /* Power management */ | | 92 | /* Power management */ |
90 | pcireg_t sc_pirq[2]; | | 93 | pcireg_t sc_pirq[2]; |
91 | pcireg_t sc_pmcon; | | 94 | pcireg_t sc_pmcon; |
92 | pcireg_t sc_fwhsel2; | | 95 | pcireg_t sc_fwhsel2; |
93 | }; | | 96 | }; |
94 | | | 97 | |
95 | static int lpcibmatch(device_t, cfdata_t, void *); | | 98 | static int lpcibmatch(device_t, cfdata_t, void *); |
96 | static void lpcibattach(device_t, device_t, void *); | | 99 | static void lpcibattach(device_t, device_t, void *); |
97 | static bool lpcib_suspend(device_t PMF_FN_PROTO); | | 100 | static bool lpcib_suspend(device_t PMF_FN_PROTO); |
98 | static bool lpcib_resume(device_t PMF_FN_PROTO); | | 101 | static bool lpcib_resume(device_t PMF_FN_PROTO); |
| | | 102 | static bool lpcib_shutdown(device_t, int); |
99 | | | 103 | |
100 | static void pmtimer_configure(device_t); | | 104 | static void pmtimer_configure(device_t); |
101 | | | 105 | |
102 | static void tcotimer_configure(device_t); | | 106 | static void tcotimer_configure(device_t); |
103 | static int tcotimer_setmode(struct sysmon_wdog *); | | 107 | static int tcotimer_setmode(struct sysmon_wdog *); |
104 | static int tcotimer_tickle(struct sysmon_wdog *); | | 108 | static int tcotimer_tickle(struct sysmon_wdog *); |
105 | static void tcotimer_stop(struct lpcib_softc *); | | 109 | static void tcotimer_stop(struct lpcib_softc *); |
106 | static void tcotimer_start(struct lpcib_softc *); | | 110 | static void tcotimer_start(struct lpcib_softc *); |
107 | static void tcotimer_status_reset(struct lpcib_softc *); | | 111 | static void tcotimer_status_reset(struct lpcib_softc *); |
108 | static int tcotimer_disable_noreboot(device_t); | | 112 | static int tcotimer_disable_noreboot(device_t); |
109 | | | 113 | |
110 | static void speedstep_configure(device_t); | | 114 | static void speedstep_configure(device_t); |
111 | static int speedstep_sysctl_helper(SYSCTLFN_ARGS); | | 115 | static int speedstep_sysctl_helper(SYSCTLFN_ARGS); |
| @@ -195,26 +199,29 @@ lpcibattach(device_t parent, device_t se | | | @@ -195,26 +199,29 @@ lpcibattach(device_t parent, device_t se |
195 | pcibattach(parent, self, aux); | | 199 | pcibattach(parent, self, aux); |
196 | | | 200 | |
197 | /* | | 201 | /* |
198 | * Part of our I/O registers are used as ACPI PM regs. | | 202 | * Part of our I/O registers are used as ACPI PM regs. |
199 | * Since our ACPI subsystem accesses the I/O space directly so far, | | 203 | * Since our ACPI subsystem accesses the I/O space directly so far, |
200 | * we do not have to bother bus_space I/O map confliction. | | 204 | * we do not have to bother bus_space I/O map confliction. |
201 | */ | | 205 | */ |
202 | if (pci_mapreg_map(pa, LPCIB_PCI_PMBASE, PCI_MAPREG_TYPE_IO, 0, | | 206 | if (pci_mapreg_map(pa, LPCIB_PCI_PMBASE, PCI_MAPREG_TYPE_IO, 0, |
203 | &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { | | 207 | &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { |
204 | aprint_error_dev(self, "can't map power management i/o space"); | | 208 | aprint_error_dev(self, "can't map power management i/o space"); |
205 | return; | | 209 | return; |
206 | } | | 210 | } |
207 | | | 211 | |
| | | 212 | sc->sc_pmcon_orig = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag, |
| | | 213 | LPCIB_PCI_GEN_PMCON_1); |
| | | 214 | |
208 | /* For ICH6 and later, always enable RCBA */ | | 215 | /* For ICH6 and later, always enable RCBA */ |
209 | if (sc->sc_has_rcba) { | | 216 | if (sc->sc_has_rcba) { |
210 | pcireg_t rcba; | | 217 | pcireg_t rcba; |
211 | | | 218 | |
212 | sc->sc_rcbat = sc->sc_pa.pa_memt; | | 219 | sc->sc_rcbat = sc->sc_pa.pa_memt; |
213 | | | 220 | |
214 | rcba = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag, | | 221 | rcba = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag, |
215 | LPCIB_RCBA); | | 222 | LPCIB_RCBA); |
216 | if ((rcba & LPCIB_RCBA_EN) == 0) { | | 223 | if ((rcba & LPCIB_RCBA_EN) == 0) { |
217 | aprint_error_dev(self, "RCBA is not enabled"); | | 224 | aprint_error_dev(self, "RCBA is not enabled"); |
218 | return; | | 225 | return; |
219 | } | | 226 | } |
220 | rcba &= ~LPCIB_RCBA_EN; | | 227 | rcba &= ~LPCIB_RCBA_EN; |
| @@ -231,31 +238,43 @@ lpcibattach(device_t parent, device_t se | | | @@ -231,31 +238,43 @@ lpcibattach(device_t parent, device_t se |
231 | | | 238 | |
232 | /* Set up the TCO (watchdog). */ | | 239 | /* Set up the TCO (watchdog). */ |
233 | tcotimer_configure(self); | | 240 | tcotimer_configure(self); |
234 | | | 241 | |
235 | /* Set up SpeedStep. */ | | 242 | /* Set up SpeedStep. */ |
236 | speedstep_configure(self); | | 243 | speedstep_configure(self); |
237 | | | 244 | |
238 | #if NHPET > 0 | | 245 | #if NHPET > 0 |
239 | /* Set up HPET. */ | | 246 | /* Set up HPET. */ |
240 | lpcib_hpet_configure(self); | | 247 | lpcib_hpet_configure(self); |
241 | #endif | | 248 | #endif |
242 | | | 249 | |
243 | /* Install power handler */ | | 250 | /* Install power handler */ |
244 | if (!pmf_device_register(self, lpcib_suspend, lpcib_resume)) | | 251 | if (!pmf_device_register1(self, lpcib_suspend, lpcib_resume, |
| | | 252 | lpcib_shutdown)) |
245 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 253 | aprint_error_dev(self, "couldn't establish power handler\n"); |
246 | } | | 254 | } |
247 | | | 255 | |
248 | static bool | | 256 | static bool |
| | | 257 | lpcib_shutdown(device_t dv, int howto) |
| | | 258 | { |
| | | 259 | struct lpcib_softc *sc = device_private(dv); |
| | | 260 | |
| | | 261 | pci_conf_write(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag, |
| | | 262 | LPCIB_PCI_GEN_PMCON_1, sc->sc_pmcon_orig); |
| | | 263 | |
| | | 264 | return true; |
| | | 265 | } |
| | | 266 | |
| | | 267 | static bool |
249 | lpcib_suspend(device_t dv PMF_FN_ARGS) | | 268 | lpcib_suspend(device_t dv PMF_FN_ARGS) |
250 | { | | 269 | { |
251 | struct lpcib_softc *sc = device_private(dv); | | 270 | struct lpcib_softc *sc = device_private(dv); |
252 | pci_chipset_tag_t pc = sc->sc_pcib.sc_pc; | | 271 | pci_chipset_tag_t pc = sc->sc_pcib.sc_pc; |
253 | pcitag_t tag = sc->sc_pcib.sc_tag; | | 272 | pcitag_t tag = sc->sc_pcib.sc_tag; |
254 | | | 273 | |
255 | /* capture PIRQ routing control registers */ | | 274 | /* capture PIRQ routing control registers */ |
256 | sc->sc_pirq[0] = pci_conf_read(pc, tag, LPCIB_PCI_PIRQA_ROUT); | | 275 | sc->sc_pirq[0] = pci_conf_read(pc, tag, LPCIB_PCI_PIRQA_ROUT); |
257 | sc->sc_pirq[1] = pci_conf_read(pc, tag, LPCIB_PCI_PIRQE_ROUT); | | 276 | sc->sc_pirq[1] = pci_conf_read(pc, tag, LPCIB_PCI_PIRQE_ROUT); |
258 | | | 277 | |
259 | sc->sc_pmcon = pci_conf_read(pc, tag, LPCIB_PCI_GEN_PMCON_1); | | 278 | sc->sc_pmcon = pci_conf_read(pc, tag, LPCIB_PCI_GEN_PMCON_1); |
260 | sc->sc_fwhsel2 = pci_conf_read(pc, tag, LPCIB_PCI_GEN_STA); | | 279 | sc->sc_fwhsel2 = pci_conf_read(pc, tag, LPCIB_PCI_GEN_STA); |
261 | | | 280 | |