Sat Aug 27 12:47:49 2011 UTC ()
Split gcscpcib into MI part, and MD pci attachement which is also in
charge of attaching the MD pcib device.
Will be used by the upcoming evbmips loongson support.


(bouyer)
diff -r1.360 -r1.361 src/sys/arch/i386/conf/files.i386
diff -r1.8 -r0 src/sys/arch/i386/pci/gcscpcib.c
diff -r0 -r1.1 src/sys/arch/i386/pci/gcscpcib_pci.c
diff -r1.1 -r0 src/sys/arch/i386/pci/gcscpcibreg.h
diff -r0 -r1.1 src/sys/dev/ic/gcscpcib.c
diff -r0 -r1.1 src/sys/dev/ic/gcscpcibreg.h
diff -r0 -r1.1 src/sys/dev/ic/gcscpcibvar.h

cvs diff -r1.360 -r1.361 src/sys/arch/i386/conf/files.i386 (expand / switch to unified diff)

--- src/sys/arch/i386/conf/files.i386 2011/06/12 03:35:41 1.360
+++ src/sys/arch/i386/conf/files.i386 2011/08/27 12:47:49 1.361
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1# $NetBSD: files.i386,v 1.360 2011/06/12 03:35:41 rmind Exp $ 1# $NetBSD: files.i386,v 1.361 2011/08/27 12:47:49 bouyer Exp $
2# 2#
3# new style config file for i386 architecture 3# new style config file for i386 architecture
4# 4#
5 5
6ifndef xen 6ifndef xen
7 7
8# maxpartitions must be first item in files.${ARCH}.newconf 8# maxpartitions must be first item in files.${ARCH}.newconf
9maxpartitions 8 9maxpartitions 8
10 10
11maxusers 2 16 128 11maxusers 2 16 128
12 12
13defparam opt_kernbase.h KERNBASE 13defparam opt_kernbase.h KERNBASE
14 14
@@ -203,28 +203,29 @@ file arch/i386/pci/geodecntr.c geodecntr @@ -203,28 +203,29 @@ file arch/i386/pci/geodecntr.c geodecntr
203 203
204# PCI-EISA bridges 204# PCI-EISA bridges
205device pceb: eisabus, isabus 205device pceb: eisabus, isabus
206attach pceb at pci 206attach pceb at pci
207file arch/i386/pci/pceb.c pceb 207file arch/i386/pci/pceb.c pceb
208 208
209# PCI-ISA bridges 209# PCI-ISA bridges
210device gscpcib: isabus, gpiobus 210device gscpcib: isabus, gpiobus
211attach gscpcib at pci 211attach gscpcib at pci
212file arch/i386/pci/gscpcib.c gscpcib 212file arch/i386/pci/gscpcib.c gscpcib
213 213
214# AMD Geode CS5535/CS5536 PCI-ISA bridge 214# AMD Geode CS5535/CS5536 PCI-ISA bridge
215device gcscpcib: isabus, sysmon_wdog, gpiobus 215device gcscpcib: isabus, sysmon_wdog, gpiobus
216attach gcscpcib at pci 216attach gcscpcib at pci with gcscpcib_pci
217file arch/i386/pci/gcscpcib.c gcscpcib 217file arch/i386/pci/gcscpcib_pci.c gcscpcib_pci
 218file dev/ic/gcscpcib.c gcscpcib
218 219
219device piixpcib: isabus, bioscall 220device piixpcib: isabus, bioscall
220attach piixpcib at pci 221attach piixpcib at pci
221file arch/i386/pci/piixpcib.c piixpcib 222file arch/i386/pci/piixpcib.c piixpcib
222 223
223device viapcib: isabus, i2cbus 224device viapcib: isabus, i2cbus
224attach viapcib at pci 225attach viapcib at pci
225file arch/i386/pci/viapcib.c viapcib 226file arch/i386/pci/viapcib.c viapcib
226 227
227# PCI-MCA bridges 228# PCI-MCA bridges
228device pcmb: mcabus 229device pcmb: mcabus
229attach pcmb at pci 230attach pcmb at pci
230file arch/i386/pci/pcmb.c pcmb 231file arch/i386/pci/pcmb.c pcmb

