Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src gpio(4) support for Intel ICH southbridges.
details: https://anonhg.NetBSD.org/src/rev/dd23b4b7d4ae
branches: trunk
changeset: 747699:dd23b4b7d4ae
user: jakllsch <jakllsch%NetBSD.org@localhost>
date: Sun Sep 27 17:55:31 2009 +0000
description:
gpio(4) support for Intel ICH southbridges.
Tested on Intel SS4200-E (ICH7), and Acorp 6A815EPD (ICH2) motherboards,
on amd64 and i386 ports respectively.
It should be noted that the majority of boards with ICH chips do not
expose the GPIO pins for off-board use. For instance, aside from the
three exposed-on-a-header pins on the 6A815EPD, another pin is also
used to control write protect on the FWH. The SS4200 exposes the GPIO
on a header that connects to the 10 LEDs on the front panel, as well
as a tact switch on the back panel.
diffstat:
share/man/man4/gpio.4 | 3 +-
share/man/man4/ichlpcib.4 | 9 +-
sys/arch/x86/pci/files.pci | 4 +-
sys/arch/x86/pci/ichlpcib.c | 232 +++++++++++++++++++++++++++++++++++++++++++-
sys/dev/ic/i82801lpcreg.h | 3 +-
5 files changed, 242 insertions(+), 9 deletions(-)
diffs (truncated from 409 to 300 lines):
diff -r 3db63b26d8ac -r dd23b4b7d4ae share/man/man4/gpio.4
--- a/share/man/man4/gpio.4 Sun Sep 27 17:48:19 2009 +0000
+++ b/share/man/man4/gpio.4 Sun Sep 27 17:55:31 2009 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: gpio.4,v 1.15 2009/09/25 19:37:03 mbalmer Exp $
+.\" $NetBSD: gpio.4,v 1.16 2009/09/27 17:55:32 jakllsch Exp $
.\" $OpenBSD: gpio.4,v 1.5 2004/11/23 09:39:29 reyk Exp $
.\"
.\" Copyright (c) 2004 Alexander Yurchenko <grange%openbsd.org@localhost>
@@ -27,6 +27,7 @@
.Cd "gpio* at gcscpcib?"
.Cd "gpio* at gpiosim?"
.Cd "gpio* at gscpcib?"
+.Cd "gpio* at ichlpcib?"
.Cd "gpio* at nsclpcsio?"
.Cd "gpio* at ppbus?"
.Pp
diff -r 3db63b26d8ac -r dd23b4b7d4ae share/man/man4/ichlpcib.4
--- a/share/man/man4/ichlpcib.4 Sun Sep 27 17:48:19 2009 +0000
+++ b/share/man/man4/ichlpcib.4 Sun Sep 27 17:55:31 2009 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: ichlpcib.4,v 1.8 2009/05/18 12:32:05 wiz Exp $
+.\" $NetBSD: ichlpcib.4,v 1.9 2009/09/27 17:55:32 jakllsch Exp $
.\"
.\" Copyright (c) 2004 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -37,6 +37,7 @@
.Cd "ichlpcib* at pci? dev ? function ?"
.Cd "hpet0 at ichlpcib?"
.Cd "isa0 at ichlpcib?"
+.Cd "gpio* at ichlpcib?"
.Sh DESCRIPTION
The
.Nm
@@ -62,8 +63,14 @@
node.
A value of 0 will use the low frequency (low power) and a 1 will
enable the high frequency (full power).
+.It
+General Purpose Input/Output.
+The ICH provides up to 64 I/O pins which can be accessed through the
+.Xr gpio 4
+framework.
.El
.Sh SEE ALSO
+.Xr gpio 4 ,
.Xr sysctl 8 ,
.Xr wdogctl 8
.Sh HISTORY
diff -r 3db63b26d8ac -r dd23b4b7d4ae sys/arch/x86/pci/files.pci
--- a/sys/arch/x86/pci/files.pci Sun Sep 27 17:48:19 2009 +0000
+++ b/sys/arch/x86/pci/files.pci Sun Sep 27 17:55:31 2009 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files.pci,v 1.7 2008/08/03 19:32:03 joerg Exp $
+# $NetBSD: files.pci,v 1.8 2009/09/27 17:55:31 jakllsch Exp $
device aapic
attach aapic at pci
@@ -33,7 +33,7 @@
# PCI-LPC bridges
define hpetichbus {}
-device ichlpcib: acpipmtimer, isabus, sysmon_wdog, hpetichbus
+device ichlpcib: acpipmtimer, isabus, sysmon_wdog, hpetichbus, gpiobus
attach ichlpcib at pci
attach hpet at hpetichbus with ichlpcib_hpet
diff -r 3db63b26d8ac -r dd23b4b7d4ae sys/arch/x86/pci/ichlpcib.c
--- a/sys/arch/x86/pci/ichlpcib.c Sun Sep 27 17:48:19 2009 +0000
+++ b/sys/arch/x86/pci/ichlpcib.c Sun Sep 27 17:55:31 2009 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ichlpcib.c,v 1.19 2009/08/18 17:47:46 dyoung Exp $ */
+/* $NetBSD: ichlpcib.c,v 1.20 2009/09/27 17:55:31 jakllsch Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.19 2009/08/18 17:47:46 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ichlpcib.c,v 1.20 2009/09/27 17:55:31 jakllsch Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -47,12 +47,14 @@
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/timetc.h>
+#include <sys/gpio.h>
#include <machine/bus.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
+#include <dev/gpio/gpiovar.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/ic/acpipmtimer.h>
@@ -62,6 +64,9 @@
#include "hpet.h"
#include "pcibvar.h"
+#include "gpio.h"
+
+#define LPCIB_GPIO_NPINS 64
struct lpcib_softc {
/* we call pcibattach() which assumes this starts like this: */
@@ -87,6 +92,16 @@
uint32_t sc_hpet_reg;
#endif
+#if NGPIO > 0
+ device_t sc_gpiobus;
+ kmutex_t sc_gpio_mtx;
+ bus_space_tag_t sc_gpio_iot;
+ bus_space_handle_t sc_gpio_ioh;
+ bus_size_t sc_gpio_ios;
+ struct gpio_chipset_tag sc_gpio_gc;
+ gpio_pin_t sc_gpio_pins[LPCIB_GPIO_NPINS];
+#endif
+
/* Speedstep */
pcireg_t sc_pmcon_orig;
@@ -133,6 +148,14 @@
static int lpcib_hpet_unconfigure(device_t, int);
#endif
+#if NGPIO > 0
+static void lpcib_gpio_configure(device_t);
+static int lpcib_gpio_unconfigure(device_t, int);
+static int lpcib_gpio_pin_read(void *, int);
+static void lpcib_gpio_pin_write(void *, int, int);
+static void lpcib_gpio_pin_ctl(void *, int, int);
+#endif
+
struct lpcib_softc *speedstep_cookie; /* XXX */
CFATTACH_DECL2_NEW(ichlpcib, sizeof(struct lpcib_softc),
@@ -263,6 +286,11 @@
lpcib_hpet_configure(self);
#endif
+#if NGPIO > 0
+ /* Set up GPIO */
+ lpcib_gpio_configure(self);
+#endif
+
/* Install power handler */
if (!pmf_device_register1(self, lpcib_suspend, lpcib_resume,
lpcib_shutdown))
@@ -275,6 +303,10 @@
struct lpcib_softc *sc = device_private(self);
uint32_t val;
+ if (sc->sc_gpiobus == child) {
+ sc->sc_gpiobus = NULL;
+ return;
+ }
if (sc->sc_hpetbus != child) {
pcibchilddet(self, child);
return;
@@ -313,7 +345,7 @@
}
}
-#if NHPET > 0
+#if NHPET > 0 || NGPIO > 0
/* XXX share this with sys/arch/i386/pci/elan520.c */
static bool
ifattr_match(const char *snull, const char *t)
@@ -325,13 +357,20 @@
static int
lpcibrescan(device_t self, const char *ifattr, const int *locators)
{
-#if NHPET > 0
+#if NHPET > 0 || NGPIO > 0
struct lpcib_softc *sc = device_private(self);
+#endif
+#if NHPET > 0
if (ifattr_match(ifattr, "hpetichbus") && sc->sc_hpetbus == NULL)
lpcib_hpet_configure(self);
#endif
+#if NGPIO > 0
+ if (ifattr_match(ifattr, "gpiobus") && sc->sc_gpiobus == NULL)
+ lpcib_gpio_configure(self);
+#endif
+
return pcibrescan(self, ifattr, locators);
}
@@ -348,6 +387,11 @@
return rc;
#endif
+#if NGPIO > 0
+ if ((rc = lpcib_gpio_unconfigure(self, flags)) != 0)
+ return rc;
+#endif
+
/* Set up SpeedStep. */
speedstep_unconfigure(self);
@@ -989,3 +1033,183 @@
return 0;
}
#endif
+
+#if NGPIO > 0
+static void
+lpcib_gpio_configure(device_t self)
+{
+ struct lpcib_softc *sc = device_private(self);
+ struct gpiobus_attach_args gba;
+ pcireg_t gpio_cntl;
+ uint32_t use, io, bit;
+ int pin, shift, base_reg, cntl_reg, reg;
+
+ /* this implies ICH >= 6, and thus different mapreg */
+ if (sc->sc_has_rcba) {
+ base_reg = LPCIB_PCI_GPIO_BASE_ICH6;
+ cntl_reg = LPCIB_PCI_GPIO_CNTL_ICH6;
+ } else {
+ base_reg = LPCIB_PCI_GPIO_BASE;
+ cntl_reg = LPCIB_PCI_GPIO_CNTL;
+ }
+
+ gpio_cntl = pci_conf_read(sc->sc_pcib.sc_pc, sc->sc_pcib.sc_tag,
+ cntl_reg);
+
+ /* Is GPIO enabled? */
+ if ((gpio_cntl & LPCIB_PCI_GPIO_CNTL_EN) == 0)
+ return;
+
+ if (pci_mapreg_map(&sc->sc_pa, base_reg, PCI_MAPREG_TYPE_IO, 0,
+ &sc->sc_gpio_iot, &sc->sc_gpio_ioh,
+ NULL, &sc->sc_gpio_ios)) {
+ aprint_error_dev(self, "can't map general purpose i/o space\n");
+ return;
+ }
+
+ mutex_init(&sc->sc_gpio_mtx, MUTEX_DEFAULT, IPL_NONE);
+
+ for (pin = 0; pin < LPCIB_GPIO_NPINS; pin++) {
+ sc->sc_gpio_pins[pin].pin_num = pin;
+
+ /* Read initial state */
+ reg = (pin < 32) ? LPCIB_GPIO_GPIO_USE_SEL : LPCIB_GPIO_GPIO_USE_SEL2;
+ use = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
+ reg = (pin < 32) ? LPCIB_GPIO_GP_IO_SEL : LPCIB_GPIO_GP_IO_SEL;
+ io = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, 4);
+ shift = pin % 32;
+ bit = __BIT(shift);
+
+ if ((use & bit) != 0) {
+ sc->sc_gpio_pins[pin].pin_caps =
+ GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+ if (pin < 32)
+ sc->sc_gpio_pins[pin].pin_caps |=
+ GPIO_PIN_PULSATE;
+ if ((io & bit) != 0)
+ sc->sc_gpio_pins[pin].pin_flags =
+ GPIO_PIN_INPUT;
+ else
+ sc->sc_gpio_pins[pin].pin_flags =
+ GPIO_PIN_OUTPUT;
+ } else
+ sc->sc_gpio_pins[pin].pin_caps = 0;
+
+ if (lpcib_gpio_pin_read(sc, pin) == 0)
+ sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_LOW;
+ else
+ sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_HIGH;
+
+ }
+
+ /* Create controller tag */
+ sc->sc_gpio_gc.gp_cookie = sc;
+ sc->sc_gpio_gc.gp_pin_read = lpcib_gpio_pin_read;
+ sc->sc_gpio_gc.gp_pin_write = lpcib_gpio_pin_write;
+ sc->sc_gpio_gc.gp_pin_ctl = lpcib_gpio_pin_ctl;
+
+ memset(&gba, 0, sizeof(gba));
+
+ gba.gba_gc = &sc->sc_gpio_gc;
+ gba.gba_pins = sc->sc_gpio_pins;
+ gba.gba_npins = LPCIB_GPIO_NPINS;
+
+ sc->sc_gpiobus = config_found_ia(self, "gpiobus", &gba, gpiobus_print);
+}
+
+static int
+lpcib_gpio_unconfigure(device_t self, int flags)
+{
+ struct lpcib_softc *sc = device_private(self);
Home |
Main Index |
Thread Index |
Old Index