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