Module Name:    src
Committed By:   jakllsch
Date:           Sun Sep 27 17:55:32 UTC 2009

Modified Files:
        src/share/man/man4: gpio.4 ichlpcib.4
        src/sys/arch/x86/pci: files.pci ichlpcib.c
        src/sys/dev/ic: i82801lpcreg.h

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/share/man/man4/gpio.4
cvs rdiff -u -r1.8 -r1.9 src/share/man/man4/ichlpcib.4
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/x86/pci/files.pci
cvs rdiff -u -r1.19 -r1.20 src/sys/arch/x86/pci/ichlpcib.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/ic/i82801lpcreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/gpio.4
diff -u src/share/man/man4/gpio.4:1.15 src/share/man/man4/gpio.4:1.16
--- src/share/man/man4/gpio.4:1.15	Fri Sep 25 19:37:03 2009
+++ src/share/man/man4/gpio.4	Sun Sep 27 17:55:32 2009
@@ -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 <gra...@openbsd.org>
@@ -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

Index: src/share/man/man4/ichlpcib.4
diff -u src/share/man/man4/ichlpcib.4:1.8 src/share/man/man4/ichlpcib.4:1.9
--- src/share/man/man4/ichlpcib.4:1.8	Mon May 18 12:32:05 2009
+++ src/share/man/man4/ichlpcib.4	Sun Sep 27 17:55:32 2009
@@ -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

Index: src/sys/arch/x86/pci/files.pci
diff -u src/sys/arch/x86/pci/files.pci:1.7 src/sys/arch/x86/pci/files.pci:1.8
--- src/sys/arch/x86/pci/files.pci:1.7	Sun Aug  3 19:32:03 2008
+++ src/sys/arch/x86/pci/files.pci	Sun Sep 27 17:55:31 2009
@@ -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
 

Index: src/sys/arch/x86/pci/ichlpcib.c
diff -u src/sys/arch/x86/pci/ichlpcib.c:1.19 src/sys/arch/x86/pci/ichlpcib.c:1.20
--- src/sys/arch/x86/pci/ichlpcib.c:1.19	Tue Aug 18 17:47:46 2009
+++ src/sys/arch/x86/pci/ichlpcib.c	Sun Sep 27 17:55:31 2009
@@ -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);
+	int rc;
+
+	if (sc->sc_gpiobus != NULL &&
+	    (rc = config_detach(sc->sc_gpiobus, flags)) != 0)
+		return rc;
+
+	mutex_destroy(&sc->sc_gpio_mtx);
+
+	bus_space_unmap(sc->sc_gpio_iot, sc->sc_gpio_ioh, sc->sc_gpio_ios);
+
+	return 0;
+}
+
+static int
+lpcib_gpio_pin_read(void *arg, int pin)
+{
+	struct lpcib_softc *sc = arg;
+	uint32_t data;
+	int reg, shift;
+	
+	reg = (pin < 32) ? LPCIB_GPIO_GP_LVL : LPCIB_GPIO_GP_LVL2;
+	shift = pin % 32;
+
+	mutex_enter(&sc->sc_gpio_mtx);
+	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
+	mutex_exit(&sc->sc_gpio_mtx);
+	
+	return (__SHIFTOUT(data, __BIT(shift)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
+}
+
+static void
+lpcib_gpio_pin_write(void *arg, int pin, int value)
+{
+	struct lpcib_softc *sc = arg;
+	uint32_t data;
+	int reg, shift;
+
+	reg = (pin < 32) ? LPCIB_GPIO_GP_LVL : LPCIB_GPIO_GP_LVL2;
+	shift = pin % 32;
+
+	mutex_enter(&sc->sc_gpio_mtx);
+
+	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
+
+	if(value)
+		data |= __BIT(shift);
+	else
+		data &= ~__BIT(shift);
+
+	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
+
+	mutex_exit(&sc->sc_gpio_mtx);
+}
+
+static void
+lpcib_gpio_pin_ctl(void *arg, int pin, int flags)
+{
+	struct lpcib_softc *sc = arg;
+	uint32_t data;
+	int reg, shift;
+
+	shift = pin % 32;
+	reg = (pin < 32) ? LPCIB_GPIO_GP_IO_SEL : LPCIB_GPIO_GP_IO_SEL2;
+	
+	mutex_enter(&sc->sc_gpio_mtx);
+	
+	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
+	
+	if (flags & GPIO_PIN_OUTPUT)
+		data &= ~__BIT(shift);
+
+	if (flags & GPIO_PIN_INPUT)
+		data |= __BIT(shift);
+
+	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
+
+
+	if (pin < 32) {
+		reg = LPCIB_GPIO_GPO_BLINK;
+		data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);
+
+		if (flags & GPIO_PIN_PULSATE)
+			data |= __BIT(shift);
+		else
+			data &= ~__BIT(shift);
+
+		bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
+	}
+
+	mutex_exit(&sc->sc_gpio_mtx);
+}
+#endif

Index: src/sys/dev/ic/i82801lpcreg.h
diff -u src/sys/dev/ic/i82801lpcreg.h:1.9 src/sys/dev/ic/i82801lpcreg.h:1.10
--- src/sys/dev/ic/i82801lpcreg.h:1.9	Mon Sep 21 16:18:31 2009
+++ src/sys/dev/ic/i82801lpcreg.h	Sun Sep 27 17:55:32 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: i82801lpcreg.h,v 1.9 2009/09/21 16:18:31 jakllsch Exp $	*/
+/*	$NetBSD: i82801lpcreg.h,v 1.10 2009/09/27 17:55:32 jakllsch Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -50,6 +50,7 @@
 /* GPIO config registers ICH0-ICH5 */
 #define LPCIB_PCI_GPIO_BASE	0x58
 #define LPCIB_PCI_GPIO_CNTL	0x5c
+#define LPCIB_PCI_GPIO_CNTL_EN	(1 << 4)
 #define LPCIB_PCI_PIRQA_ROUT	0x60
 #define LPCIB_PCI_PIRQB_ROUT	0x61
 #define LPCIB_PCI_PIRQC_ROUT	0x62

Reply via email to