File Deleted: src/sys/arch/i386/pci/Attic/gcscpcib.c

File Added: src/sys/arch/i386/pci/gcscpcib_pci.c
/* $NetBSD: gcscpcib_pci.c,v 1.1 2011/08/27 12:47:49 bouyer Exp $ */
/* $OpenBSD: gcscpcib.c,v 1.6 2007/11/17 17:02:47 mbalmer Exp $	*/

/*
 * Copyright (c) 2008 Yojiro UO <yuo@nui.org>
 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
 * Copyright (c) 2007 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * AMD CS5535/CS5536 series LPC bridge also containing timer, watchdog and GPIO.
 * machine-dependent attachement.
 */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gcscpcib_pci.c,v 1.1 2011/08/27 12:47:49 bouyer Exp $");


#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/timetc.h>
#include <sys/wdog.h>

#include <sys/bus.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/gpio/gpiovar.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/ic/gcscpcibreg.h>
#include <dev/ic/gcscpcibvar.h>

#include <machine/cpufunc.h>
#include <x86/pci/pcibvar.h>

struct gcscpcib_pci_softc {
        /* we call pcibattach() which assumes softc starts like this: */
	struct pcib_softc       sc_pcib;
	/* MI gcscpcib datas */
	struct gcscpcib_softc	sc_gcscpcib;
};

static int      gcscpcib_pci_match(device_t, cfdata_t, void *);
static void     gcscpcib_pci_attach(device_t, device_t, void *);

CFATTACH_DECL_NEW(gcscpcib_pci, sizeof(struct gcscpcib_pci_softc),
        gcscpcib_pci_match, gcscpcib_pci_attach, NULL, NULL);


static int
gcscpcib_pci_match(device_t parent, cfdata_t match, void *aux)
{ 
	struct pci_attach_args *pa = aux;

	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE ||
	    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_ISA)
		return 0;

	switch (PCI_PRODUCT(pa->pa_id)) {
	case PCI_PRODUCT_NS_CS5535_ISA:
	case PCI_PRODUCT_AMD_CS5536_PCIB:
		return 2;	/* supersede pcib(4) */
	}

	return 0;
}

static void
gcscpcib_pci_attach(device_t parent, device_t self, void *aux)
{
	struct gcscpcib_pci_softc *sc = device_private(self);
	struct pci_attach_args *pa = (struct pci_attach_args *)aux;

	sc->sc_pcib.sc_pc = pa->pa_pc;
	sc->sc_pcib.sc_tag = pa->pa_tag;
	/* Attach the PCI-ISA bridge at first */
	pcibattach(parent, self, aux);
	/* then attach gcscpcib itself */
	gcscpcib_attach(self, &sc->sc_gcscpcib, pa->pa_iot);
}

uint64_t
gcsc_rdmsr(uint msr)
{
	return rdmsr(msr);
}

void
gcsc_wrmsr(uint msr, uint64_t v)
{
	wrmsr(msr, v);
}

File Deleted: src/sys/arch/i386/pci/Attic/gcscpcibreg.h

File Added: src/sys/dev/ic/gcscpcib.c
/* $NetBSD: gcscpcib.c,v 1.1 2011/08/27 12:47:49 bouyer Exp $ */
/* $OpenBSD: gcscpcib.c,v 1.6 2007/11/17 17:02:47 mbalmer Exp $	*/

/*
 * Copyright (c) 2008 Yojiro UO <yuo@nui.org>
 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
 * Copyright (c) 2007 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * AMD CS5535/CS5536 series LPC bridge also containing timer, watchdog and GPIO.
 */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gcscpcib.c,v 1.1 2011/08/27 12:47:49 bouyer Exp $");

#include "gpio.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/sysctl.h>
#include <sys/timetc.h>
#include <sys/wdog.h>

#include <sys/bus.h>

#include <dev/gpio/gpiovar.h>

#include <dev/sysmon/sysmonvar.h>

#include <dev/ic/gcscpcibreg.h>
#include <dev/ic/gcscpcibvar.h>

