| @@ -1,38 +1,38 @@ | | | @@ -1,38 +1,38 @@ |
1 | /* $NetBSD: piixpm.c,v 1.54 2019/07/13 09:24:17 msaitoh Exp $ */ | | 1 | /* $NetBSD: piixpm.c,v 1.54.2.1 2020/07/16 12:39:11 martin Exp $ */ |
2 | /* $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $ */ | | 2 | /* $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org> | | 5 | * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | /* | | 20 | /* |
21 | * Intel PIIX and compatible Power Management controller driver. | | 21 | * Intel PIIX and compatible Power Management controller driver. |
22 | */ | | 22 | */ |
23 | | | 23 | |
24 | #include <sys/cdefs.h> | | 24 | #include <sys/cdefs.h> |
25 | __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.54 2019/07/13 09:24:17 msaitoh Exp $"); | | 25 | __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.54.2.1 2020/07/16 12:39:11 martin Exp $"); |
26 | | | 26 | |
27 | #include <sys/param.h> | | 27 | #include <sys/param.h> |
28 | #include <sys/systm.h> | | 28 | #include <sys/systm.h> |
29 | #include <sys/device.h> | | 29 | #include <sys/device.h> |
30 | #include <sys/kernel.h> | | 30 | #include <sys/kernel.h> |
31 | #include <sys/mutex.h> | | 31 | #include <sys/mutex.h> |
32 | #include <sys/proc.h> | | 32 | #include <sys/proc.h> |
33 | | | 33 | |
34 | #include <sys/bus.h> | | 34 | #include <sys/bus.h> |
35 | | | 35 | |
36 | #include <dev/pci/pcidevs.h> | | 36 | #include <dev/pci/pcidevs.h> |
37 | #include <dev/pci/pcireg.h> | | 37 | #include <dev/pci/pcireg.h> |
38 | #include <dev/pci/pcivar.h> | | 38 | #include <dev/pci/pcivar.h> |
| @@ -60,42 +60,46 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 | | | @@ -60,42 +60,46 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 |
60 | ((PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_ATI_SB600_SMB) && \ | | 60 | ((PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_ATI_SB600_SMB) && \ |
61 | ((sc)->sc_rev >= 0x40))) | | 61 | ((sc)->sc_rev >= 0x40))) |
62 | | | 62 | |
63 | #define PIIXPM_IS_HUDSON(sc) \ | | 63 | #define PIIXPM_IS_HUDSON(sc) \ |
64 | ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ | | 64 | ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ |
65 | (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_HUDSON_SMB)) | | 65 | (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_HUDSON_SMB)) |
66 | | | 66 | |
67 | #define PIIXPM_IS_KERNCZ(sc) \ | | 67 | #define PIIXPM_IS_KERNCZ(sc) \ |
68 | ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ | | 68 | ((PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_AMD) && \ |
69 | (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_KERNCZ_SMB)) | | 69 | (PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_AMD_KERNCZ_SMB)) |
70 | | | 70 | |
71 | #define PIIXPM_IS_FCHGRP(sc) (PIIXPM_IS_HUDSON(sc) || PIIXPM_IS_KERNCZ(sc)) | | 71 | #define PIIXPM_IS_FCHGRP(sc) (PIIXPM_IS_HUDSON(sc) || PIIXPM_IS_KERNCZ(sc)) |
72 | | | 72 | |
| | | 73 | #define PIIX_SB800_TIMEOUT 500 |
| | | 74 | |
73 | struct piixpm_smbus { | | 75 | struct piixpm_smbus { |
74 | int sda; | | 76 | int sda; |
| | | 77 | int sda_save; |
75 | struct piixpm_softc *softc; | | 78 | struct piixpm_softc *softc; |
76 | }; | | 79 | }; |
77 | | | 80 | |
78 | struct piixpm_softc { | | 81 | struct piixpm_softc { |
79 | device_t sc_dev; | | 82 | device_t sc_dev; |
80 | | | 83 | |
81 | bus_space_tag_t sc_iot; | | 84 | bus_space_tag_t sc_iot; |
82 | #define sc_pm_iot sc_iot | | 85 | #define sc_pm_iot sc_iot |
83 | #define sc_smb_iot sc_iot | | 86 | #define sc_smb_iot sc_iot |
84 | bus_space_handle_t sc_pm_ioh; | | 87 | bus_space_handle_t sc_pm_ioh; |
85 | bus_space_handle_t sc_sb800_ioh; | | 88 | bus_space_handle_t sc_sb800_ioh; |
86 | bus_space_handle_t sc_smb_ioh; | | 89 | bus_space_handle_t sc_smb_ioh; |
87 | void * sc_smb_ih; | | 90 | void * sc_smb_ih; |
88 | int sc_poll; | | 91 | int sc_poll; |
| | | 92 | bool sc_sb800_selen; /* Use SMBUS0SEL */ |
89 | | | 93 | |
90 | pci_chipset_tag_t sc_pc; | | 94 | pci_chipset_tag_t sc_pc; |
91 | pcitag_t sc_pcitag; | | 95 | pcitag_t sc_pcitag; |
92 | pcireg_t sc_id; | | 96 | pcireg_t sc_id; |
93 | pcireg_t sc_rev; | | 97 | pcireg_t sc_rev; |
94 | | | 98 | |
95 | int sc_numbusses; | | 99 | int sc_numbusses; |
96 | device_t sc_i2c_device[4]; | | 100 | device_t sc_i2c_device[4]; |
97 | struct piixpm_smbus sc_busses[4]; | | 101 | struct piixpm_smbus sc_busses[4]; |
98 | struct i2c_controller sc_i2c_tags[4]; | | 102 | struct i2c_controller sc_i2c_tags[4]; |
99 | | | 103 | |
100 | kmutex_t sc_i2c_mutex; | | 104 | kmutex_t sc_i2c_mutex; |
101 | struct { | | 105 | struct { |
| @@ -109,28 +113,28 @@ struct piixpm_softc { | | | @@ -109,28 +113,28 @@ struct piixpm_softc { |
109 | pcireg_t sc_devact[2]; | | 113 | pcireg_t sc_devact[2]; |
110 | }; | | 114 | }; |
111 | | | 115 | |
112 | static int piixpm_match(device_t, cfdata_t, void *); | | 116 | static int piixpm_match(device_t, cfdata_t, void *); |
113 | static void piixpm_attach(device_t, device_t, void *); | | 117 | static void piixpm_attach(device_t, device_t, void *); |
114 | static int piixpm_rescan(device_t, const char *, const int *); | | 118 | static int piixpm_rescan(device_t, const char *, const int *); |
115 | static void piixpm_chdet(device_t, device_t); | | 119 | static void piixpm_chdet(device_t, device_t); |
116 | | | 120 | |
117 | static bool piixpm_suspend(device_t, const pmf_qual_t *); | | 121 | static bool piixpm_suspend(device_t, const pmf_qual_t *); |
118 | static bool piixpm_resume(device_t, const pmf_qual_t *); | | 122 | static bool piixpm_resume(device_t, const pmf_qual_t *); |
119 | | | 123 | |
120 | static int piixpm_sb800_init(struct piixpm_softc *); | | 124 | static int piixpm_sb800_init(struct piixpm_softc *); |
121 | static void piixpm_csb5_reset(void *); | | 125 | static void piixpm_csb5_reset(void *); |
122 | static int piixpm_i2c_acquire_bus(void *, int); | | 126 | static int piixpm_i2c_sb800_acquire_bus(void *, int); |
123 | static void piixpm_i2c_release_bus(void *, int); | | 127 | static void piixpm_i2c_sb800_release_bus(void *, int); |
124 | static int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, | | 128 | static int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, |
125 | size_t, void *, size_t, int); | | 129 | size_t, void *, size_t, int); |
126 | | | 130 | |
127 | static int piixpm_intr(void *); | | 131 | static int piixpm_intr(void *); |
128 | | | 132 | |
129 | CFATTACH_DECL3_NEW(piixpm, sizeof(struct piixpm_softc), | | 133 | CFATTACH_DECL3_NEW(piixpm, sizeof(struct piixpm_softc), |
130 | piixpm_match, piixpm_attach, NULL, NULL, piixpm_rescan, piixpm_chdet, 0); | | 134 | piixpm_match, piixpm_attach, NULL, NULL, piixpm_rescan, piixpm_chdet, 0); |
131 | | | 135 | |
132 | static int | | 136 | static int |
133 | piixpm_match(device_t parent, cfdata_t match, void *aux) | | 137 | piixpm_match(device_t parent, cfdata_t match, void *aux) |
134 | { | | 138 | { |
135 | struct pci_attach_args *pa; | | 139 | struct pci_attach_args *pa; |
136 | | | 140 | |
| @@ -221,35 +225,30 @@ piixpm_attach(device_t parent, device_t | | | @@ -221,35 +225,30 @@ piixpm_attach(device_t parent, device_t |
221 | /* | | 225 | /* |
222 | * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M. | | 226 | * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M. |
223 | * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 | | 227 | * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 |
224 | * in the "Specification update" (document #297738). | | 228 | * in the "Specification update" (document #297738). |
225 | */ | | 229 | */ |
226 | acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, | | 230 | acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, |
227 | (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0); | | 231 | (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0); |
228 | | | 232 | |
229 | nopowermanagement: | | 233 | nopowermanagement: |
230 | | | 234 | |
231 | /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ | | 235 | /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ |
232 | if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { | | 236 | if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { |
233 | if (piixpm_sb800_init(sc) == 0) { | | 237 | if (piixpm_sb800_init(sc) == 0) { |
234 | sc->sc_numbusses = 4; | | | |
235 | | | | |
236 | /* Read configuration */ | | 238 | /* Read configuration */ |
237 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, | | 239 | conf = bus_space_read_1(sc->sc_iot, |
238 | SB800_SMB_HOSTC); | | 240 | sc->sc_smb_ioh, SB800_SMB_HOSTC); |
239 | DPRINTF(("%s: conf 0x%08x\n", device_xname(self), | | 241 | usesmi = ((conf & SB800_SMB_HOSTC_IRQ) == 0); |
240 | conf)); | | | |
241 | | | | |
242 | usesmi = conf & SB800_SMB_HOSTC_SMI; | | | |
243 | goto setintr; | | 242 | goto setintr; |
244 | } | | 243 | } |
245 | aprint_normal_dev(self, "SMBus initialization failed\n"); | | 244 | aprint_normal_dev(self, "SMBus initialization failed\n"); |
246 | return; | | 245 | return; |
247 | } | | 246 | } |
248 | | | 247 | |
249 | /* Read configuration */ | | 248 | /* Read configuration */ |
250 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); | | 249 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC); |
251 | DPRINTF(("%s: conf 0x%08x\n", device_xname(self), conf)); | | 250 | DPRINTF(("%s: conf 0x%08x\n", device_xname(self), conf)); |
252 | | | 251 | |
253 | if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { | | 252 | if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) { |
254 | aprint_normal_dev(self, "SMBus disabled\n"); | | 253 | aprint_normal_dev(self, "SMBus disabled\n"); |
255 | return; | | 254 | return; |
| @@ -318,37 +317,44 @@ piixpm_iicbus_print(void *aux, const cha | | | @@ -318,37 +317,44 @@ piixpm_iicbus_print(void *aux, const cha |
318 | static int | | 317 | static int |
319 | piixpm_rescan(device_t self, const char *ifattr, const int *flags) | | 318 | piixpm_rescan(device_t self, const char *ifattr, const int *flags) |
320 | { | | 319 | { |
321 | struct piixpm_softc *sc = device_private(self); | | 320 | struct piixpm_softc *sc = device_private(self); |
322 | struct i2cbus_attach_args iba; | | 321 | struct i2cbus_attach_args iba; |
323 | int i; | | 322 | int i; |
324 | | | 323 | |
325 | if (!ifattr_match(ifattr, "i2cbus")) | | 324 | if (!ifattr_match(ifattr, "i2cbus")) |
326 | return 0; | | 325 | return 0; |
327 | | | 326 | |
328 | /* Attach I2C bus */ | | 327 | /* Attach I2C bus */ |
329 | | | 328 | |
330 | for (i = 0; i < sc->sc_numbusses; i++) { | | 329 | for (i = 0; i < sc->sc_numbusses; i++) { |
| | | 330 | struct i2c_controller *tag = &sc->sc_i2c_tags[i]; |
| | | 331 | |
331 | if (sc->sc_i2c_device[i]) | | 332 | if (sc->sc_i2c_device[i]) |
332 | continue; | | 333 | continue; |
333 | sc->sc_busses[i].sda = i; | | 334 | sc->sc_busses[i].sda = i; |
334 | sc->sc_busses[i].softc = sc; | | 335 | sc->sc_busses[i].softc = sc; |
335 | sc->sc_i2c_tags[i].ic_cookie = &sc->sc_busses[i]; | | 336 | tag->ic_cookie = &sc->sc_busses[i]; |
336 | sc->sc_i2c_tags[i].ic_acquire_bus = piixpm_i2c_acquire_bus; | | 337 | if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_FCHGRP(sc)) { |
337 | sc->sc_i2c_tags[i].ic_release_bus = piixpm_i2c_release_bus; | | 338 | tag->ic_acquire_bus = piixpm_i2c_sb800_acquire_bus; |
338 | sc->sc_i2c_tags[i].ic_exec = piixpm_i2c_exec; | | 339 | tag->ic_release_bus = piixpm_i2c_sb800_release_bus; |
| | | 340 | } else { |
| | | 341 | tag->ic_acquire_bus = NULL; |
| | | 342 | tag->ic_release_bus = NULL; |
| | | 343 | } |
| | | 344 | tag->ic_exec = piixpm_i2c_exec; |
339 | memset(&iba, 0, sizeof(iba)); | | 345 | memset(&iba, 0, sizeof(iba)); |
340 | iba.iba_type = I2C_TYPE_SMBUS; | | 346 | iba.iba_type = I2C_TYPE_SMBUS; |
341 | iba.iba_tag = &sc->sc_i2c_tags[i]; | | 347 | iba.iba_tag = tag; |
342 | sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba, | | 348 | sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba, |
343 | piixpm_iicbus_print); | | 349 | piixpm_iicbus_print); |
344 | } | | 350 | } |
345 | | | 351 | |
346 | return 0; | | 352 | return 0; |
347 | } | | 353 | } |
348 | | | 354 | |
349 | static void | | 355 | static void |
350 | piixpm_chdet(device_t self, device_t child) | | 356 | piixpm_chdet(device_t self, device_t child) |
351 | { | | 357 | { |
352 | struct piixpm_softc *sc = device_private(self); | | 358 | struct piixpm_softc *sc = device_private(self); |
353 | int i; | | 359 | int i; |
354 | | | 360 | |
| @@ -391,68 +397,77 @@ piixpm_resume(device_t dv, const pmf_qua | | | @@ -391,68 +397,77 @@ piixpm_resume(device_t dv, const pmf_qua |
391 | * Extract SMBus base address from SB800 Power Management (PM) registers. | | 397 | * Extract SMBus base address from SB800 Power Management (PM) registers. |
392 | * The PM registers can be accessed either through indirect I/O (CD6/CD7) or | | 398 | * The PM registers can be accessed either through indirect I/O (CD6/CD7) or |
393 | * direct mapping if AcpiMMioDecodeEn is enabled. Since this function is only | | 399 | * direct mapping if AcpiMMioDecodeEn is enabled. Since this function is only |
394 | * called once it uses indirect I/O for simplicity. | | 400 | * called once it uses indirect I/O for simplicity. |
395 | */ | | 401 | */ |
396 | static int | | 402 | static int |
397 | piixpm_sb800_init(struct piixpm_softc *sc) | | 403 | piixpm_sb800_init(struct piixpm_softc *sc) |
398 | { | | 404 | { |
399 | bus_space_tag_t iot = sc->sc_iot; | | 405 | bus_space_tag_t iot = sc->sc_iot; |
400 | bus_space_handle_t ioh; /* indirect I/O handle */ | | 406 | bus_space_handle_t ioh; /* indirect I/O handle */ |
401 | uint16_t val, base_addr; | | 407 | uint16_t val, base_addr; |
402 | bool enabled; | | 408 | bool enabled; |
403 | | | 409 | |
| | | 410 | if (PIIXPM_IS_KERNCZ(sc) || |
| | | 411 | (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) |
| | | 412 | sc->sc_numbusses = 2; |
| | | 413 | else |
| | | 414 | sc->sc_numbusses = 4; |
| | | 415 | |
404 | /* Fetch SMB base address */ | | 416 | /* Fetch SMB base address */ |
405 | if (bus_space_map(iot, | | 417 | if (bus_space_map(iot, |
406 | SB800_INDIRECTIO_BASE, SB800_INDIRECTIO_SIZE, 0, &ioh)) { | | 418 | SB800_INDIRECTIO_BASE, SB800_INDIRECTIO_SIZE, 0, &ioh)) { |
407 | device_printf(sc->sc_dev, "couldn't map indirect I/O space\n"); | | 419 | device_printf(sc->sc_dev, "couldn't map indirect I/O space\n"); |
408 | return EBUSY; | | 420 | return EBUSY; |
409 | } | | 421 | } |
410 | if (PIIXPM_IS_FCHGRP(sc)) { | | 422 | if (PIIXPM_IS_FCHGRP(sc)) { |
411 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, | | 423 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, |
412 | AMDFCH41_PM_DECODE_EN0); | | 424 | AMDFCH41_PM_DECODE_EN0); |
413 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); | | 425 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); |
414 | enabled = val & AMDFCH41_SMBUS_EN; | | 426 | enabled = val & AMDFCH41_SMBUS_EN; |
415 | if (!enabled) | | 427 | if (!enabled) |
416 | return ENOENT; | | 428 | return ENOENT; |
417 | | | 429 | |
418 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, | | 430 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, |
419 | AMDFCH41_PM_DECODE_EN1); | | 431 | AMDFCH41_PM_DECODE_EN1); |
420 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; | | 432 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; |
421 | base_addr = val; | | 433 | base_addr = val; |
422 | } else { | | 434 | } else { |
| | | 435 | uint8_t data; |
| | | 436 | |
423 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, | | 437 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, |
424 | SB800_PM_SMBUS0EN_LO); | | 438 | SB800_PM_SMBUS0EN_LO); |
425 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); | | 439 | val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); |
426 | enabled = val & SB800_PM_SMBUS0EN_ENABLE; | | 440 | enabled = val & SB800_PM_SMBUS0EN_ENABLE; |
427 | if (!enabled) | | 441 | if (!enabled) |
428 | return ENOENT; | | 442 | return ENOENT; |
429 | | | 443 | |
430 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, | | 444 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, |
431 | SB800_PM_SMBUS0EN_HI); | | 445 | SB800_PM_SMBUS0EN_HI); |
432 | val |= bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; | | 446 | val |= bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; |
433 | base_addr = val & SB800_PM_SMBUS0EN_BADDR; | | 447 | base_addr = val & SB800_PM_SMBUS0EN_BADDR; |
434 | | | 448 | |
435 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, | | 449 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, |
436 | SB800_PM_SMBUS0SELEN); | | 450 | SB800_PM_SMBUS0SELEN); |
437 | bus_space_write_1(iot, ioh, SB800_INDIRECTIO_DATA, | | 451 | data = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); |
438 | SB800_PM_SMBUS0EN_ENABLE); | | 452 | if ((data & SB800_PM_USE_SMBUS0SEL) != 0) |
| | | 453 | sc->sc_sb800_selen = true; |
439 | } | | 454 | } |
440 | | | 455 | |
441 | sc->sc_sb800_ioh = ioh; | | 456 | sc->sc_sb800_ioh = ioh; |
442 | aprint_debug_dev(sc->sc_dev, "SMBus @ 0x%04x\n", base_addr); | | 457 | aprint_debug_dev(sc->sc_dev, "SMBus @ 0x%04x\n", base_addr); |
443 | | | 458 | |
444 | if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr), | | 459 | if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr), |
445 | PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { | | 460 | SB800_SMB_SIZE, 0, &sc->sc_smb_ioh)) { |
446 | aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); | | 461 | aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); |
447 | return EBUSY; | | 462 | return EBUSY; |
448 | } | | 463 | } |
449 | | | 464 | |
450 | return 0; | | 465 | return 0; |
451 | } | | 466 | } |
452 | | | 467 | |
453 | static void | | 468 | static void |
454 | piixpm_csb5_reset(void *arg) | | 469 | piixpm_csb5_reset(void *arg) |
455 | { | | 470 | { |
456 | struct piixpm_softc *sc = arg; | | 471 | struct piixpm_softc *sc = arg; |
457 | pcireg_t base, hostc, pmbase; | | 472 | pcireg_t base, hostc, pmbase; |
458 | | | 473 | |
| @@ -462,71 +477,125 @@ piixpm_csb5_reset(void *arg) | | | @@ -462,71 +477,125 @@ piixpm_csb5_reset(void *arg) |
462 | pmbase = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE); | | 477 | pmbase = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE); |
463 | pmbase |= PIIX_PM_BASE_CSB5_RESET; | | 478 | pmbase |= PIIX_PM_BASE_CSB5_RESET; |
464 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); | | 479 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); |
465 | pmbase &= ~PIIX_PM_BASE_CSB5_RESET; | | 480 | pmbase &= ~PIIX_PM_BASE_CSB5_RESET; |
466 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); | | 481 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase); |
467 | | | 482 | |
468 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE, base); | | 483 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE, base); |
469 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC, hostc); | | 484 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC, hostc); |
470 | | | 485 | |
471 | (void) tsleep(&sc, PRIBIO, "csb5reset", hz/2); | | 486 | (void) tsleep(&sc, PRIBIO, "csb5reset", hz/2); |
472 | } | | 487 | } |
473 | | | 488 | |
474 | static int | | 489 | static int |
475 | piixpm_i2c_acquire_bus(void *cookie, int flags) | | 490 | piixpm_i2c_sb800_acquire_bus(void *cookie, int flags) |
476 | { | | 491 | { |
477 | struct piixpm_smbus *smbus = cookie; | | 492 | struct piixpm_smbus *smbus = cookie; |
478 | struct piixpm_softc *sc = smbus->softc; | | 493 | struct piixpm_softc *sc = smbus->softc; |
| | | 494 | uint8_t sctl, old_sda, index, mask, reg; |
| | | 495 | int i; |
| | | 496 | |
479 | | | 497 | |
480 | if (!cold) | | 498 | if (!cold) |
481 | mutex_enter(&sc->sc_i2c_mutex); | | 499 | mutex_enter(&sc->sc_i2c_mutex); |
482 | | | 500 | |
483 | if (PIIXPM_IS_KERNCZ(sc)) { | | 501 | sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC); |
484 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 502 | for (i = 0; i < PIIX_SB800_TIMEOUT; i++) { |
485 | SB800_INDIRECTIO_INDEX, AMDFCH41_PM_PORT_INDEX); | | 503 | /* Try to acquire the host semaphore */ |
486 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 504 | sctl &= ~PIIX_SMB_SC_SEMMASK; |
487 | SB800_INDIRECTIO_DATA, smbus->sda << 3); | | 505 | bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC, |
488 | } else if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_HUDSON(sc)) { | | 506 | sctl | PIIX_SMB_SC_HOSTSEM); |
489 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 507 | |
490 | SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); | | 508 | sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, |
| | | 509 | PIIX_SMB_SC); |
| | | 510 | if ((sctl & PIIX_SMB_SC_HOSTSEM) != 0) |
| | | 511 | break; |
| | | 512 | |
| | | 513 | delay(1000); |
| | | 514 | } |
| | | 515 | if (i >= PIIX_SB800_TIMEOUT) { |
| | | 516 | device_printf(sc->sc_dev, |
| | | 517 | "Failed to acquire the host semaphore\n"); |
| | | 518 | return -1; |
| | | 519 | } |
| | | 520 | |
| | | 521 | if (PIIXPM_IS_KERNCZ(sc) || |
| | | 522 | (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { |
| | | 523 | index = AMDFCH41_PM_PORT_INDEX; |
| | | 524 | mask = AMDFCH41_SMBUS_PORTMASK; |
| | | 525 | } else if (sc->sc_sb800_selen) { |
| | | 526 | index = SB800_PM_SMBUS0SEL; |
| | | 527 | mask = SB800_PM_SMBUS0_MASK_E; |
| | | 528 | } else { |
| | | 529 | index = SB800_PM_SMBUS0EN_LO; |
| | | 530 | mask = SB800_PM_SMBUS0_MASK_C; |
| | | 531 | } |
| | | 532 | |
| | | 533 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, |
| | | 534 | SB800_INDIRECTIO_INDEX, index); |
| | | 535 | reg = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, |
| | | 536 | SB800_INDIRECTIO_DATA); |
| | | 537 | |
| | | 538 | old_sda = __SHIFTOUT(reg, mask); |
| | | 539 | if (smbus->sda != old_sda) { |
| | | 540 | reg &= ~mask; |
| | | 541 | reg |= __SHIFTIN(smbus->sda, mask); |
491 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 542 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, |
492 | SB800_INDIRECTIO_DATA, smbus->sda << 1); | | 543 | SB800_INDIRECTIO_DATA, reg); |
493 | } | | 544 | } |
494 | | | 545 | |
| | | 546 | /* Save the old port number */ |
| | | 547 | smbus->sda_save = old_sda; |
| | | 548 | |
495 | return 0; | | 549 | return 0; |
496 | } | | 550 | } |
497 | | | 551 | |
498 | static void | | 552 | static void |
499 | piixpm_i2c_release_bus(void *cookie, int flags) | | 553 | piixpm_i2c_sb800_release_bus(void *cookie, int flags) |
500 | { | | 554 | { |
501 | struct piixpm_smbus *smbus = cookie; | | 555 | struct piixpm_smbus *smbus = cookie; |
502 | struct piixpm_softc *sc = smbus->softc; | | 556 | struct piixpm_softc *sc = smbus->softc; |
| | | 557 | uint8_t sctl, index, mask, reg; |
503 | | | 558 | |
504 | if (PIIXPM_IS_KERNCZ(sc)) { | | 559 | if (PIIXPM_IS_KERNCZ(sc) || |
505 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 560 | (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { |
506 | SB800_INDIRECTIO_INDEX, AMDFCH41_PM_PORT_INDEX); | | 561 | index = AMDFCH41_PM_PORT_INDEX; |
507 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 562 | mask = AMDFCH41_SMBUS_PORTMASK; |
508 | SB800_INDIRECTIO_DATA, 0); | | 563 | } else if (sc->sc_sb800_selen) { |
509 | } else if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_HUDSON(sc)) { | | 564 | index = SB800_PM_SMBUS0SEL; |
510 | /* | | 565 | mask = SB800_PM_SMBUS0_MASK_E; |
511 | * HP Microserver hangs after reboot if not set to SDA0. | | 566 | } else { |
512 | * Also add shutdown hook? | | 567 | index = SB800_PM_SMBUS0EN_LO; |
513 | */ | | 568 | mask = SB800_PM_SMBUS0_MASK_C; |
514 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 569 | } |
515 | SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); | | 570 | |
| | | 571 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, |
| | | 572 | SB800_INDIRECTIO_INDEX, index); |
| | | 573 | if (smbus->sda != smbus->sda_save) { |
| | | 574 | /* Restore the port number */ |
| | | 575 | reg = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, |
| | | 576 | SB800_INDIRECTIO_DATA); |
| | | 577 | reg &= ~mask; |
| | | 578 | reg |= __SHIFTIN(smbus->sda_save, mask); |
516 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, | | 579 | bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, |
517 | SB800_INDIRECTIO_DATA, 0); | | 580 | SB800_INDIRECTIO_DATA, reg); |
518 | } | | 581 | } |
519 | | | 582 | |
| | | 583 | /* Relase the host semaphore */ |
| | | 584 | sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC); |
| | | 585 | sctl &= ~PIIX_SMB_SC_SEMMASK; |
| | | 586 | bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC, |
| | | 587 | sctl | PIIX_SMB_SC_CLRHOSTSEM); |
| | | 588 | |
520 | if (!cold) | | 589 | if (!cold) |
521 | mutex_exit(&sc->sc_i2c_mutex); | | 590 | mutex_exit(&sc->sc_i2c_mutex); |
522 | } | | 591 | } |
523 | | | 592 | |
524 | static int | | 593 | static int |
525 | piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, | | 594 | piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, |
526 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) | | 595 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
527 | { | | 596 | { |
528 | struct piixpm_smbus *smbus = cookie; | | 597 | struct piixpm_smbus *smbus = cookie; |
529 | struct piixpm_softc *sc = smbus->softc; | | 598 | struct piixpm_softc *sc = smbus->softc; |
530 | const uint8_t *b; | | 599 | const uint8_t *b; |
531 | uint8_t ctl = 0, st; | | 600 | uint8_t ctl = 0, st; |
532 | int retries; | | 601 | int retries; |