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 */

Reply via email to