/* define if you need to select MFGPT for watchdog manually (0-5). */
/* #define AMD553X_WDT_FORCEUSEMFGPT 	0 */
/* select precision of watchdog timer (default value = 0.25sec (4Hz tick) */
#define	AMD553X_MFGPT_PRESCALE	AMD553X_MFGPT_DIV_8K /* 32K/8K = 4Hz */

/* #define GCSCPCIB_DEBUG */
#ifdef GCSCPCIB_DEBUG
#define DPRINTF(x)	printf x
#else
#define DPRINTF(x)
#endif

/* 1 bit replace (not support multiple bit)*/
#define AMD553X_MFGPTx_NR_DISABLE(x, bit) \
	( gcsc_wrmsr(AMD553X_MFGPT_NR, gcsc_rdmsr(AMD553X_MFGPT_NR) & ~((bit) << (x))) )
#define AMD553X_MFGPTx_NR_ENABLE(x, bit) \
	( gcsc_wrmsr(AMD553X_MFGPT_NR, gcsc_rdmsr(AMD553X_MFGPT_NR) | ((bit) << (x))) )

/* caliculate watchdog timer setting */
#define	AMD553X_WDT_TICK (1<<(AMD553X_MFGPT_DIV_32K - AMD553X_MFGPT_PRESCALE))
#define AMD553X_WDT_COUNTMAX	(0xffff / AMD553X_WDT_TICK)

static u_int	gcscpcib_get_timecount(struct timecounter *tc);
static int	gscspcib_scan_mfgpt(struct gcscpcib_softc *sc);
static void 	gscspcib_wdog_update(struct gcscpcib_softc *, uint16_t);
static int	gcscpcib_wdog_setmode(struct sysmon_wdog *smw);
static int	gcscpcib_wdog_tickle(struct sysmon_wdog *smw);
static void	gcscpcib_wdog_enable(struct gcscpcib_softc *sc);
static void	gcscpcib_wdog_disable(struct gcscpcib_softc *sc);
static void	gcscpcib_wdog_reset(struct gcscpcib_softc *sc);

#if NGPIO > 0
static int	gcscpcib_gpio_pin_read(void *, int);
static void	gcscpcib_gpio_pin_write(void *, int, int);
static void	gcscpcib_gpio_pin_ctl(void *, int, int);
#endif

void
gcscpcib_attach(device_t self, struct gcscpcib_softc *sc,
    bus_space_tag_t iot)
{
	struct timecounter *tc = &sc->sc_timecounter;
	bus_addr_t wdtbase;
	int wdt = 0;
#if NGPIO > 0
	struct gpiobus_attach_args gba;
	bus_addr_t gpiobase;
	int i, gpio;
#endif

	sc->sc_iot = iot;
#if NGPIO > 0
	sc->sc_gpio_iot = iot;
#endif

	/* Attach the CS553[56] timer */
	tc->tc_get_timecount = gcscpcib_get_timecount;
	tc->tc_counter_mask = 0xffffffff;
	tc->tc_frequency = 3579545;
	tc->tc_name = device_xname(self);
	tc->tc_quality = 1000;
	tc->tc_priv = sc;
	tc_init(tc);

	/* Attach the watchdog timer */
	wdtbase = gcsc_rdmsr(MSR_LBAR_MFGPT) & 0xffff;
	if (bus_space_map(sc->sc_iot, wdtbase, 64, 0, &sc->sc_ioh)) {
		aprint_error_dev(self, "can't map memory space for WDT\n");
	} else {
		/* select a MFGPT timer for watchdog counter */
		if (!gscspcib_scan_mfgpt(sc)) {
			aprint_error_dev(self, "can't alloc an MFGPT for WDT\n");
			goto gpio;
		}
		/* 
		 * Note: MFGPGx_SETUP register is write once register
 		 * except CNT_EN and CMP[12]EV bit. 
		 */
		bus_space_write_2(sc->sc_iot, sc->sc_ioh,
			AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt),
		    	AMD553X_MFGPT_CMP2EV | AMD553X_MFGPT_CMP2 |
		    	AMD553X_MFGPT_PRESCALE);

		/* disable watchdog action */
		AMD553X_MFGPTx_NR_DISABLE(sc->sc_wdt_mfgpt, 
			AMD553X_MFGPT0_C2_NMIM);
		AMD553X_MFGPTx_NR_DISABLE(sc->sc_wdt_mfgpt,
			AMD553X_MFGPT0_C2_RSTEN);

		sc->sc_smw.smw_name = device_xname(self);
		sc->sc_smw.smw_cookie = sc;
		sc->sc_smw.smw_setmode = gcscpcib_wdog_setmode;
		sc->sc_smw.smw_tickle = gcscpcib_wdog_tickle;
		sc->sc_smw.smw_period = 32;
		aprint_normal_dev(self, "Watchdog Timer via MFGPT%d",
			 sc->sc_wdt_mfgpt);
		wdt = 1;
	}

