Module Name: src
Committed By: matt
Date: Fri Dec 30 06:48:56 UTC 2011
Modified Files:
src/sys/arch/mips/rmi [matt-nb5-mips64]: rmixl_intr.h rmixl_nand_pci.c
rmixl_sdio.c rmixl_spi_pci.c rmixlreg.h
Added Files:
src/sys/arch/mips/rmi [matt-nb5-mips64]: rmixl_gpio_pci.c
Log Message:
Add GPIO support for XLP.
Let NAND, MMC/SD, and SPI remove their pins from the GPIO available pin mask.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1.2.1 src/sys/arch/mips/rmi/rmixl_gpio_pci.c
cvs rdiff -u -r1.1.2.9 -r1.1.2.10 src/sys/arch/mips/rmi/rmixl_intr.h
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/arch/mips/rmi/rmixl_nand_pci.c \
src/sys/arch/mips/rmi/rmixl_sdio.c src/sys/arch/mips/rmi/rmixl_spi_pci.c
cvs rdiff -u -r1.1.2.15 -r1.1.2.16 src/sys/arch/mips/rmi/rmixlreg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/mips/rmi/rmixl_intr.h
diff -u src/sys/arch/mips/rmi/rmixl_intr.h:1.1.2.9 src/sys/arch/mips/rmi/rmixl_intr.h:1.1.2.10
--- src/sys/arch/mips/rmi/rmixl_intr.h:1.1.2.9 Sat Dec 24 01:57:54 2011
+++ src/sys/arch/mips/rmi/rmixl_intr.h Fri Dec 30 06:48:55 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: rmixl_intr.h,v 1.1.2.9 2011/12/24 01:57:54 matt Exp $ */
+/* $NetBSD: rmixl_intr.h,v 1.1.2.10 2011/12/30 06:48:55 matt Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -107,4 +107,8 @@ void rmixl_intr_init_clk(void);
void rmixl_intr_init_ipi(void);
#endif
+void * gpio_intr_establish(size_t /* pin */, int /* ipl */, int /* ist */,
+ int (*)(void *), void *, bool);
+
+void gpio_intr_disestablish(void *);
#endif /* _MIPS_RMI_RMIXL_INTR_H_ */
Index: src/sys/arch/mips/rmi/rmixl_nand_pci.c
diff -u src/sys/arch/mips/rmi/rmixl_nand_pci.c:1.1.2.1 src/sys/arch/mips/rmi/rmixl_nand_pci.c:1.1.2.2
--- src/sys/arch/mips/rmi/rmixl_nand_pci.c:1.1.2.1 Tue Dec 27 19:58:19 2011
+++ src/sys/arch/mips/rmi/rmixl_nand_pci.c Fri Dec 30 06:48:56 2011
@@ -29,7 +29,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: rmixl_nand_pci.c,v 1.1.2.1 2011/12/27 19:58:19 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rmixl_nand_pci.c,v 1.1.2.2 2011/12/30 06:48:56 matt Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -58,6 +58,18 @@ struct xlnand_softc {
bus_space_handle_t sc_bsh;
};
+static inline uint32_t
+xlnand_read_4(struct xlnand_softc *sc, bus_size_t off)
+{
+ return bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
+}
+
+static inline void
+xlnand_write_4(struct xlnand_softc *sc, bus_size_t off, uint32_t v)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, v);
+}
+
CFATTACH_DECL_NEW(xlnand_pci, sizeof(struct xlnand_softc),
xlnand_pci_match, xlnand_pci_attach, NULL, NULL);
@@ -87,10 +99,22 @@ xlnand_pci_attach(device_t parent, devic
* Why isn't this accessible via a BAR?
*/
if (bus_space_subregion(sc->sc_bst, rcp->rc_pci_ecfg_eb_memh,
- pa->pa_tag | 0x100, 0, &sc->sc_bsh)) {
+ pa->pa_tag, 0, &sc->sc_bsh)) {
aprint_error(": can't map registers\n");
return;
}
aprint_normal(": XLP NAND Controller\n");
+
+ /*
+ * If a NAND is using non-0 RDY/BSY signals, we need to take control
+ * of those from GPIO.
+ */
+ uint32_t r = xlnand_read_4(sc, RMIXLP_NAND_RDYBSY_SEL);
+ for (r >>= 3; r != 0; r >>= 3) {
+ u_int rdybsy = r & 7;
+ if (rdybsy != 0) {
+ rcp->rc_gpio_available &= ~__BIT(33 + rdybsy);
+ }
+ }
}
Index: src/sys/arch/mips/rmi/rmixl_sdio.c
diff -u src/sys/arch/mips/rmi/rmixl_sdio.c:1.1.2.1 src/sys/arch/mips/rmi/rmixl_sdio.c:1.1.2.2
--- src/sys/arch/mips/rmi/rmixl_sdio.c:1.1.2.1 Sat Dec 24 01:57:54 2011
+++ src/sys/arch/mips/rmi/rmixl_sdio.c Fri Dec 30 06:48:56 2011
@@ -29,7 +29,7 @@
#include <sys/param.h>
-__KERNEL_RCSID(1, "$NetBSD: rmixl_sdio.c,v 1.1.2.1 2011/12/24 01:57:54 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rmixl_sdio.c,v 1.1.2.2 2011/12/30 06:48:56 matt Exp $");
#include <sys/device.h>
#include <sys/bus.h>
@@ -91,8 +91,10 @@ xlsdio_attach(device_t parent, device_t
pci_conf_write(pa->pa_pc, pa->pa_tag, RMIXLP_MMC_SYSCTRL, r);
DELAY(1000);
r |= RMIXLP_MMC_SYSCTRL_CA; /* Cache Allocate */
+#if 0
r |= RMIXLP_MMC_SYSCTRL_EN0; /* Enable Slot 0 */
r |= RMIXLP_MMC_SYSCTRL_EN1; /* Enable Slot 1 */
+#endif
r &= ~RMIXLP_MMC_SYSCTRL_CLK_DIS; /* Don't Disable Clock */
pci_conf_write(pa->pa_pc, pa->pa_tag, RMIXLP_MMC_SYSCTRL, r);
@@ -113,7 +115,15 @@ xlsdio_attach(device_t parent, device_t
pci_conf_write(pa->pa_pc, pa->pa_tag,
offset + SDHC_NINTR_STATUS, 0xffffffff);
- config_found(self, &xaa, xlsdio_print);
+ if (r & RMIXLP_MMC_SYSCTRL_EN(slot)) {
+ /*
+ * For any SDHC port we are using, we must remove
+ * the pins used by it from those that GPIO will
+ * offer to userland.
+ */
+ rcp->rc_gpio_available &= ~RMIXLP_MMC_GPIO_PINS(slot);
+ config_found(self, &xaa, xlsdio_print);
+ }
}
}
Index: src/sys/arch/mips/rmi/rmixl_spi_pci.c
diff -u src/sys/arch/mips/rmi/rmixl_spi_pci.c:1.1.2.1 src/sys/arch/mips/rmi/rmixl_spi_pci.c:1.1.2.2
--- src/sys/arch/mips/rmi/rmixl_spi_pci.c:1.1.2.1 Tue Dec 27 19:58:19 2011
+++ src/sys/arch/mips/rmi/rmixl_spi_pci.c Fri Dec 30 06:48:56 2011
@@ -29,7 +29,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: rmixl_spi_pci.c,v 1.1.2.1 2011/12/27 19:58:19 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rmixl_spi_pci.c,v 1.1.2.2 2011/12/30 06:48:56 matt Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -55,6 +55,7 @@ int xlspi_debug = 0;
static int xlspi_pci_match(device_t, cfdata_t, void *);
static void xlspi_pci_attach(device_t, device_t, void *);
+static int xlspi_intr(void *);
struct xlspi_softc {
device_t sc_dev;
@@ -82,7 +83,7 @@ xlspi_pci_attach(device_t parent, device
struct rmixl_config * const rcp = &rmixl_configuration;
struct pci_attach_args * const pa = aux;
struct xlspi_softc * const sc = device_private(self);
- // struct norbus_attach_args iba;
+ // struct spibus_attach_args iba;
sc->sc_dev = self;
sc->sc_bst = &rcp->rc_pci_ecfg_eb_memt;
@@ -91,10 +92,41 @@ xlspi_pci_attach(device_t parent, device
* Why isn't this accessible via a BAR?
*/
if (bus_space_subregion(sc->sc_bst, rcp->rc_pci_ecfg_eb_memh,
- pa->pa_tag | 0x100, 0, &sc->sc_bsh)) {
+ pa->pa_tag, 0, &sc->sc_bsh)) {
aprint_error(": can't map registers\n");
return;
}
- aprint_normal(": XLP SPI Controller\n");
+ uint32_t r = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+ RMIXLP_SPI_SYSCNTRL);
+
+ if ((r & RMIXLP_SPI_SYSCNTRL_PMEN) == 0) {
+ aprint_normal(": XLP SPI Controller%s\n", " (disabled)");
+ return;
+ }
+
+ /*
+ * Take away the SPI pins
+ */
+ rcp->rc_gpio_available &= ~RMIXLP_SPI_GPIO_PINS;
+
+ aprint_normal(": XLP SPI Controller%s\n", "");
+
+ pci_intr_handle_t pcih;
+ pci_intr_map(pa, &pcih);
+
+ if (pci_intr_establish(pa->pa_pc, pcih, IPL_VM, xlspi_intr, sc) == NULL) {
+ aprint_error_dev(self, "failed to establish interrupt\n");
+ } else {
+ const char * const intrstr = pci_intr_string(pa->pa_pc, pcih);
+ aprint_normal_dev(self, "interrupting at %s\n", intrstr);
+ }
+}
+
+static int
+xlspi_intr(void *v)
+{
+ struct xlspi_softc * const sc = v;
+
+ panic("%s(%p)", device_xname(sc->sc_dev), v);
}
Index: src/sys/arch/mips/rmi/rmixlreg.h
diff -u src/sys/arch/mips/rmi/rmixlreg.h:1.1.2.15 src/sys/arch/mips/rmi/rmixlreg.h:1.1.2.16
--- src/sys/arch/mips/rmi/rmixlreg.h:1.1.2.15 Wed Dec 28 05:36:11 2011
+++ src/sys/arch/mips/rmi/rmixlreg.h Fri Dec 30 06:48:56 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: rmixlreg.h,v 1.1.2.15 2011/12/28 05:36:11 matt Exp $ */
+/* $NetBSD: rmixlreg.h,v 1.1.2.16 2011/12/30 06:48:56 matt Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -900,6 +900,41 @@
*/
#define RMIXL_GPIO_LOW_PWR_DIS_RESV __BITS(31,9)
+#define RMIXLP_GPIO_PADOE(g) _RMIXL_OFFSET(0x40+(g)) // Pad Output Enable Register 0
+#define RMIXLP_GPIO_PADOE0 _RMIXL_OFFSET(0x40) // Pad Output Enable Register 0
+#define RMIXLP_GPIO_PADOE1 _RMIXL_OFFSET(0x41) // Pad Output Enable Register 1
+#define RMIXLP_GPIO_PADDRV(g) _RMIXL_OFFSET(0x42+(g)) // Pad Drive Register 0
+#define RMIXLP_GPIO_PADDRV0 _RMIXL_OFFSET(0x42) // Pad Drive Register 0
+#define RMIXLP_GPIO_PADDRV1 _RMIXL_OFFSET(0x43) // Pad Drive Register 1
+#define RMIXLP_GPIO_PADSAMPLE(g) _RMIXL_OFFSET(0x44+(g)) // Pad Sample Register 0
+#define RMIXLP_GPIO_PADSAMPLE0 _RMIXL_OFFSET(0x44) // Pad Sample Register 0
+#define RMIXLP_GPIO_PADSAMPLE1 _RMIXL_OFFSET(0x45) // Pad Sample Register 1
+#define RMIXLP_GPIO_INTEN(n,g) _RMIXL_OFFSET(0x46+2*(n)+(g)) // Interrupt 0 Enable Register 0
+#define RMIXLP_GPIO_INTEN0(n) _RMIXL_OFFSET(0x46+2*(n)) // Interrupt 0 Enable Register 0
+#define RMIXLP_GPIO_INTEN1(n) _RMIXL_OFFSET(0x47+2*(n)) // Interrupt 0 Enable Register 0
+#define RMIXLP_GPIO_INTEN00 _RMIXL_OFFSET(0x46) // Interrupt 0 Enable Register 0
+#define RMIXLP_GPIO_INTEN01 _RMIXL_OFFSET(0x47) // Interrupt 0 Enable Register 1
+#define RMIXLP_GPIO_INTEN10 _RMIXL_OFFSET(0x48) // Interrupt 1 Enable Register 0
+#define RMIXLP_GPIO_INTEN11 _RMIXL_OFFSET(0x49) // Interrupt 1 Enable Register 1
+#define RMIXLP_GPIO_INTEN20 _RMIXL_OFFSET(0x4A) // Interrupt 2 Enable Register 0
+#define RMIXLP_GPIO_INTEN21 _RMIXL_OFFSET(0x4B) // Interrupt 2 Enable Register 1
+#define RMIXLP_GPIO_INTEN30 _RMIXL_OFFSET(0x4C) // Interrupt 3 Enable Register 0
+#define RMIXLP_GPIO_INTEN31 _RMIXL_OFFSET(0x4D) // Interrupt 3 Enable Register 1
+#define RMIXLP_GPIO_INTPOL(g) _RMIXL_OFFSET((0x4E)+(g)) // Interrupt Polarity Register 0
+#define RMIXLP_GPIO_INTPOL0 _RMIXL_OFFSET(0x4E) // Interrupt Polarity Register 0
+#define RMIXLP_GPIO_INTPOL1 _RMIXL_OFFSET(0x4F) // Interrupt Polarity Register 1
+#define RMIXLP_GPIO_INTTYPE(g) _RMIXL_OFFSET(0x50+(g)) // Interrupt Type Register 0
+#define RMIXLP_GPIO_INTTYPE0 _RMIXL_OFFSET(0x50) // Interrupt Type Register 0
+#define RMIXLP_GPIO_INTTYPE1 _RMIXL_OFFSET(0x51) // Interrupt Type Register 1
+#define RMIXLP_GPIO_INTSTAT(g) _RMIXL_OFFSET(0x52+(g)) // Interrupt Status Register 0
+#define RMIXLP_GPIO_INTSTAT0 _RMIXL_OFFSET(0x52) // Interrupt Status Register 0
+#define RMIXLP_GPIO_INTSTAT1 _RMIXL_OFFSET(0x53) // Interrupt Status Register 1
+
+#define RMIXLP_GPIO_8XX_MAXPINS 41 /* 41 GPIO pins */
+#define RMIXLP_GPIO_4XX_MAXPINS 41 /* 41 GPIO pins */
+#define RMIXLP_GPIO_3XX_MAXPINS 57 /* 41 GPIO pins */
+#define RMIXLP_GPIO_3XXL_MAXPINS 44 /* 44 GPIO pins */
+
/*
* Peripheral I/O bus (Flash/PCMCIA) controller registers
*/
@@ -1432,6 +1467,12 @@
#define PCI_RMIXLP_STATID _RMIXL_OFFSET(0x3c)
#define PCI_RMIXLP_IRTINFO _RMIXL_OFFSET(0x3d)
+#define PCI_RMIXLP_STATID_BASE(x) (((x) >> 0) & 0xfff)
+#define PCI_RMIXLP_STATID_COUNT(x) (((x) >> 16) & 0xfff)
+
+#define PCI_RMIXLP_IRTINFO_BASE(x) (((x) >> 0) & 0xfff)
+#define PCI_RMIXLP_IRTINFO_COUNT(x) (((x) >> 16) & 0xfff)
+
/*
* XLP System Management Registers
*/
@@ -1608,14 +1649,78 @@
#define RMIXLP_NOR_STATUS_RDYBSY __BIT(0)
#define RMIXLP_NAND_PCITAG _RMIXL_PCITAG(0,7,1)
+#define RMIXLP_NAND_RDYBSY_SEL _RMIXL_OFFSET(0x81)
+
#define RMIXLP_SPI_PCITAG _RMIXL_PCITAG(0,7,2)
+#define RMIXLP_SPI_CS_CONFIG(n) _RMIXL_OFFSET(0x40+0x10*(n))
+#define RMIXLP_SPI_CS_FDIV(n) _RMIXL_OFFSET(0x41+0x10*(n))
+#define RMIXLP_SPI_CS_CMD(n) _RMIXL_OFFSET(0x42+0x10*(n))
+#define RMIXLP_SPI_CS_STATUS(n) _RMIXL_OFFSET(0x43+0x10*(n))
+#define RMIXLP_SPI_CS_INTEN(n) _RMIXL_OFFSET(0x44+0x10*(n))
+#define RMIXLP_SPI_CS_FIFO_THRESH(n) _RMIXL_OFFSET(0x45+0x10*(n))
+#define RMIXLP_SPI_CS_FIFO_WCNT(n) _RMIXL_OFFSET(0x46+0x10*(n))
+#define RMIXLP_SPI_CS_TXDATA_FIFO(n) _RMIXL_OFFSET(0x47+0x10*(n))
+#define RMIXLP_SPI_CS_RXDATA_FIFO(n) _RMIXL_OFFSET(0x48+0x10*(n))
+#define RMIXLP_SPI_SYSCNTRL _RMIXL_OFFSET(0x80)
+
+#define RMIXLP_SPI_CS_CONFIG_RXCAP __BIT(11) // RX capture on phase drive
+#define RMIXLP_SPI_CS_CONFIG_LSBFE __BIT(10) // LSB first enable
+#define RMIXLP_SPI_CS_CONFIG_CSTODATA __BITS(9,8) // chip select polarity 1:high
+#define RMIXLP_SPI_CS_CONFIG_SBPOL __BIT(6) // start bit polarity 1:high
+#define RMIXLP_SPI_CS_CONFIG_SBE __BIT(6) // start bit enable 1:enabled
+#define RMIXLP_SPI_CS_CONFIG_RXMISO __BIT(5) // 0: RX MOSI, 1: RX MISO
+#define RMIXLP_SPI_CS_CONFIG_TXMOSI __BIT(4) // 1: TX enable for MOSI pin
+#define RMIXLP_SPI_CS_CONFIG_TXMISO __BIT(3) // 1: TX enable for MISO pin
+#define RMIXLP_SPI_CS_CONFIG_CSPOL __BIT(2) // chip select polarity 1:high
+#define RMIXLP_SPI_CS_CONFIG_CPOL __BIT(1) // clock polarity 1:high
+#define RMIXLP_SPI_CS_CONFIG_CPHA __BIT(0) // SPI_CLK clock phase select
+
+#define RMIXLP_SPI_CS_FDIV_CNT __BITS(15,0) // divisor (min of 16)
+
+#define RMIXLP_SPI_CS_CMD_XFERBITCNT __BITS(31,16) // total # of bits - 1
+#define RMIXLP_SPI_CS_CMD_CONT __BIT(4)
+#define RMIXLP_SPI_CS_CMD_CMD __BITS(3,0)
+#define RMIXLP_SPI_CS_CMD_IDLE 0
+#define RMIXLP_SPI_CS_CMD_TX 1
+#define RMIXLP_SPI_CS_CMD_RX 2
+#define RMIXLP_SPI_CS_CMD_TXRX 3
+
+#define RMIXLP_SPI_CS_STATUS_RXOF __BIT(5) // RX FIFO overflow
+#define RMIXLP_SPI_CS_STATUS_TXUF __BIT(4) // TX FIFO underflow
+#define RMIXLP_SPI_CS_STATUS_RXTHRESH __BIT(3) // RX FIFO threshold crossed
+#define RMIXLP_SPI_CS_STATUS_TXTHRESH __BIT(2) // TX FIFO threshold crossed
+#define RMIXLP_SPI_CS_STATUS_XFERDONE __BIT(1) // Transfer is complete (RO)
+#define RMIXLP_SPI_CS_STATUS_XFERPEND __BIT(1) // Transfer is pending (RO)
+
+#define RMIXLP_SPI_CS_INTEN_RXOF __BIT(4) // RX FIFO overflow
+#define RMIXLP_SPI_CS_INTEN_TXUF __BIT(3) // TX FIFO underflow
+#define RMIXLP_SPI_CS_INTEN_RXTHRESH __BIT(2) // RX FIFO threshold crossed
+#define RMIXLP_SPI_CS_INTEN_TXTHRESH __BIT(1) // TX FIFO threshold crossed
+#define RMIXLP_SPI_CS_INTEN_XFERDONE __BIT(0) // Transfer is complete
+
+#define RMIXLP_SPI_CS_FIFO_THRESH_TXFIFO __BITS(7,4)
+#define RMIXLP_SPI_CS_FIFO_THRESH_RXFIFO __BITS(3,0)
+
+#define RMIXLP_SPI_CS_FIFO_WCNT_TXFIFO __BITS(7,4)
+#define RMIXLP_SPI_CS_FIFO_WCNT_RXFIFO __BITS(3,0)
+
+#define RMIXLP_SPI_SYSCNTRL_PMEN __BIT(8) // Pin muxing enable
+#define RMIXLP_SPI_SYSCNTRL_CLKDSI(n) __BIT(4+(n)) // Clock disable for chan
+#define RMIXLP_SPI_SYSCNTRL_RESET(n) __BIT(0+(n)) // Reset SPI channel n
+
+#define RMIXLP_SPI_GPIO_PINS __BITS(28,22)
+
#define RMIXLP_MMC_PCITAG _RMIXL_PCITAG(0,7,3)
#define RMIXLP_MMC_SLOTSIZE _RMIXL_OFFSET(0x40)
#define RMIXLP_MMC_SLOT0 _RMIXL_OFFSET(0x40)
#define RMIXLP_MMC_SLOT1 _RMIXL_OFFSET(0x80)
#define RMIXLP_MMC_SYSCTRL _RMIXL_OFFSET(0xC0)
+#define RMIXLP_MMC_CAPCFG0_S(n) _RMIXL_OFFSET(0xC1+5*(n))
+#define RMIXLP_MMC_CAPCFG1_S(n) _RMIXL_OFFSET(0xC2+5*(n))
+#define RMIXLP_MMC_INIT_PRESET_S(n) _RMIXL_OFFSET(0xC3+5*(n))
+#define RMIXLP_MMC_DEF_PRESET_S(n) _RMIXL_OFFSET(0xC4+5*(n))
#define RMIXLP_MMC_SYSCTRL_DELAY __BITS(21,19)
#define RMIXLP_MMC_SYSCTRL_RT __BIT(8)
@@ -1625,9 +1730,19 @@
#define RMIXLP_MMC_SYSCTRL_CA __BIT(4)
#define RMIXLP_MMC_SYSCTRL_EN1 __BIT(3)
#define RMIXLP_MMC_SYSCTRL_EN0 __BIT(2)
+#define RMIXLP_MMC_SYSCTRL_EN(n) __BIT(2+(n))
#define RMIXLP_MMC_SYSCTRL_CLK_DIS __BIT(1)
#define RMIXLP_MMC_SYSCTRL_RST __BIT(0)
+#define RMIXLP_MMC_CAPCFG0_S_EMB __BIT(17) // Extended Media Bus
+
+#define RMIXLP_MMC_GPIO_PINS0 \
+ (__BITS(10,0) | __BIT(29) | __BIT(31))
+#define RMIXLP_MMC_GPIO_PINS1 \
+ (__BITS(21,11) | __BIT(28) | __BIT(30))
+#define RMIXLP_MMC_GPIO_PINS(slot) \
+ (slot == 0 ? RMIXLP_MMC_GPIO_PINS0 : RMIXLP_MMC_GPIO_PINS1)
+
/*
* FMN non-core station configuration registers
*/
Added files:
Index: src/sys/arch/mips/rmi/rmixl_gpio_pci.c
diff -u /dev/null src/sys/arch/mips/rmi/rmixl_gpio_pci.c:1.1.2.1
--- /dev/null Fri Dec 30 06:48:56 2011
+++ src/sys/arch/mips/rmi/rmixl_gpio_pci.c Fri Dec 30 06:48:55 2011
@@ -0,0 +1,581 @@
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: rmixl_gpio_pci.c,v 1.1.2.1 2011/12/30 06:48:55 matt Exp $");
+
+#include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/gpio.h>
+
+#include "locators.h"
+#include "gpio.h"
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/gpio/gpiovar.h>
+
+#include <mips/rmi/rmixlreg.h>
+#include <mips/rmi/rmixlvar.h>
+#include <mips/rmi/rmixl_intr.h>
+
+#ifdef DEBUG
+int xlgpio_debug = 0;
+#define DPRINTF(x, ...) do { if (xlgpio_debug) printf(x, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+static int xlgpio_pci_match(device_t, cfdata_t, void *);
+static void xlgpio_pci_attach(device_t, device_t, void *);
+static void xlgpio_defer(device_t);
+static int xlgpio_high_intr(void *);
+static int xlgpio_ddb_intr(void *);
+static int xlgpio_sched_intr(void *);
+static int xlgpio_vm_intr(void *);
+static int xlgpio_stray_intr(void *v);
+
+static int xlgpio_pin_read(void *, int);
+static void xlgpio_pin_write(void *, int, int);
+static void xlgpio_pin_ctl(void *, int, int);
+
+static const uint8_t xlgpio_pincnt_by_variant[] = {
+ [RMIXLP_8XX] = RMIXLP_GPIO_8XX_MAXPINS,
+ [RMIXLP_4XX] = RMIXLP_GPIO_4XX_MAXPINS,
+ [RMIXLP_3XX] = RMIXLP_GPIO_3XX_MAXPINS,
+ [RMIXLP_3XXL] = RMIXLP_GPIO_3XXL_MAXPINS,
+ [RMIXLP_3XXH] = RMIXLP_GPIO_3XXL_MAXPINS,
+ [RMIXLP_3XXQ] = RMIXLP_GPIO_3XXL_MAXPINS,
+};
+
+
+static int (* const xlgpio_intrs[])(void *) = {
+ [IPL_VM - IPL_VM] = xlgpio_vm_intr,
+ [IPL_SCHED - IPL_VM] = xlgpio_sched_intr,
+ [IPL_DDB - IPL_VM] = xlgpio_ddb_intr,
+ [IPL_HIGH - IPL_VM] = xlgpio_high_intr,
+};
+
+struct xlgpio_intrpin {
+ struct evcnt gip_ev;
+ int (*gip_func)(void *);
+ void *gip_arg;
+ uint8_t gip_ipl;
+ uint8_t gip_ist;
+ char gip_ev_name[sizeof("pin XX")];
+};
+
+#define PINMASK 31
+#define PINGROUP (PINMASK+1)
+#define PIN_GROUP(pin) ((pin) / PINGROUP)
+#define PIN_SELECT(pin) ((pin) & PINMASK)
+#define PIN_MASK(pin) (1 << ((pin) & PINMASK))
+
+struct xlgpio_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ struct xlgpio_intrpin sc_pins[2*PINGROUP];
+ struct xlgpio_group {
+ struct xlgpio_intrpin *gg_pins;
+ uint32_t gg_padoe;
+ uint32_t gg_paddrv;
+ uint32_t gg_inten[IPL_HIGH - IPL_VM + 1];
+ uint32_t gg_intpol;
+ uint32_t gg_inttype;
+ uint16_t gg_r_padoe;
+ uint16_t gg_r_paddrv;
+ uint16_t gg_r_padsample;
+ uint16_t gg_r_inten[IPL_HIGH - IPL_VM + 1];
+ uint16_t gg_r_intpol;
+ uint16_t gg_r_inttype;
+ uint32_t gg_r_intstat;
+ } sc_groups[2];
+ kmutex_t *sc_pin_lock;
+ kmutex_t *sc_intr_lock;
+#if NGPIO > 0
+ uint8_t sc_pincnt;
+ struct gpio_chipset_tag sc_gpio_chipset;
+ gpio_pin_t sc_gpio_pins[64];
+#endif
+};
+
+static struct xlgpio_softc xlgpio_sc = { /* there can only be one */
+ .sc_pins = {
+ [0 ... 2*PINGROUP-1] = {
+ .gip_ipl = IPL_NONE,
+ .gip_ist = IST_NONE,
+ .gip_func = xlgpio_stray_intr,
+ },
+ },
+ .sc_groups = {
+ [0] = {
+ .gg_pins = xlgpio_sc.sc_pins,
+ .gg_r_padoe = RMIXLP_GPIO_PADOE(0),
+ .gg_r_paddrv = RMIXLP_GPIO_PADOE(0),
+ .gg_r_padsample = RMIXLP_GPIO_PADOE(0),
+ .gg_r_inten = {
+ [0] = RMIXLP_GPIO_INTEN(0, 0),
+ [1] = RMIXLP_GPIO_INTEN(1, 0),
+ [2] = RMIXLP_GPIO_INTEN(2, 0),
+ [3] = RMIXLP_GPIO_INTEN(3, 0),
+ },
+ .gg_r_intpol = RMIXLP_GPIO_INTPOL(0),
+ .gg_r_inttype = RMIXLP_GPIO_INTTYPE(0),
+ .gg_r_intstat = RMIXLP_GPIO_INTSTAT(0),
+ },
+ [1] = {
+ .gg_pins = xlgpio_sc.sc_pins + PINGROUP,
+ .gg_r_padoe = RMIXLP_GPIO_PADOE(1),
+ .gg_r_paddrv = RMIXLP_GPIO_PADOE(1),
+ .gg_r_padsample = RMIXLP_GPIO_PADOE(1),
+ .gg_r_inten = {
+ [0] = RMIXLP_GPIO_INTEN(0, 1),
+ [1] = RMIXLP_GPIO_INTEN(1, 1),
+ [2] = RMIXLP_GPIO_INTEN(2, 1),
+ [3] = RMIXLP_GPIO_INTEN(3, 1),
+ },
+ .gg_r_intpol = RMIXLP_GPIO_INTPOL(1),
+ .gg_r_inttype = RMIXLP_GPIO_INTTYPE(1),
+ .gg_r_intstat = RMIXLP_GPIO_INTSTAT(1),
+ },
+ },
+ .sc_gpio_chipset = {
+ .gp_cookie = &xlgpio_sc,
+#if 0
+ .gp_gc_open = xlgpio_gc_open,
+ .gp_gc_close = xlgpio_gc_close,
+#endif
+ .gp_pin_read = xlgpio_pin_read,
+ .gp_pin_write = xlgpio_pin_write,
+ .gp_pin_ctl = xlgpio_pin_ctl,
+ },
+};
+
+static inline uint32_t
+xlgpio_read_4(struct xlgpio_softc *sc, bus_size_t off)
+{
+ return bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
+}
+
+static inline void
+xlgpio_write_4(struct xlgpio_softc *sc, bus_size_t off, uint32_t v)
+{
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, v);
+}
+
+CFATTACH_DECL_NEW(xlgpio_pci, 0,
+ xlgpio_pci_match, xlgpio_pci_attach, NULL, NULL);
+
+static int
+xlgpio_pci_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct pci_attach_args * const pa = aux;
+
+ if (xlgpio_sc.sc_dev != NULL) // there can only be one
+ return 0;
+
+ if (pa->pa_id == PCI_ID_CODE(PCI_VENDOR_NETLOGIC, PCI_PRODUCT_NETLOGIC_XLP_GPIO))
+ return 1;
+
+ return 0;
+}
+
+static void
+xlgpio_pci_attach(device_t parent, device_t self, void *aux)
+{
+ struct rmixl_config * const rcp = &rmixl_configuration;
+ struct pci_attach_args * const pa = aux;
+ struct xlgpio_softc * const sc = &xlgpio_sc;
+ const char * const xname = device_xname(self);
+
+ KASSERT(sc->sc_dev == NULL);
+
+ self->dv_private = sc;
+ sc->sc_dev = self;
+ sc->sc_bst = &rcp->rc_pci_ecfg_eb_memt;
+
+ /*
+ * Why isn't this accessible via a BAR?
+ */
+ if (bus_space_subregion(sc->sc_bst, rcp->rc_pci_ecfg_eb_memh,
+ pa->pa_tag, 0, &sc->sc_bsh)) {
+ aprint_error(": can't map registers\n");
+ return;
+ }
+
+ aprint_normal(": XLP GPIO Controller\n");
+
+ sc->sc_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_HIGH);
+ sc->sc_pin_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
+
+ /*
+ * Of course, each XLP variant has a different number of pins.
+ */
+ KASSERT(rmixl_xlp_variant < __arraycount(xlgpio_pincnt_by_variant));
+ sc->sc_pincnt = xlgpio_pincnt_by_variant[rmixl_xlp_variant];
+ rcp->rc_gpio_available &= __BITS(sc->sc_pincnt - 1, 0);
+
+ /*
+ * Attach the evcnt for each pin, whether it's available or not.
+ */
+ for (size_t pin = 0; pin < sc->sc_pincnt; pin++) {
+ struct xlgpio_intrpin * const gip = &sc->sc_pins[pin];
+ snprintf(gip->gip_ev_name, sizeof(gip->gip_ev_name),
+ "pin %zu", pin);
+
+ evcnt_attach_dynamic(&gip->gip_ev, EVCNT_TYPE_INTR,
+ NULL, xname, gip->gip_ev_name);
+ KASSERT(gip->gip_func == xlgpio_stray_intr);
+ }
+
+ for (size_t group = 0; group < __arraycount(sc->sc_groups); group++) {
+ struct xlgpio_group * const gg = &sc->sc_groups[group];
+ KASSERT(gg->gg_intpol == 0);
+ KASSERT(gg->gg_inttype == 0);
+
+ /*
+ * Disable all interrupts for group.
+ * Get shadow copy of registers.
+ */
+
+ gg->gg_padoe = xlgpio_read_4(sc, gg->gg_r_padoe);
+ gg->gg_paddrv = xlgpio_read_4(sc, gg->gg_r_paddrv);
+ xlgpio_write_4(sc, gg->gg_r_intpol, gg->gg_intpol);
+ xlgpio_write_4(sc, gg->gg_r_inttype, gg->gg_inttype);
+ for (size_t irt = 0; irt < __arraycount(gg->gg_inten); irt++) {
+ KASSERT(gg->gg_inten[irt] == 0);
+ xlgpio_write_4(sc, gg->gg_r_inten[irt],
+ gg->gg_inten[irt]);
+ }
+ }
+
+ /*
+ * GPIO has 4 interrupts which map 1:1 on IPL_VM to IPL_HIGH
+ */
+ const pcireg_t irtinfo = xlgpio_read_4(sc, PCI_RMIXLP_IRTINFO);
+
+ const size_t irtstart = PCI_RMIXLP_IRTINFO_BASE(irtinfo);
+ const size_t irtcount = PCI_RMIXLP_IRTINFO_COUNT(irtinfo);
+
+ KASSERT(irtcount >= IPL_HIGH - IPL_VM + 1);
+
+ for (size_t irt = 0; irt < irtcount; irt++) {
+ if (rmixl_intr_establish(irtstart + irt, IPL_VM + irt,
+ RMIXL_TRIG_LEVEL, RMIXL_POLR_HIGH,
+ xlgpio_intrs[irt], sc, true) == NULL)
+ panic("%s: failed to establish interrupt %zu",
+ __func__, irtstart + irt);
+ }
+
+#if NGPIO > 0
+ config_defer(self, xlgpio_defer);
+#endif
+}
+
+static int
+xlgpio_stray_intr(void *v)
+{
+ return 0;
+}
+
+static int
+xlgpio_group_intr(struct xlgpio_softc *sc, int ipl, size_t group)
+{
+ struct xlgpio_group * const gg = &sc->sc_groups[group];
+ uint32_t sts = gg->gg_inten[ipl - IPL_VM];
+ int rv = 0;
+
+ if (sts == 0)
+ return rv;
+
+ sts &= xlgpio_read_4(sc, gg->gg_r_intstat);
+ if (sts == 0)
+ return rv;
+
+ /* First, ACK any edge type interrupts */
+ if (sts & gg->gg_inttype)
+ xlgpio_write_4(sc, gg->gg_r_intstat, sts & gg->gg_inttype);
+
+ /* narrow to level interrupts */
+ uint32_t intlevel = (sts & ~gg->gg_inttype);
+
+ while (sts != 0) {
+ const int bit = PINMASK - __builtin_clz(sts);
+ struct xlgpio_intrpin * const gip = &gg->gg_pins[bit];
+
+ KASSERT(gip->gip_ipl == ipl);
+ const int nrv = (*gip->gip_func)(gip->gip_arg);
+ if (nrv)
+ rv = nrv;
+ gip->gip_ev.ev_count++;
+ sts &= ~(1 << bit);
+ }
+
+ /* Now ACK any level type interrupts */
+ if (intlevel)
+ xlgpio_write_4(sc, gg->gg_r_intstat, intlevel);
+
+ return rv;
+}
+
+static inline int
+xlgpio_intr(struct xlgpio_softc *sc, size_t ipl)
+{
+ int rv = 0;
+ for (size_t group = 0; group < __arraycount(sc->sc_groups); group++) {
+ const int nrv = xlgpio_group_intr(sc, ipl, group);
+ if (!rv)
+ rv = nrv;
+ }
+
+ return rv;
+}
+
+static int
+xlgpio_high_intr(void *v)
+{
+ struct xlgpio_softc * const sc = v;
+ return xlgpio_intr(sc, IPL_HIGH);
+}
+
+static int
+xlgpio_ddb_intr(void *v)
+{
+ struct xlgpio_softc * const sc = v;
+ return xlgpio_intr(sc, IPL_DDB);
+}
+
+static int
+xlgpio_sched_intr(void *v)
+{
+ struct xlgpio_softc * const sc = v;
+ return xlgpio_intr(sc, IPL_SCHED);
+}
+
+static int
+xlgpio_vm_intr(void *v)
+{
+ struct xlgpio_softc * const sc = v;
+ return xlgpio_intr(sc, IPL_VM);
+}
+
+void *
+gpio_intr_establish(size_t pin, int ipl, int ist,
+ int (*func)(void *), void *arg, bool mpsafe)
+{
+ struct xlgpio_softc * const sc = &xlgpio_sc;
+ struct rmixl_config * const rcp = &rmixl_configuration;
+ struct xlgpio_intrpin * const gip = &sc->sc_pins[pin];
+ size_t group = PIN_GROUP(pin);
+ struct xlgpio_group * const gg = &sc->sc_groups[group];
+ const uint32_t mask = PIN_MASK(pin);
+ uint32_t * const inten_p = &gg->gg_inten[ipl - IPL_VM];
+
+ KASSERT(IPL_VM <= ipl);
+ KASSERT(ipl <= IPL_HIGH);
+ KASSERT(ist == IST_LEVEL_LOW || ist == IST_LEVEL_HIGH || ist == IST_EDGE);
+ KASSERT(func != NULL);
+ KASSERT(group < __arraycount(sc->sc_groups));
+
+ if (pin >= sc->sc_pincnt)
+ return NULL;
+
+ if ((pin & rcp->rc_gpio_available) == 0)
+ return NULL;
+
+ KASSERT((*inten_p & mask) == 0);
+ KASSERT(gip->gip_func != xlgpio_stray_intr);
+ KASSERT(gip->gip_ipl == IPL_NONE);
+ KASSERT(gip->gip_ist == IST_NONE);
+
+ mutex_enter(sc->sc_intr_lock);
+
+ gip->gip_ipl = ipl;
+ gip->gip_func = func;
+ gip->gip_arg = arg;
+
+ if (ist == IST_EDGE) {
+ atomic_or_32(&gg->gg_inttype, mask);
+ atomic_and_32(&gg->gg_intpol, ~mask);
+ } else if (ist == IST_LEVEL_HIGH) {
+ atomic_and_32(&gg->gg_inttype, ~mask);
+ atomic_and_32(&gg->gg_intpol, ~mask);
+ } else {
+ atomic_and_32(&gg->gg_inttype, ~mask);
+ atomic_or_32(&gg->gg_intpol, mask);
+ }
+
+ xlgpio_write_4(sc, gg->gg_r_inttype, gg->gg_inttype);
+ xlgpio_write_4(sc, gg->gg_r_intpol, gg->gg_intpol);
+
+ /*
+ * Atomically update our shadow copy of inten and feed the new
+ * value to the register.
+ */
+
+ xlgpio_write_4(sc, gg->gg_r_intpol, atomic_or_32_nv(inten_p, mask));
+
+ mutex_exit(sc->sc_intr_lock);
+
+ return gip;
+}
+
+void
+gpio_intr_disestablish(void *v)
+{
+ struct xlgpio_softc * const sc = &xlgpio_sc;
+ struct xlgpio_intrpin * const gip = v;
+ const size_t pin = gip - sc->sc_pins;
+ const size_t group = PIN_GROUP(pin);
+ const uint32_t mask = PIN_MASK(pin);
+ struct xlgpio_group * const gg = &sc->sc_groups[group];
+ uint32_t * const inten_p = &gg->gg_inten[gip->gip_ipl - IPL_VM];
+
+ KASSERT(&sc->sc_pins[pin] == gip);
+ KASSERT(pin < __arraycount(sc->sc_pins));
+ KASSERT(gip->gip_func != xlgpio_stray_intr);
+
+ *inten_p &= ~mask;
+ xlgpio_write_4(sc, gg->gg_r_inten[gip->gip_ipl - IPL_VM], *inten_p);
+ xlgpio_write_4(sc, RMIXLP_GPIO_INTSTAT(group), mask); /* ACK it */
+
+ gip->gip_ipl = IPL_NONE;
+ gip->gip_ist = IST_NONE;
+}
+
+#if NGPIO > 0
+static int
+xlgpio_pin_read(void *arg, int pin)
+{
+ struct xlgpio_softc * const sc = arg;
+ struct xlgpio_group * const gg = &sc->sc_groups[PIN_GROUP(pin)];
+ const uint32_t mask = PIN_MASK(pin);
+
+ /* no locking needed */
+
+ return (xlgpio_read_4(sc, gg->gg_r_padsample) & mask) != 0;
+}
+
+static void
+xlgpio_pin_write(void *arg, int pin, int value)
+{
+ struct xlgpio_softc * const sc = arg;
+ struct xlgpio_group * const gg = &sc->sc_groups[PIN_GROUP(pin)];
+ const uint32_t mask = 1 << (pin & PINMASK);
+
+ mutex_enter(sc->sc_pin_lock);
+
+ /*
+ * set new to 0 if no change, or mask since mask needs to be
+ * inverted.
+ */
+ const uint32_t new = (gg->gg_paddrv & mask) ^ (value ? mask : 0);
+
+ if (new) {
+ gg->gg_paddrv ^= new;
+ xlgpio_write_4(sc, gg->gg_r_paddrv, gg->gg_paddrv);
+ }
+
+ mutex_exit(sc->sc_pin_lock);
+}
+
+static void
+xlgpio_pin_ctl(void *arg, int pin, int flags)
+{
+ struct xlgpio_softc * const sc = arg;
+ const bus_size_t r_padoe = RMIXLP_GPIO_PADOE(pin / PINGROUP);
+ const uint32_t mask = 1 << (pin & PINMASK);
+
+ mutex_enter(sc->sc_pin_lock);
+
+ KASSERT(pin < sc->sc_pincnt);
+
+ const uint32_t old = xlgpio_read_4(sc, r_padoe);
+ uint32_t new;
+
+ switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
+ case GPIO_PIN_INPUT: new = old | mask; break;
+ case GPIO_PIN_OUTPUT: new = old & ~mask; break;
+ default: new = old;
+ }
+ if (old != new)
+ xlgpio_write_4(sc, r_padoe, new);
+
+ mutex_exit(sc->sc_pin_lock);
+}
+
+static void
+xlgpio_defer(device_t self)
+{
+ struct xlgpio_softc * const sc = device_private(self);
+ struct gpio_chipset_tag * const gp = &sc->sc_gpio_chipset;
+ struct gpiobus_attach_args gba;
+ gpio_pin_t *pins = sc->sc_gpio_pins;
+ uint64_t mask, oe, valueout, valuein;
+ const uint64_t available_pins = rmixl_configuration.rc_gpio_available;
+ u_int pin;
+
+ gba.gba_gc = gp;
+ gba.gba_pins = pins;
+
+ oe = ((uint64_t)sc->sc_groups[0].gg_padoe << 0)
+ | ((uint64_t)sc->sc_groups[1].gg_padoe << 32);
+ valueout = ((uint64_t)sc->sc_groups[0].gg_paddrv << 0)
+ | ((uint64_t)sc->sc_groups[1].gg_paddrv << 32);
+ valuein = ((uint64_t)xlgpio_read_4(sc, RMIXLP_GPIO_PADSAMPLE0) << 0)
+ | ((uint64_t)xlgpio_read_4(sc, RMIXLP_GPIO_PADSAMPLE1) << 32);
+
+ for (pin = 0, mask = 1;
+ available_pins >= mask && pin < sc->sc_pincnt;
+ mask <<= 1, pin++) {
+ if ((available_pins & mask) == 0)
+ continue;
+
+ pins->pin_num = pin;
+ pins->pin_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
+ pins->pin_flags =
+ (oe & mask) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+ pins->pin_state =
+ (((oe & mask) ? valueout : valuein) & mask)
+ ? GPIO_PIN_HIGH
+ : GPIO_PIN_LOW;
+
+ pins++;
+ }
+ gba.gba_npins = pins - sc->sc_gpio_pins;
+
+ config_found_ia(self, "gpiobus", &gba, gpiobus_print);
+}
+#endif /* NGPIO > 0 */