gpio:
#if NGPIO > 0
	/* map GPIO I/O space */
	gpiobase = gcsc_rdmsr(MSR_LBAR_GPIO) & 0xffff;
	if (!bus_space_map(sc->sc_gpio_iot, gpiobase, 0xff, 0,
	    &sc->sc_gpio_ioh)) {
		aprint_normal(", GPIO");

		/* initialize pin array */
		for (i = 0; i < AMD553X_GPIO_NPINS; i++) {
			sc->sc_gpio_pins[i].pin_num = i;
			sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
			    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
			    GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE |
			    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
			    GPIO_PIN_INVIN | GPIO_PIN_INVOUT;

			/* read initial state */
			sc->sc_gpio_pins[i].pin_state =
			    gcscpcib_gpio_pin_read(sc, i);
		}

		/* create controller tag */
		sc->sc_gpio_gc.gp_cookie = sc;
		sc->sc_gpio_gc.gp_pin_read = gcscpcib_gpio_pin_read;
		sc->sc_gpio_gc.gp_pin_write = gcscpcib_gpio_pin_write;
		sc->sc_gpio_gc.gp_pin_ctl = gcscpcib_gpio_pin_ctl;

		gba.gba_gc = &sc->sc_gpio_gc;
		gba.gba_pins = sc->sc_gpio_pins;
		gba.gba_npins = AMD553X_GPIO_NPINS;
		gpio = 1;
	}
#endif
	aprint_normal("\n");

#if NGPIO > 0
	/* Attach GPIO framework */
	if (gpio)
                config_found_ia(self, "gpiobus", &gba, gpiobus_print);
#endif

	/* Register Watchdog timer to SMW */
	if (wdt) {
		if (sysmon_wdog_register(&sc->sc_smw) != 0)
			aprint_error_dev(self,
			    "cannot register wdog with sysmon\n");
	}
}

static u_int
gcscpcib_get_timecount(struct timecounter *tc)
{
        return gcsc_rdmsr(AMD553X_TMC);
}

/* Watchdog timer support functions */
static int	
gscspcib_scan_mfgpt(struct gcscpcib_softc *sc)
{
	int i;

#ifdef AMD553X_WDT_FORCEUSEMFGPT
	if (AMD553X_WDT_FORCEUSEMFGPT >= AMD553X_MFGPT_MAX)
		return 0;
	sc->sc_wdt_mfgpt = AMD553X_WDT_FORCEUSEMFGPT;
	return 1;
#endif /* AMD553X_WDT_FORCEUSEMFGPT */

	for (i = 0; i < AMD553X_MFGPT_MAX; i++){
		if (bus_space_read_2(sc->sc_iot, sc->sc_ioh,
		    AMD553X_MFGPTX_SETUP(i)) == 0) {
			/* found unused MFGPT, use it. */
			sc->sc_wdt_mfgpt = i;
			return 1;
		}
	}
	/* no MFGPT for WDT found */
	return 0;  
}


static void
gscspcib_wdog_update(struct gcscpcib_softc *sc, uint16_t count)
{
#ifdef GCSCPCIB_DEBUG
	uint16_t cnt;
	cnt = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_CNT(sc->sc_wdt_mfgpt));
#endif
	if (count > AMD553X_WDT_COUNTMAX)
		count = AMD553X_WDT_COUNTMAX;
	/* 
	 * CS553X databook recommend following sequence to re-initialize
	 * the counter and compare value. (See p165 on CS5536 databook) 
	 * 1: suspend counter: clear counter enable bit to 0 
	 * 2: reset (and NMI, if need) enable bit in MSRs
	 * 3: update counter & clear event flags
	 * 4: resume (2) operation
	 * 5: re-enable counter
	 */
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt), 0);
	AMD553X_MFGPTx_NR_DISABLE(sc->sc_wdt_mfgpt, AMD553X_MFGPT0_C2_RSTEN);
	bus_space_write_2(sc->sc_iot, sc->sc_ioh, 
		AMD553X_MFGPTX_CNT(sc->sc_wdt_mfgpt), count);
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt), 
			AMD553X_MFGPT_CMP1 | AMD553X_MFGPT_CMP2);
	AMD553X_MFGPTx_NR_ENABLE(sc->sc_wdt_mfgpt, AMD553X_MFGPT0_C2_RSTEN);
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt),
	    	AMD553X_MFGPT_CNT_EN | AMD553X_MFGPT_CMP2);

	DPRINTF(("%s: MFGPT%d_CNT= %d -> %d (expect: %d), MFGPT_NR=%#.8x\n",
		__func__, sc->sc_wdt_mfgpt, cnt,
		bus_space_read_2(sc->sc_iot, sc->sc_ioh,
			 AMD553X_MFGPTX_CNT(sc->sc_wdt_mfgpt)), count,
		(uint32_t)(gcsc_rdmsr(AMD553X_MFGPT_NR))));
}

static void
gcscpcib_wdog_disable(struct gcscpcib_softc *sc)
{
	/*
	 * stop counter and reset counter value 
	 * Note: as the MFGPTx_SETUP is write once register, the prescaler
	 * setting, clock select and compare mode are kept till reset.
	 */
	gscspcib_wdog_update(sc, 0);
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt), 0);

	/* disable watchdog action */
	DPRINTF(("%s: disable watchdog action\n", __func__));
	AMD553X_MFGPTx_NR_DISABLE(sc->sc_wdt_mfgpt, AMD553X_MFGPT0_C2_RSTEN);
}

static void
gcscpcib_wdog_enable(struct gcscpcib_softc *sc)
{
	int period = sc->sc_smw.smw_period;

	/* clear recent event flag and counter value, and start counter */
	gcscpcib_wdog_reset(sc);
	/* set watchdog timer limit, counter tick is 0.5sec */
	bus_space_write_2(sc->sc_iot, sc->sc_ioh, 
		AMD553X_MFGPTX_CMP2(sc->sc_wdt_mfgpt), 
			period * AMD553X_WDT_TICK);

	/* enable watchdog action */
	DPRINTF(("%s: enable watchdog action. (MFGPT0_CMP2= %d)\n", __func__,
	        bus_space_read_2(sc->sc_iot, sc->sc_ioh,
			 AMD553X_MFGPTX_CMP2(sc->sc_wdt_mfgpt))));
	AMD553X_MFGPTx_NR_ENABLE(sc->sc_wdt_mfgpt, AMD553X_MFGPT0_C2_RSTEN);
}

static int
gcscpcib_wdog_setmode(struct sysmon_wdog *smw)
{
	struct gcscpcib_softc *sc = smw->smw_cookie;

	if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
		gcscpcib_wdog_disable(sc);
		return 0;
	}

	if (smw->smw_period == WDOG_PERIOD_DEFAULT)
		smw->smw_period = 32;
	else if (smw->smw_period > AMD553X_WDT_COUNTMAX) /* too big */
		return EINVAL;	

	gcscpcib_wdog_enable(sc);

	return 0;
}

static void
gcscpcib_wdog_reset(struct gcscpcib_softc *sc)
{
	/* reset counter value */
	gscspcib_wdog_update(sc, 0);
	/* start counter & clear recent event of CMP2 */
	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
		AMD553X_MFGPTX_SETUP(sc->sc_wdt_mfgpt),
	   	AMD553X_MFGPT_CNT_EN | AMD553X_MFGPT_CMP2);
}

static int
gcscpcib_wdog_tickle(struct sysmon_wdog *smw)
{
	struct gcscpcib_softc *sc = smw->smw_cookie;

	DPRINTF(("%s: update watchdog timer\n", __func__));
	gcscpcib_wdog_reset(sc);
	return 0;
}

#if NGPIO > 0
/* GPIO support functions */
static int
gcscpcib_gpio_pin_read(void *arg, int pin)
{
	struct gcscpcib_softc *sc = arg;
	uint32_t data;
	int reg;

	reg = AMD553X_GPIO_OUT_VAL;
	if (pin > 15) {
		pin &= 0x0f;
		reg += AMD553X_GPIOH_OFFSET;
	}
	data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg);

	return data & 1 << pin ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
}

static void
gcscpcib_gpio_pin_write(void *arg, int pin, int value)
{
	struct gcscpcib_softc *sc = arg;
	uint32_t data;
	int reg;

	reg = AMD553X_GPIO_OUT_VAL;
	if (pin > 15) {
		pin &= 0x0f;
		reg += AMD553X_GPIOH_OFFSET;
	}
	if (value == 1)
		data = 1 << pin;
	else
		data = 1 << (pin + 16);

	bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data);
}

static void
gcscpcib_gpio_pin_ctl(void *arg, int pin, int flags)
{
	struct gcscpcib_softc *sc = arg;
	int n, reg[7], val[7], nreg = 0, off = 0;

	if (pin > 15) {
		pin &= 0x0f;
		off = AMD553X_GPIOH_OFFSET;
	}

	reg[nreg] = AMD553X_GPIO_IN_EN + off;
	if (flags & GPIO_PIN_INPUT)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_OUT_EN + off;
	if (flags & GPIO_PIN_OUTPUT)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_OD_EN + off;
	if (flags & GPIO_PIN_OPENDRAIN)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_PU_EN + off;
	if (flags & GPIO_PIN_PULLUP)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_PD_EN + off;
	if (flags & GPIO_PIN_PULLDOWN)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_IN_INVRT_EN + off;
	if (flags & GPIO_PIN_INVIN)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	reg[nreg] = AMD553X_GPIO_OUT_INVRT_EN + off;
	if (flags & GPIO_PIN_INVOUT)
		val[nreg++] = 1 << pin;
	else
		val[nreg++] = 1 << (pin + 16);

	/* set flags */
	for (n = 0; n < nreg; n++)
		bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg[n],
		    val[n]);
} 
#endif /* NGPIO > 0 */


File Added: src/sys/dev/ic/gcscpcibreg.h
/* $NetBSD: gcscpcibreg.h,v 1.1 2011/08/27 12:47:49 bouyer Exp $ */
/* $OpenBSD: glxpcib.c,v 1.6 2007/11/17 17:02:47 mbalmer Exp $	*/

/*
 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
 * Copyright (c) 2007 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Register definitions for the AMD CS5535/CS5536 Companion Device.
 */

#ifndef _IC_GCSCPCIBREG_H_
#define _IC_GCSCPCIBREG_H_

#define	AMD553X_REV		0x51400017
#define	AMD553X_REV_MASK	0xff
#define	AMD553X_TMC		0x51400050

/* Multi-Functional General Purpose Timer */
#define	MSR_LBAR_MFGPT		0x5140000d
#define AMD553X_MFGPT_MAX	6	/* 6 timers for wdog */
#define AMD553X_MFGPT_REGOFFSET	0x8
#define	AMD553X_MFGPTX_CMP1(x)	(0x00000000 + (AMD553X_MFGPT_REGOFFSET * (x)))
#define	AMD553X_MFGPTX_CMP2(x)	(0x00000002 + (AMD553X_MFGPT_REGOFFSET * (x)))
#define	AMD553X_MFGPTX_CNT(x)	(0x00000004 + (AMD553X_MFGPT_REGOFFSET * (x)))
#define	AMD553X_MFGPTX_SETUP(x)	(0x00000006 + (AMD553X_MFGPT_REGOFFSET * (x)))
#define	AMD553X_MFGPT_DIV_MASK	0x000f	/* div = 1 << mask */
#define	  AMD553X_MFGPT_DIV_1	0x0000
#define	  AMD553X_MFGPT_DIV_2	0x0001
#define	  AMD553X_MFGPT_DIV_4	0x0002
#define	  AMD553X_MFGPT_DIV_8	0x0003
#define	  AMD553X_MFGPT_DIV_16	0x0004
#define	  AMD553X_MFGPT_DIV_32	0x0005
#define	  AMD553X_MFGPT_DIV_64	0x0006
#define	  AMD553X_MFGPT_DIV_128	0x0007
#define	  AMD553X_MFGPT_DIV_256	0x0008
#define	  AMD553X_MFGPT_DIV_512	0x0009
#define	  AMD553X_MFGPT_DIV_1K	0x000a
#define	  AMD553X_MFGPT_DIV_2K	0x000b
#define	  AMD553X_MFGPT_DIV_4K	0x000c
#define	  AMD553X_MFGPT_DIV_8K	0x000d
#define	  AMD553X_MFGPT_DIV_16K	0x000e
#define	  AMD553X_MFGPT_DIV_32K	0x000f
#define	AMD553X_MFGPT_CLKSEL	0x0010
#define	AMD553X_MFGPT_REV_EN	0x0020
#define	AMD553X_MFGPT_CMP1DIS	0x0000
#define	AMD553X_MFGPT_CMP1EQ	0x0040
#define	AMD553X_MFGPT_CMP1GE	0x0080
#define	AMD553X_MFGPT_CMP1EV	0x00c0
#define	AMD553X_MFGPT_CMP2DIS	0x0000
#define	AMD553X_MFGPT_CMP2EQ	0x0100
#define	AMD553X_MFGPT_CMP2GE	0x0200
#define	AMD553X_MFGPT_CMP2EV	0x0300
#define	AMD553X_MFGPT_STOP_EN	0x0800
#define	AMD553X_MFGPT_SET	0x1000
#define	AMD553X_MFGPT_CMP1	0x2000
#define	AMD553X_MFGPT_CMP2	0x4000
#define	AMD553X_MFGPT_CNT_EN	0x8000
#define	AMD553X_MFGPT_IRQ	0x51400028
#define	AMD553X_MFGPT0_C1_IRQM	0x00000001
#define	AMD553X_MFGPT1_C1_IRQM	0x00000002
#define	AMD553X_MFGPT2_C1_IRQM	0x00000004
#define	AMD553X_MFGPT3_C1_IRQM	0x00000008
#define	AMD553X_MFGPT4_C1_IRQM	0x00000010
#define	AMD553X_MFGPT5_C1_IRQM	0x00000020
#define	AMD553X_MFGPT6_C1_IRQM	0x00000040
#define	AMD553X_MFGPT7_C1_IRQM	0x00000080
#define	AMD553X_MFGPT0_C2_IRQM	0x00000100
#define	AMD553X_MFGPT1_C2_IRQM	0x00000200
#define	AMD553X_MFGPT2_C2_IRQM	0x00000400
#define	AMD553X_MFGPT3_C2_IRQM	0x00000800
#define	AMD553X_MFGPT4_C2_IRQM	0x00001000
#define	AMD553X_MFGPT5_C2_IRQM	0x00002000
#define	AMD553X_MFGPT6_C2_IRQM	0x00004000
#define	AMD553X_MFGPT7_C2_IRQM	0x00008000
#define	AMD553X_MFGPT_NR	0x51400029 /* NMI and Reset mask */
#define	AMD553X_MFGPT0_C1_NMIM	0x00000001
#define	AMD553X_MFGPT1_C1_NMIM	0x00000002
#define	AMD553X_MFGPT2_C1_NMIM	0x00000004
#define	AMD553X_MFGPT3_C1_NMIM	0x00000008
#define	AMD553X_MFGPT4_C1_NMIM	0x00000010
#define	AMD553X_MFGPT5_C1_NMIM	0x00000020
#define	AMD553X_MFGPT6_C1_NMIM	0x00000040
#define	AMD553X_MFGPT7_C1_NMIM	0x00000080
#define	AMD553X_MFGPT0_C2_NMIM	0x00000100
#define	AMD553X_MFGPT1_C2_NMIM	0x00000200
#define	AMD553X_MFGPT2_C2_NMIM	0x00000400
#define	AMD553X_MFGPT3_C2_NMIM	0x00000800
#define	AMD553X_MFGPT4_C2_NMIM	0x00001000
#define	AMD553X_MFGPT5_C2_NMIM	0x00002000
#define	AMD553X_MFGPT6_C2_NMIM	0x00004000
#define	AMD553X_MFGPT7_C2_NMIM	0x00008000
#define	AMD553X_NMI_LEG		0x00010000
#define	AMD553X_MFGPT0_C2_RSTEN	0x01000000
#define	AMD553X_MFGPT1_C2_RSTEN	0x02000000
#define	AMD553X_MFGPT2_C2_RSTEN	0x04000000
#define	AMD553X_MFGPT3_C2_RSTEN	0x08000000
#define	AMD553X_MFGPT4_C2_RSTEN	0x10000000
#define	AMD553X_MFGPT5_C2_RSTEN	0x20000000
#define	AMD553X_MFGPT_SETUP	0x5140002b

/* SMB / IIC */
#define	MSR_LBAR_SMB		0x5140000b

/* GPIO */
#define	MSR_LBAR_GPIO		0x5140000c
#define	AMD553X_GPIO_NPINS	32
#define	AMD553X_GPIOH_OFFSET	0x80	/* high bank register offset */
#define	AMD553X_GPIO_OUT_VAL	0x00	/* output value */
#define	AMD553X_GPIO_OUT_EN	0x04	/* output enable */
#define	AMD553X_GPIO_OD_EN	0x08	/* open-drain enable */
#define AMD553X_GPIO_OUT_INVRT_EN 0x0c	/* invert output enable*/
#define	AMD553X_GPIO_PU_EN	0x18	/* pull-up enable */
#define	AMD553X_GPIO_PD_EN	0x1c	/* pull-down enable */
#define	AMD553X_GPIO_IN_EN	0x20	/* input enable */
#define AMD553X_GPIO_IN_INVRT_EN 0x24	/* invert input */
#define	AMD553X_GPIO_IN_FLTR_EN	0x28	/* filter enable */
#define	AMD553X_GPIO_IN_EVNTCNT_EN	0x2c	/* event counter enable */
#define	AMD553X_GPIO_READ_BACK	0x30	/* read back value */
#define	AMD553X_GPIO_EVNT_EN	0x38	/* event enable */
#define	AMD553X_GPIO_LOCK_EN	0x3c	/* lock enable */
#define	AMD553X_GPIO_IN_PE_EN	0x40	/* input positive edge enable */
#define	AMD553X_GPIO_IN_NE_EN	0x44	/* input negative edge enable */
#define	AMD553X_GPIO_IN_NE_STS	0x48	/* input negative edge status */
#define	AMD553X_GPIO_IN_PE_STS	0x4c	/* input positive edge status */

#endif /* _IC_GCSCPCIBREG_H_ */

File Added: src/sys/dev/ic/gcscpcibvar.h
/* $NetBSD: gcscpcibvar.h,v 1.1 2011/08/27 12:47:49 bouyer Exp $ */
/* $OpenBSD: gcscpcib.c,v 1.6 2007/11/17 17:02:47 mbalmer Exp $	*/

/*
 * Copyright (c) 2008 Yojiro UO <yuo@nui.org>
 * Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
 * Copyright (c) 2007 Michael Shalayeff
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

struct gcscpcib_softc {
	struct timecounter	sc_timecounter;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;

	/* Watchdog Timer */
	struct sysmon_wdog	sc_smw;
	int			sc_wdt_mfgpt;

	/* GPIO interface */
	bus_space_tag_t		sc_gpio_iot;
	bus_space_handle_t	sc_gpio_ioh;
	struct gpio_chipset_tag	sc_gpio_gc;
	gpio_pin_t		sc_gpio_pins[AMD553X_GPIO_NPINS];

#if 0
	/* SMbus/i2c interface */ 
	bus_space_tag_t		sc_smbus_iot;
        bus_space_handle_t	sc_smbus_ioh;
	i2c_addr_t		sc_smbus_slaveaddr; /* address of smbus slave */
	struct i2c_controller	sc_i2c;		/* i2c controller info */
	krwlock_t		sc_smbus_rwlock;
#endif
};

void gcscpcib_attach(device_t, struct gcscpcib_softc *, bus_space_tag_t);

uint64_t gcsc_rdmsr(uint);
void     gcsc_wrmsr(uint, uint64_t);