Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Jan 2010 12:53:38 -0800
From:      Weongyo Jeong <weongyo.jeong@gmail.com>
To:        current@freebsd.org
Cc:        imp@freebsd.org
Subject:   HEADUP: major update of siba(4) - again
Message-ID:  <20100127205338.GA28399@weongyo>

next in thread | raw e-mail | index | archive | help

--YiEDa0DAkWCtVeE4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Tue, Jan 12, 2010 at 01:33:29PM -0800, Weongyo Jeong wrote:
> Hello,
> 
> As someone know I posted a new ssb(4) driver to support bwn(4) driver
> I'd written some weeks ago and gavin@ told me that there's a almost
> same-purpose driver called siba(4) that could be merged into one with
> ssb(4).
> 
> As a result I made a patch here:
> 
>       http://people.freebsd.org/~weongyo/patch_siba_20100112.diff
> 
> The changes are as follows:
> 
>   - This patch is focused to support Broadcom Wireless NICs so major
>     consumer would be bwn(4) currently.
>   - could break backward compatibility of siba(4).  But I could not
>     find consumers of siba(4), Makefile to build or examples in the
>     tree.
>   - adds a siba(4) man page that it'll be reviewed before committing.
> 
> If no objections, I'll commit it by end of this week.

I made an another patch not to break the backward compatibility of
siba(4).

	http://people.freebsd.org/~weongyo/patch_siba_20100127.diff

This version is tested just on MIPS cross-compilation due to lack of H/W
but I expect that the patch doesn't touch any original siba(4) logics.

By design reasons I made a siba_bwn bridge module whose parent device is
PCI that placed at sys/modules/siba_bwn/Makefile.

I believe that with this patch I solved a objection until now so If no
more objections by end of this week, I'll commit it into HEAD.

regards,
Weongyo Jeong


--YiEDa0DAkWCtVeE4
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="patch_siba_20100127.diff"

Index: siba.c
===================================================================
--- siba.c	(revision 202983)
+++ siba.c	(working copy)
@@ -37,9 +37,9 @@
 
 #include <machine/bus.h>
 
-#include <dev/siba/sibavar.h>
-#include <dev/siba/sibareg.h>
 #include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/sibavar.h>
 
 /*
  * TODO: De-mipsify this code.
@@ -77,7 +77,7 @@
 	  "MIPS core" },
 	{ SIBA_VID_BROADCOM,	SIBA_DEVID_ETHERNET,	SIBA_REV_ANY,
 	  "Ethernet core" },
-	{ SIBA_VID_BROADCOM,	SIBA_DEVID_USB,		SIBA_REV_ANY,
+	{ SIBA_VID_BROADCOM,	SIBA_DEVID_USB11_HOSTDEV, SIBA_REV_ANY,
 	  "USB host controller" },
 	{ SIBA_VID_BROADCOM,	SIBA_DEVID_IPSEC,	SIBA_REV_ANY,
 	  "IPSEC accelerator" },
@@ -103,7 +103,6 @@
 static struct resource_list *
 		siba_get_reslist(device_t, device_t);
 static uint8_t	siba_getirq(uint16_t);
-static uint8_t	siba_getncores(uint16_t);
 static int	siba_print_all_resources(device_t dev);
 static int	siba_print_child(device_t, device_t);
 static int	siba_probe(device_t);
@@ -112,32 +111,9 @@
 static struct siba_devinfo *
 		siba_setup_devinfo(device_t, uint8_t);
 int		siba_write_ivar(device_t, device_t, int, uintptr_t);
+uint8_t		siba_getncores(device_t, uint16_t);
 
 /*
- * Earlier ChipCommon revisions have hardcoded number of cores
- * present dependent on the ChipCommon ID.
- */
-static uint8_t
-siba_getncores(uint16_t ccid)
-{
-	uint8_t ncores;
-
-	switch (ccid) {
-	case SIBA_CCID_SENTRY5:
-		ncores = 7;
-		break;
-	case SIBA_CCID_BCM4710:
-	case SIBA_CCID_BCM4704:
-		ncores = 9;
-		break;
-	default:
-		ncores = 0;
-	}
-
-	return (ncores);
-}
-
-/*
  * On the Sentry5, the system bus IRQs are the same as the
  * MIPS IRQs. Particular cores are hardwired to certain IRQ lines.
  */
@@ -156,7 +132,7 @@
 	case SIBA_DEVID_IPSEC:
 		irq = 2;
 		break;
-	case SIBA_DEVID_USB:
+	case SIBA_DEVID_USB11_HOSTDEV:
 		irq = 3;
 		break;
 	case SIBA_DEVID_PCI:
@@ -188,7 +164,7 @@
 	uint16_t ccid;
 	int rid;
 
-	sc->sc_dev = dev;
+	sc->siba_dev = dev;
 
 	//rman_debug = 1;	/* XXX */
 
@@ -197,24 +173,24 @@
 	 * was compiled with.
 	 */
 	rid = MIPS_MEM_RID;
-	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	sc->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
 	    RF_ACTIVE);
-	if (sc->sc_mem == NULL) {
+	if (sc->siba_mem_res == NULL) {
 		device_printf(dev, "unable to allocate probe aperture\n");
 		return (ENXIO);
 	}
-	sc->sc_bt = rman_get_bustag(sc->sc_mem);
-	sc->sc_bh = rman_get_bushandle(sc->sc_mem);
-	sc->sc_maddr = rman_get_start(sc->sc_mem);
-	sc->sc_msize = rman_get_size(sc->sc_mem);
+	sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res);
+	sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res);
+	sc->siba_maddr = rman_get_start(sc->siba_mem_res);
+	sc->siba_msize = rman_get_size(sc->siba_mem_res);
 
 	if (siba_debug) {
 		device_printf(dev, "start %08x len %08x\n",
-		    sc->sc_maddr, sc->sc_msize);
+		    sc->siba_maddr, sc->siba_msize);
 	}
 
-	idlo = siba_read_4(sc, 0, SIBA_CORE_IDLO);
-	idhi = siba_read_4(sc, 0, SIBA_CORE_IDHI);
+	idlo = siba_mips_read_4(sc, 0, SIBA_IDLOW);
+	idhi = siba_mips_read_4(sc, 0, SIBA_IDHIGH);
 	ccid = ((idhi & 0x8ff0) >> 4);
 	if (siba_debug) {
 		device_printf(dev, "idlo = %08x\n", idlo);
@@ -256,7 +232,7 @@
 	uint16_t cc_id;
 	uint16_t cc_rev;
 
-	ccidreg = siba_read_4(sc, 0, SIBA_CC_CCID);
+	ccidreg = siba_mips_read_4(sc, 0, SIBA_CC_CHIPID);
 	cc_id = (ccidreg & SIBA_CC_IDMASK);
 	cc_rev = (ccidreg & SIBA_CC_REVMASK) >> SIBA_CC_REVSHIFT;
 	if (siba_debug) {
@@ -264,9 +240,9 @@
 		     ccidreg, cc_id, cc_rev);
 	}
 
-	sc->sc_ncores = siba_getncores(cc_id);
+	sc->siba_ncores = siba_getncores(dev, cc_id);
 	if (siba_debug) {
-		device_printf(dev, "%d cores detected.\n", sc->sc_ncores);
+		device_printf(dev, "%d cores detected.\n", sc->siba_ncores);
 	}
 
 	/*
@@ -275,36 +251,38 @@
 	 */
 	rid = MIPS_MEM_RID;
 	int result;
-	result = bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->sc_mem);
+	result = bus_release_resource(dev, SYS_RES_MEMORY, rid,
+	    sc->siba_mem_res);
 	if (result != 0) {
 		device_printf(dev, "error %d releasing resource\n", result);
 		return (ENXIO);
 	}
 
 	uint32_t total;
-	total = sc->sc_ncores * SIBA_CORE_LEN;
+	total = sc->siba_ncores * SIBA_CORE_LEN;
 
 	/* XXX Don't allocate the entire window until we
 	 * enumerate the bus. Once the bus has been enumerated,
 	 * and instance variables/children instantiated + populated,
 	 * release the resource so children may attach.
 	 */
-	sc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
-	    sc->sc_maddr, sc->sc_maddr + total - 1, total, RF_ACTIVE);
-	if (sc->sc_mem == NULL) {
+	sc->siba_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+	    sc->siba_maddr, sc->siba_maddr + total - 1, total, RF_ACTIVE);
+	if (sc->siba_mem_res == NULL) {
 		device_printf(dev, "unable to allocate entire aperture\n");
 		return (ENXIO);
 	}
-	sc->sc_bt = rman_get_bustag(sc->sc_mem);
-	sc->sc_bh = rman_get_bushandle(sc->sc_mem);
-	sc->sc_maddr = rman_get_start(sc->sc_mem);
-	sc->sc_msize = rman_get_size(sc->sc_mem);
+	sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res);
+	sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res);
+	sc->siba_maddr = rman_get_start(sc->siba_mem_res);
+	sc->siba_msize = rman_get_size(sc->siba_mem_res);
 
 	if (siba_debug) {
 		device_printf(dev, "after remapping: start %08x len %08x\n",
-		    sc->sc_maddr, sc->sc_msize);
+		    sc->siba_maddr, sc->siba_msize);
 	}
-	bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->sc_maddr, sc->sc_msize);
+	bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->siba_maddr,
+	    sc->siba_msize);
 
 	/*
 	 * We need a manager for the space we claim on nexus to
@@ -313,12 +291,13 @@
 	 * otherwise it may be claimed elsewhere.
 	 * XXX move to softc
 	 */
-	mem_rman.rm_start = sc->sc_maddr;
-	mem_rman.rm_end = sc->sc_maddr + sc->sc_msize - 1;
+	mem_rman.rm_start = sc->siba_maddr;
+	mem_rman.rm_end = sc->siba_maddr + sc->siba_msize - 1;
 	mem_rman.rm_type = RMAN_ARRAY;
 	mem_rman.rm_descr = "SiBa I/O memory addresses";
 	if (rman_init(&mem_rman) != 0 ||
-	    rman_manage_region(&mem_rman, mem_rman.rm_start, mem_rman.rm_end) != 0) {
+	    rman_manage_region(&mem_rman, mem_rman.rm_start,
+		mem_rman.rm_end) != 0) {
 		panic("%s: mem_rman", __func__);
 	}
 
@@ -344,7 +323,7 @@
 	 * NB: only one core may be mapped at any time if the siba bus
 	 * is the child of a PCI or PCMCIA bus.
 	 */
-	for (idx = 0; idx < sc->sc_ncores; idx++) {
+	for (idx = 0; idx < sc->siba_ncores; idx++) {
 		sdi = siba_setup_devinfo(dev, idx);
 		child = device_add_child(dev, NULL, -1);
 		if (child == NULL)
@@ -483,13 +462,14 @@
 	sdi = malloc(sizeof(*sdi), M_DEVBUF, M_WAITOK | M_ZERO);
 	resource_list_init(&sdi->sdi_rl);
 
-	idlo = siba_read_4(sc, idx, SIBA_CORE_IDLO);
-	idhi = siba_read_4(sc, idx, SIBA_CORE_IDHI);
+	idlo = siba_mips_read_4(sc, idx, SIBA_IDLOW);
+	idhi = siba_mips_read_4(sc, idx, SIBA_IDHIGH);
 
-	vendorid = (idhi & SIBA_IDHIGH_VC) >> SIBA_IDHIGH_VC_SHIFT;
+	vendorid = (idhi & SIBA_IDHIGH_VENDORMASK) >>
+	    SIBA_IDHIGH_VENDOR_SHIFT;
 	devid = ((idhi & 0x8ff0) >> 4);
-	rev = (idhi & SIBA_IDHIGH_RCLO);
-	rev |= (idhi & SIBA_IDHIGH_RCHI) >> SIBA_IDHIGH_RCHI_SHIFT;
+	rev = (idhi & SIBA_IDHIGH_REVLO);
+	rev |= (idhi & SIBA_IDHIGH_REVHI) >> SIBA_IDHIGH_REVHI_SHIFT;
 
 	sdi->sdi_vid = vendorid;
 	sdi->sdi_devid = devid;
@@ -500,7 +480,7 @@
 	/*
 	 * Determine memory window on bus and irq if one is needed.
 	 */
-	baseaddr = sc->sc_maddr + (idx * SIBA_CORE_LEN);
+	baseaddr = sc->siba_maddr + (idx * SIBA_CORE_LEN);
 	resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY,
 	    MIPS_MEM_RID, /* XXX */
 	    baseaddr, baseaddr + SIBA_CORE_LEN - 1, SIBA_CORE_LEN);
Index: sibareg.h
===================================================================
--- sibareg.h	(revision 202983)
+++ sibareg.h	(working copy)
@@ -34,40 +34,383 @@
 #ifndef _SIBA_SIBAREG_H_
 #define _SIBA_SIBAREG_H_
 
+#define	PCI_DEVICE_ID_BCM4401		0x4401
+#define	PCI_DEVICE_ID_BCM4401B0		0x4402
+#define	PCI_DEVICE_ID_BCM4401B1		0x170c
+#define	SIBA_PCIR_BAR			PCIR_BAR(0)
+#define	SIBA_CCID_BCM4710		0x4710
+#define	SIBA_CCID_BCM4704		0x4704
+#define	SIBA_CCID_SENTRY5		0x5365
+
+/*
+ * ChipCommon registers.
+ */
+#define	SIBA_CC_CHIPID			0x0000
+#define	SIBA_CC_IDMASK			0x0000ffff
+#define	SIBA_CC_ID(id)			(id & SIBA_CC_IDMASK)
+#define	SIBA_CC_REVMASK			0x000f0000
+#define	SIBA_CC_REVSHIFT		16
+#define	SIBA_CC_REV(id)							\
+	((id & SIBA_CC_REVMASK) >> SIBA_CC_REVSHIFT)
+#define	SIBA_CC_PKGMASK			0x00F00000
+#define	SIBA_CC_PKGSHIFT		20
+#define	SIBA_CC_PKG(id)							\
+	((id & SIBA_CC_PKGMASK) >> SIBA_CC_PKGSHIFT)
+#define	SIBA_CC_NCORESMASK		0x0F000000
+#define	SIBA_CC_NCORESSHIFT		24
+#define	SIBA_CC_NCORES(id)						\
+	((id & SIBA_CC_NCORESMASK) >> SIBA_CC_NCORESSHIFT)
+#define	SIBA_CC_CAPS			0x0004
+#define	SIBA_CC_CAPS_PWCTL		0x00040000
+#define	SIBA_CC_CAPS_PMU		0x10000000	/* PMU (rev >= 20) */
+#define	SIBA_CC_CHIPCTL			0x0028		/* rev >= 11 */
+#define	SIBA_CC_CHIPSTAT		0x002C		/* rev >= 11 */
+#define	SIBA_CC_BCAST_ADDR		0x0050		/* Broadcast Address */
+#define	SIBA_CC_BCAST_DATA		0x0054		/* Broadcast Data */
+#define	SIBA_CC_PLLONDELAY		0x00B0		/* Rev >= 4 only */
+#define	SIBA_CC_FREFSELDELAY		0x00B4		/* Rev >= 4 only */
+#define	SIBA_CC_CLKSLOW			0x00b8		/* 6 <= Rev <= 9 only */
+#define	SIBA_CC_CLKSLOW_SRC		0x00000007
+#define	SIBA_CC_CLKSLOW_SRC_CRYSTAL	0x00000001
+#define	SIBA_CC_CLKSLOW_FSLOW		0x00000800
+#define	SIBA_CC_CLKSLOW_IPLL		0x00001000
+#define	SIBA_CC_CLKSLOW_ENXTAL		0x00002000
+#define	SIBA_CC_CLKSYSCTL		0x00C0		/* Rev >= 3 only */
+#define	SIBA_CC_CLKCTLSTATUS		0x01e0
+#define	SIBA_CC_CLKCTLSTATUS_HT		0x00010000
+#define	SIBA_CC_UART0			0x0300		/* offset of UART0 */
+#define	SIBA_CC_UART1			0x0400		/* offset of UART1 */
+#define	SIBA_CC_PMUCTL			0x0600		/* PMU control */
+#define	SIBA_CC_PMUCTL_ILP		0xffff0000	/* mask */
+#define	SIBA_CC_PMUCTL_NOILP		0x00000200
+#define	SIBA_CC_PMUCTL_XF		0x0000007c	/* crystal freq */
+#define	SIBA_CC_PMUCTL_XF_VAL(id)	((id & 0x0000007c) >> 2)
+#define	SIBA_CC_PMUCAPS			0x0604
+#define	SIBA_CC_PMUCAPS_REV		0x000000ff
+#define	SIBA_CC_PMU_MINRES		0x0618
+#define	SIBA_CC_PMU_MAXRES		0x061c
+#define	SIBA_CC_PMU_TABSEL		0x0620
+#define	SIBA_CC_PMU_DEPMSK		0x0624
+#define	SIBA_CC_PMU_UPDNTM		0x0628
+#define	SIBA_CC_PLLCTL_ADDR		0x0660
+#define	SIBA_CC_PLLCTL_DATA		0x0664
+
+#define	SIBA_CC_PMU0_PLL0		0
+#define	SIBA_CC_PMU0_PLL0_PDIV_MSK	0x00000001
+#define	SIBA_CC_PMU0_PLL0_PDIV_FREQ	25000
+#define	SIBA_CC_PMU0_PLL1		1
+#define	SIBA_CC_PMU0_PLL1_IMSK		0xf0000000
+#define	SIBA_CC_PMU0_PLL1_FMSK		0x0fffff00
+#define	SIBA_CC_PMU0_PLL1_STOPMOD	0x00000040
+#define	SIBA_CC_PMU0_PLL2		2
+#define	SIBA_CC_PMU0_PLL2_IMSKHI	0x0000000f
+#define	SIBA_CC_PMU1_PLL0		0
+#define	SIBA_CC_PMU1_PLL0_P1DIV		0x00f00000
+#define	SIBA_CC_PMU1_PLL0_P2DIV		0x0f000000
+#define	SIBA_CC_PMU1_PLL2		2
+#define	SIBA_CC_PMU1_PLL2_NDIVMODE	0x000e0000
+#define	SIBA_CC_PMU1_PLL2_NDIVINT	0x1ff00000
+#define	SIBA_CC_PMU1_PLL3		3
+#define	SIBA_CC_PMU1_PLL3_NDIVFRAC	0x00ffffff
+#define	SIBA_CC_PMU1_PLL5		5
+#define	SIBA_CC_PMU1_PLL5_CLKDRV	0xffffff00
+
+#define	SIBA_CC_PMU0_DEFAULT_XTALFREQ	20000
+#define	SIBA_CC_PMU1_DEFAULT_FREQ	15360
+
+#define	SIBA_CC_PMU1_PLLTAB_ENTRY					\
+{									\
+	{ 12000,  1, 3, 22,  0x9, 0xffffef },				\
+	{ 13000,  2, 1,  6,  0xb, 0x483483 },				\
+	{ 14400,  3, 1, 10,  0xa, 0x1c71c7 },				\
+	{ 15360,  4, 1,  5,  0xb, 0x755555 },				\
+	{ 16200,  5, 1, 10,  0x5, 0x6e9e06 },				\
+	{ 16800,  6, 1, 10,  0x5, 0x3cf3cf },				\
+	{ 19200,  7, 1,  9,  0x5, 0x17b425 },				\
+	{ 19800,  8, 1, 11,  0x4, 0xa57eb },				\
+	{ 20000,  9, 1, 11,  0x4, 0 },					\
+	{ 24000, 10, 3, 11,  0xa, 0 },					\
+	{ 25000, 11, 5, 16,  0xb, 0 },					\
+	{ 26000, 12, 1,  2, 0x10, 0xec4ec4 },				\
+	{ 30000, 13, 3,  8,  0xb, 0 },					\
+	{ 38400, 14, 1,  5,  0x4, 0x955555 },				\
+	{ 40000, 15, 1,  2,  0xb, 0 }					\
+}
+
+#define	SIBA_CC_PMU0_PLLTAB_ENTRY					\
+{									\
+	{ 12000,  1, 73, 349525, }, { 13000,  2, 67, 725937, },		\
+	{ 14400,  3, 61, 116508, }, { 15360,  4, 57, 305834, },		\
+	{ 16200,  5, 54, 336579, }, { 16800,  6, 52, 399457, },		\
+	{ 19200,  7, 45, 873813, }, { 19800,  8, 44, 466033, },		\
+	{ 20000,  9, 44, 0,      }, { 25000, 10, 70, 419430, },		\
+	{ 26000, 11, 67, 725937, }, { 30000, 12, 58, 699050, },		\
+	{ 38400, 13, 45, 873813, }, { 40000, 14, 45, 0,      },		\
+}
+
+#define	SIBA_CC_PMU_4325_BURST		1
+#define	SIBA_CC_PMU_4325_CLBURST	3
+#define	SIBA_CC_PMU_4325_LN		10
+#define	SIBA_CC_PMU_4325_CRYSTAL	13
+#define	SIBA_CC_PMU_4325_RX_PWR		15
+#define	SIBA_CC_PMU_4325_TX_PWR		16
+#define	SIBA_CC_PMU_4325_LOGEN_PWR	18
+#define	SIBA_CC_PMU_4325_AFE_PWR	19
+#define	SIBA_CC_PMU_4325_BBPLL_PWR	20
+#define	SIBA_CC_PMU_4325_HT		21
+#define	SIBA_CC_PMU_4328_EXT_SWITCH_PWM	0
+#define	SIBA_CC_PMU_4328_BB_SWITCH_PWM	1
+#define	SIBA_CC_PMU_4328_BB_SWITCH_BURST	2
+#define	SIBA_CC_PMU_4328_BB_EXT_SWITCH_BURST	3
+#define	SIBA_CC_PMU_4328_ILP_REQUEST	4
+#define	SIBA_CC_PMU_4328_RADSWITCH_PWM	5	/* radio switch */
+#define	SIBA_CC_PMU_4328_RADSWITCH_BURST	6
+#define	SIBA_CC_PMU_4328_ROM_SWITCH	7
+#define	SIBA_CC_PMU_4328_PA_REF		8
+#define	SIBA_CC_PMU_4328_RADIO		9
+#define	SIBA_CC_PMU_4328_AFE		10
+#define	SIBA_CC_PMU_4328_PLL		11
+#define	SIBA_CC_PMU_4328_BG_FILTBYP	12
+#define	SIBA_CC_PMU_4328_TX_FILTBYP	13
+#define	SIBA_CC_PMU_4328_RX_FILTBYP	14
+#define	SIBA_CC_PMU_4328_CRYSTAL_PU	15
+#define	SIBA_CC_PMU_4328_CRYSTAL_EN	16
+#define	SIBA_CC_PMU_4328_BB_PLL_FILTBYP	17
+#define	SIBA_CC_PMU_4328_RF_PLL_FILTBYP	18
+#define	SIBA_CC_PMU_4328_BB_PLL_PU	19
+#define	SIBA_CC_PMU_5354_BB_PLL_PU	19
+
+#define	SIBA_CC_PMU_4325_RES_UPDOWN					\
+{									\
+	{ SIBA_CC_PMU_4325_CRYSTAL, 0x1501 }				\
+}
+
+#define	SIBA_CC_PMU_4325_RES_DEPEND					\
+{									\
+	{ SIBA_CC_PMU_4325_HT, SIBA_CC_PMU_DEP_ADD,			\
+	  ((1 << SIBA_CC_PMU_4325_RX_PWR) |				\
+	   (1 << SIBA_CC_PMU_4325_TX_PWR) |				\
+	   (1 << SIBA_CC_PMU_4325_LOGEN_PWR) |				\
+	   (1 << SIBA_CC_PMU_4325_AFE_PWR)) }				\
+}
+
+#define	SIBA_CC_PMU_4328_RES_UPDOWN					\
+{									\
+	{ SIBA_CC_PMU_4328_EXT_SWITCH_PWM, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_BB_SWITCH_PWM, 0x1f01 },			\
+	{ SIBA_CC_PMU_4328_BB_SWITCH_BURST, 0x010f },			\
+	{ SIBA_CC_PMU_4328_BB_EXT_SWITCH_BURST, 0x0101 },		\
+	{ SIBA_CC_PMU_4328_ILP_REQUEST, 0x0202 },			\
+	{ SIBA_CC_PMU_4328_RADSWITCH_PWM, 0x0f01 },			\
+	{ SIBA_CC_PMU_4328_RADSWITCH_BURST, 0x0f01 },			\
+	{ SIBA_CC_PMU_4328_ROM_SWITCH, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_PA_REF, 0x0f01 },				\
+	{ SIBA_CC_PMU_4328_RADIO, 0x0f01 },				\
+	{ SIBA_CC_PMU_4328_AFE, 0x0f01 },				\
+	{ SIBA_CC_PMU_4328_PLL, 0x0f01 },				\
+	{ SIBA_CC_PMU_4328_BG_FILTBYP, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_TX_FILTBYP, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_RX_FILTBYP, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_CRYSTAL_PU, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_CRYSTAL_EN, 0xa001 },			\
+	{ SIBA_CC_PMU_4328_BB_PLL_FILTBYP, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_RF_PLL_FILTBYP, 0x0101 },			\
+	{ SIBA_CC_PMU_4328_BB_PLL_PU, 0x0701 },				\
+}
+
+#define	SIBA_CC_PMU_4328_RES_DEPEND					\
+{									\
+	{ SIBA_CC_PMU_4328_ILP_REQUEST, SIBA_CC_PMU_DEP_SET,		\
+	  ((1 << SIBA_CC_PMU_4328_EXT_SWITCH_PWM) |			\
+	   (1 << SIBA_CC_PMU_4328_BB_SWITCH_PWM)) },			\
+}
+
+#define	SIBA_CC_CHST_4325_PMUTOP_2B	0x00000200
+
+#define	SIBA_BAR0			0x80
+#define	SIBA_IRQMASK			0x94
+#define	SIBA_GPIO_IN			0xb0
+#define	SIBA_GPIO_OUT			0xb4
+#define	SIBA_GPIO_OUT_EN		0xb8
+#define	SIBA_GPIO_CRYSTAL		0x40
+#define	SIBA_GPIO_PLL			0x80
+
+#define	SIBA_REGWIN(x)							\
+	(SIBA_ENUM_START + ((x) * SIBA_CORE_LEN))
 #define SIBA_CORE_LEN		0x00001000	/* Size of cfg per core */
 #define SIBA_CFG_END		0x00010000	/* Upper bound of cfg space */
 #define SIBA_MAX_CORES		(SIBA_CFG_END/SIBA_CORE_LEN)	/* #max cores */
+#define	SIBA_ENUM_START			0x18000000U
+#define	SIBA_ENUM_END			0x18010000U
 
-/* offset of high ID register */
-#define SIBA_CORE_IDLO		0x00000ff8
-#define SIBA_CORE_IDHI		0x00000ffc
+#define	SIBA_DMA_TRANSLATION_MASK	0xc0000000
 
-/*
- * Offsets of ChipCommon core registers.
- * XXX: move to siba_cc
- */
-#define SIBA_CC_UART0	0x00000300	/* offset of UART0 */
-#define SIBA_CC_UART1	0x00000400	/* offset of UART1 */
+#define	SIBA_PCI_DMA			0x40000000U
+#define	SIBA_TPS			0x0f18
+#define	SIBA_TPS_BPFLAG			0x0000003f
+#define	SIBA_IAS			0x0f90     /* Initiator Agent State */
+#define	SIBA_IAS_INBAND_ERR		0x00020000
+#define	SIBA_IAS_TIMEOUT		0x00040000
+#define	SIBA_INTR_MASK			0x0f94
+#define	SIBA_TGSLOW			0x0f98
+#define	SIBA_TGSLOW_RESET		0x00000001	/* target state low */
+#define	SIBA_TGSLOW_REJECT_22		0x00000002
+#define	SIBA_TGSLOW_REJECT_23		0x00000004
+#define	SIBA_TGSLOW_CLOCK		0x00010000
+#define	SIBA_TGSLOW_FGC			0x00020000
+#define	SIBA_TGSHIGH			0x0f9c
+#define	SIBA_TGSHIGH_SERR		0x00000001
+#define	SIBA_TGSHIGH_BUSY		0x00000004
+#define	SIBA_TGSHIGH_DMA64		0x10000000
+#define	SIBA_IMCFGLO			0x0fa8
+#define	SIBA_IMCFGLO_SERTO		0x00000007
+#define	SIBA_IMCFGLO_REQTO		0x00000070
+#define	SIBA_IDLOW			0x0ff8
+#define	SIBA_IDLOW_SSBREV		0xf0000000
+#define	SIBA_IDLOW_SSBREV_22		0x00000000
+#define	SIBA_IDLOW_SSBREV_23		0x10000000
+#define	SIBA_IDLOW_SSBREV_24		0x40000000
+#define	SIBA_IDLOW_SSBREV_25		0x50000000
+#define	SIBA_IDLOW_SSBREV_26		0x60000000
+#define	SIBA_IDLOW_SSBREV_27		0x70000000
+#define	SIBA_IDHIGH			0x0ffc
+#define	SIBA_IDHIGH_CORECODEMASK	0x00008FF0 /* Core Code */
+#define	SIBA_IDHIGH_CORECODE_SHIFT	4
+#define	SIBA_IDHIGH_CORECODE(id)					\
+	((id & SIBA_IDHIGH_CORECODEMASK) >> SIBA_IDHIGH_CORECODE_SHIFT)
+/* Revision Code (low part) */
+#define	SIBA_IDHIGH_REVLO		0x0000000f
+/* Revision Code (high part) */
+#define	SIBA_IDHIGH_REVHI		0x00007000
+#define	SIBA_IDHIGH_REVHI_SHIFT	8
+#define	SIBA_IDHIGH_REV(id)						\
+	((id & SIBA_IDHIGH_REVLO) | ((id & SIBA_IDHIGH_REVHI) >>	\
+	    SIBA_IDHIGH_REVHI_SHIFT))
+#define	SIBA_IDHIGH_VENDORMASK		0xFFFF0000 /* Vendor Code */
+#define	SIBA_IDHIGH_VENDOR_SHIFT	16
+#define	SIBA_IDHIGH_VENDOR(id)						\
+	((id & SIBA_IDHIGH_VENDORMASK) >> SIBA_IDHIGH_VENDOR_SHIFT)
 
-#define SIBA_CC_CCID 0x0000
-#define  SIBA_CC_IDMASK 0x0000FFFF
-#define  SIBA_CC_REVMASK 0x000F0000
-#define  SIBA_CC_REVSHIFT 16
-#define  SIBA_CC_PACKMASK 0x00F00000
-#define  SIBA_CC_PACKSHIFT 20
-#define  SIBA_CC_NRCORESMASK 0x0F000000
-#define  SIBA_CC_NRCORESSHIFT 24
+#define	SIBA_SPROMSIZE_R123		64
+#define	SIBA_SPROMSIZE_R4		220
+#define	SIBA_SPROM_BASE			0x1000
+#define	SIBA_SPROM_REV_CRC		0xff00
+#define	SIBA_SPROM1_MAC_80211BG		0x1048
+#define	SIBA_SPROM1_MAC_ETH		0x104e
+#define	SIBA_SPROM1_MAC_80211A		0x1054
+#define	SIBA_SPROM1_ETHPHY		0x105a
+#define	SIBA_SPROM1_ETHPHY_MII_ETH0	0x001f
+#define	SIBA_SPROM1_ETHPHY_MII_ETH1	0x03e0
+#define	SIBA_SPROM1_ETHPHY_MDIO_ETH0	(1 << 14)
+#define	SIBA_SPROM1_ETHPHY_MDIO_ETH1	(1 << 15)
+#define	SIBA_SPROM1_BOARDINFO		0x105c
+#define	SIBA_SPROM1_BOARDINFO_BREV	0x00ff
+#define	SIBA_SPROM1_BOARDINFO_CCODE	0x0f00
+#define	SIBA_SPROM1_BOARDINFO_ANTBG	0x3000
+#define	SIBA_SPROM1_BOARDINFO_ANTA	0xc000
+#define	SIBA_SPROM1_PA0B0		0x105e
+#define	SIBA_SPROM1_PA0B1		0x1060
+#define	SIBA_SPROM1_PA0B2		0x1062
+#define	SIBA_SPROM1_GPIOA		0x1064
+#define	SIBA_SPROM1_GPIOA_P0		0x00ff
+#define	SIBA_SPROM1_GPIOA_P1		0xff00
+#define	SIBA_SPROM1_GPIOB		0x1066
+#define	SIBA_SPROM1_GPIOB_P2		0x00ff
+#define	SIBA_SPROM1_GPIOB_P3		0xff00
+#define	SIBA_SPROM1_MAXPWR		0x1068
+#define	SIBA_SPROM1_MAXPWR_BG		0x00ff
+#define	SIBA_SPROM1_MAXPWR_A		0xff00
+#define	SIBA_SPROM1_PA1B0		0x106a
+#define	SIBA_SPROM1_PA1B1		0x106c
+#define	SIBA_SPROM1_PA1B2		0x106e
+#define	SIBA_SPROM1_TSSI		0x1070
+#define	SIBA_SPROM1_TSSI_BG		0x00ff
+#define	SIBA_SPROM1_TSSI_A		0xff00
+#define	SIBA_SPROM1_BFLOW		0x1072
+#define	SIBA_SPROM1_AGAIN		0x1074
+#define	SIBA_SPROM1_AGAIN_BG		0x00ff
+#define	SIBA_SPROM1_AGAIN_A		0xff00
+#define	SIBA_SPROM2_BFHIGH		0x1038
+#define	SIBA_SPROM3_MAC_80211BG		0x104a
+#define	SIBA_SPROM4_MAC_80211BG		0x104c
+#define	SIBA_SPROM4_ETHPHY		0x105a
+#define	SIBA_SPROM4_ETHPHY_ET0A		0x001f
+#define	SIBA_SPROM4_ETHPHY_ET1A		0x03e0
+#define	SIBA_SPROM4_CCODE		0x1052
+#define	SIBA_SPROM4_ANTAVAIL		0x105d
+#define	SIBA_SPROM4_ANTAVAIL_A		0x00ff
+#define	SIBA_SPROM4_ANTAVAIL_BG		0xff00
+#define	SIBA_SPROM4_BFLOW		0x1044
+#define	SIBA_SPROM4_AGAIN01		0x105e
+#define	SIBA_SPROM4_AGAIN0		0x00ff
+#define	SIBA_SPROM4_AGAIN1		0xff00
+#define	SIBA_SPROM4_AGAIN23		0x1060
+#define	SIBA_SPROM4_AGAIN2		0x00ff
+#define	SIBA_SPROM4_AGAIN3		0xff00
+#define	SIBA_SPROM4_BFHIGH		0x1046
+#define	SIBA_SPROM4_MAXP_BG		0x1080
+#define	SIBA_SPROM4_MAXP_BG_MASK	0x00ff
+#define	SIBA_SPROM4_TSSI_BG		0xff00
+#define	SIBA_SPROM4_MAXP_A		0x108a
+#define	SIBA_SPROM4_MAXP_A_MASK		0x00ff
+#define	SIBA_SPROM4_TSSI_A		0xff00
+#define	SIBA_SPROM4_GPIOA		0x1056
+#define	SIBA_SPROM4_GPIOA_P0		0x00ff
+#define	SIBA_SPROM4_GPIOA_P1		0xff00
+#define	SIBA_SPROM4_GPIOB		0x1058
+#define	SIBA_SPROM4_GPIOB_P2		0x00ff
+#define	SIBA_SPROM4_GPIOB_P3		0xff00
+#define	SIBA_SPROM5_BFLOW		0x104a
+#define	SIBA_SPROM5_BFHIGH		0x104c
+#define	SIBA_SPROM5_MAC_80211BG		0x1052
+#define	SIBA_SPROM5_CCODE		0x1044
+#define	SIBA_SPROM5_GPIOA		0x1076
+#define	SIBA_SPROM5_GPIOA_P0		0x00ff
+#define	SIBA_SPROM5_GPIOA_P1		0xff00
+#define	SIBA_SPROM5_GPIOB		0x1078
+#define	SIBA_SPROM5_GPIOB_P2		0x00ff
+#define	SIBA_SPROM5_GPIOB_P3		0xff00
+#define	SIBA_SPROM8_BFLOW		0x1084
+#define	SIBA_SPROM8_BFHIGH		0x1086
+#define	SIBA_SPROM8_CCODE		0x1092
+#define	SIBA_SPROM8_ANTAVAIL		0x109c
+#define	SIBA_SPROM8_ANTAVAIL_A		0xff00
+#define	SIBA_SPROM8_ANTAVAIL_BG		0x00ff
+#define	SIBA_SPROM8_AGAIN01		0x109e
+#define	SIBA_SPROM8_AGAIN0		0x00ff
+#define	SIBA_SPROM8_AGAIN1		0xff00
+#define	SIBA_SPROM8_AGAIN23		0x10a0
+#define	SIBA_SPROM8_AGAIN2		0x00ff
+#define	SIBA_SPROM8_AGAIN3		0xff00
+#define	SIBA_SPROM8_GPIOA		0x1096
+#define	SIBA_SPROM8_GPIOA_P0		0x00ff
+#define	SIBA_SPROM8_GPIOA_P1		0xff00
+#define	SIBA_SPROM8_GPIOB		0x1098
+#define	SIBA_SPROM8_GPIOB_P2		0x00ff
+#define	SIBA_SPROM8_GPIOB_P3		0xff00
+#define	SIBA_SPROM8_MAXP_BG		0x10c0
+#define	SIBA_SPROM8_MAXP_BG_MASK	0x00ff
+#define	SIBA_SPROM8_TSSI_BG		0xff00
+#define	SIBA_SPROM8_MAXP_A		0x10c8
+#define	SIBA_SPROM8_MAXP_A_MASK		0x00ff
+#define	SIBA_SPROM8_TSSI_A		0xff00
 
-#define  SIBA_IDHIGH_RCLO	0x0000000F /* Revision Code (low part) */
-#define  SIBA_IDHIGH_CC		0x00008FF0 /* Core Code */
-#define  SIBA_IDHIGH_CC_SHIFT	4
-#define  SIBA_IDHIGH_RCHI	0x00007000 /* Revision Code (high part) */
-#define  SIBA_IDHIGH_RCHI_SHIFT	8
-#define  SIBA_IDHIGH_VC		0xFFFF0000 /* Vendor Code */
-#define  SIBA_IDHIGH_VC_SHIFT	16
+#define	SIBA_BOARDVENDOR_DELL		0x1028
+#define	SIBA_BOARDVENDOR_BCM		0x14e4
+#define	SIBA_BOARD_BCM4309G		0x0421
+#define	SIBA_BOARD_MP4318		0x044a
+#define	SIBA_BOARD_BU4306		0x0416
+#define	SIBA_BOARD_BU4309		0x040a
 
-#define SIBA_CCID_BCM4710	0x4710
-#define SIBA_CCID_BCM4704	0x4704
-#define SIBA_CCID_SENTRY5	0x5365
+#define	SIBA_PCICORE_BCAST_ADDR		SIBA_CC_BCAST_ADDR
+#define	SIBA_PCICORE_BCAST_DATA		SIBA_CC_BCAST_DATA
+#define	SIBA_PCICORE_SBTOPCI0		0x0100
+#define	SIBA_PCICORE_SBTOPCI1		0x0104
+#define	SIBA_PCICORE_SBTOPCI2		0x0108
+#define	SIBA_PCICORE_MDIO_CTL		0x0128
+#define	SIBA_PCICORE_MDIO_DATA		0x012c
+#define	SIBA_PCICORE_SBTOPCI_PREF	0x00000004
+#define	SIBA_PCICORE_SBTOPCI_BURST	0x00000008
+#define	SIBA_PCICORE_SBTOPCI_MRM	0x00000020
 
 #endif /* _SIBA_SIBAREG_H_ */
Index: siba_ids.h
===================================================================
--- siba_ids.h	(revision 202983)
+++ siba_ids.h	(working copy)
@@ -39,23 +39,45 @@
 	uint8_t		 sd_rev;
 	char		*sd_desc;
 };
+#define	SIBA_DEV(_vendor, _cid, _rev, _msg)			\
+	{ SIBA_VID_##_vendor, SIBA_DEVID_##_cid, _rev, _msg }
 
 /*
  * Device IDs
  */
-#define SIBA_DEVID_ANY		0xffff
-#define SIBA_DEVID_CHIPCOMMON	0x0800
-#define SIBA_DEVID_INSIDELINE	0x0801
-#define SIBA_DEVID_SDRAM	0x0803
-#define SIBA_DEVID_PCI		0x0804
-#define SIBA_DEVID_MIPS		0x0805
-#define SIBA_DEVID_ETHERNET	0x0806
-#define SIBA_DEVID_MODEM	0x0807
-#define SIBA_DEVID_USB		0x0808
-#define SIBA_DEVID_IPSEC	0x080b
-#define SIBA_DEVID_SDRAMDDR	0x080f
-#define SIBA_DEVID_EXTIF	0x0811
-#define SIBA_DEVID_MIPS_3302	0x0816
+#define SIBA_DEVID_ANY			0xffff
+#define	SIBA_DEVID_CHIPCOMMON		0x800
+#define	SIBA_DEVID_ILINE20		0x801
+#define	SIBA_DEVID_SDRAM		0x803
+#define	SIBA_DEVID_PCI			0x804
+#define	SIBA_DEVID_MIPS			0x805
+#define	SIBA_DEVID_ETHERNET		0x806
+#define	SIBA_DEVID_MODEM		0x807
+#define	SIBA_DEVID_USB11_HOSTDEV	0x808
+#define	SIBA_DEVID_ADSL			0x809
+#define	SIBA_DEVID_ILINE100		0x80a
+#define	SIBA_DEVID_IPSEC		0x80b
+#define	SIBA_DEVID_PCMCIA		0x80d
+#define	SIBA_DEVID_INTERNAL_MEM		0x80e
+#define	SIBA_DEVID_SDRAMDDR		0x80f
+#define	SIBA_DEVID_EXTIF		0x811
+#define	SIBA_DEVID_80211		0x812
+#define	SIBA_DEVID_MIPS_3302		0x816
+#define	SIBA_DEVID_USB11_HOST		0x817
+#define	SIBA_DEVID_USB11_DEV		0x818
+#define	SIBA_DEVID_USB20_HOST		0x819
+#define	SIBA_DEVID_USB20_DEV		0x81a
+#define	SIBA_DEVID_SDIO_HOST		0x81b
+#define	SIBA_DEVID_ROBOSWITCH		0x81c
+#define	SIBA_DEVID_PARA_ATA		0x81d
+#define	SIBA_DEVID_SATA_XORDMA		0x81e
+#define	SIBA_DEVID_ETHERNET_GBIT	0x81f
+#define	SIBA_DEVID_PCIE			0x820
+#define	SIBA_DEVID_MIMO_PHY		0x821
+#define	SIBA_DEVID_SRAM_CTRLR		0x822
+#define	SIBA_DEVID_MINI_MACPHY		0x823
+#define	SIBA_DEVID_ARM_1176		0x824
+#define	SIBA_DEVID_ARM_7TDMI		0x825
 
 /*
  * Vendor IDs
Index: siba_cc.c
===================================================================
--- siba_cc.c	(revision 202983)
+++ siba_cc.c	(working copy)
@@ -55,9 +55,9 @@
 
 #include <machine/bus.h>
 
+#include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
 #include <dev/siba/sibavar.h>
-#include <dev/siba/sibareg.h>
-#include <dev/siba/siba_ids.h>
 
 static int	siba_cc_attach(device_t);
 static int	siba_cc_probe(device_t);
Index: siba_bwn.c
===================================================================
--- siba_bwn.c	(revision 0)
+++ siba_bwn.c	(revision 0)
@@ -0,0 +1,366 @@
+/*-
+ * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Sonics Silicon Backplane front-end for bwn(4).
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/sibavar.h>
+
+/*
+ * PCI glue.
+ */
+
+struct siba_bwn_softc {
+	/* Child driver using MSI. */
+	device_t			ssc_msi_child;
+	struct siba_softc		ssc_siba;
+};
+
+#define	BS_BAR				0x10
+#define	PCI_VENDOR_BROADCOM		0x14e4
+#define	N(a)				(sizeof(a) / sizeof(a[0]))
+
+static const struct siba_dev {
+	uint16_t	vid;
+	uint16_t	did;
+	const char	*desc;
+} siba_devices[] = {
+	{ PCI_VENDOR_BROADCOM, 0x4301, "Broadcom BCM4301 802.11b Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4306, "Unknown" },
+	{ PCI_VENDOR_BROADCOM, 0x4307, "Broadcom BCM4307 802.11b Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4311, "Broadcom BCM4311 802.11b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4312,
+	  "Broadcom BCM4312 802.11a/b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4315, "Broadcom BCM4312 802.11b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4318, "Broadcom BCM4318 802.11b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4319,
+	  "Broadcom BCM4318 802.11a/b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4320, "Broadcom BCM4306 802.11b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4321, "Broadcom BCM4306 802.11a Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4324,
+	  "Broadcom BCM4309 802.11a/b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4325, "Broadcom BCM4306 802.11b/g Wireless" },
+	{ PCI_VENDOR_BROADCOM, 0x4328, "Unknown" },
+	{ PCI_VENDOR_BROADCOM, 0x4329, "Unknown" },
+	{ PCI_VENDOR_BROADCOM, 0x432b, "Unknown" }
+};
+
+device_t	siba_add_child(device_t, struct siba_softc *, int, const char *,
+		    int);
+int		siba_core_attach(struct siba_softc *);
+int		siba_core_detach(struct siba_softc *);
+int		siba_core_suspend(struct siba_softc *);
+int		siba_core_resume(struct siba_softc *);
+
+static int
+siba_bwn_probe(device_t dev)
+{
+	int i;
+	uint16_t did, vid;
+
+	did = pci_get_device(dev);
+	vid = pci_get_vendor(dev);
+
+	for (i = 0; i < N(siba_devices); i++) {
+		if (siba_devices[i].did == did && siba_devices[i].vid == vid) {
+			device_set_desc(dev, siba_devices[i].desc);
+			return (BUS_PROBE_DEFAULT);
+		}
+	}
+	return (ENXIO);
+}
+
+static int
+siba_bwn_attach(device_t dev)
+{
+	struct siba_bwn_softc *ssc = device_get_softc(dev);
+	struct siba_softc *siba = &ssc->ssc_siba;
+
+	siba->siba_dev = dev;
+	siba->siba_type = SIBA_TYPE_PCI;
+
+	/*
+	 * Enable bus mastering.
+	 */
+	pci_enable_busmaster(dev);
+
+	/* 
+	 * Setup memory-mapping of PCI registers.
+	 */
+	siba->siba_mem_rid = SIBA_PCIR_BAR;
+	siba->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+		&siba->siba_mem_rid, RF_ACTIVE);
+	if (siba->siba_mem_res == NULL) {
+		device_printf(dev, "cannot map register space\n");
+		return (ENXIO);
+	}
+	siba->siba_mem_bt = rman_get_bustag(siba->siba_mem_res);
+	siba->siba_mem_bh = rman_get_bushandle(siba->siba_mem_res);
+
+	/* Get more PCI information */
+	siba->siba_pci_did = pci_get_device(dev);
+	siba->siba_pci_vid = pci_get_vendor(dev);
+	siba->siba_pci_subvid = pci_get_subvendor(dev);
+	siba->siba_pci_subdid = pci_get_subdevice(dev);
+
+	return (siba_core_attach(siba));
+}
+
+static int
+siba_bwn_detach(device_t dev)
+{
+	struct siba_bwn_softc *ssc = device_get_softc(dev);
+	struct siba_softc *siba = &ssc->ssc_siba;
+
+	/* check if device was removed */
+	siba->siba_invalid = !bus_child_present(dev);
+
+	pci_disable_busmaster(dev);
+	bus_generic_detach(dev);
+	siba_core_detach(siba);
+
+	bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, siba->siba_mem_res);
+
+	return (0);
+}
+
+static int
+siba_bwn_shutdown(device_t dev)
+{
+	device_t *devlistp;
+	int devcnt, error = 0, i;
+
+	error = device_get_children(dev, &devlistp, &devcnt);
+	if (error != 0)
+		return (error);
+
+	for (i = 0 ; i < devcnt ; i++)
+		device_shutdown(devlistp[i]);
+	free(devlistp, M_TEMP);
+	return (0);
+}
+
+static int
+siba_bwn_suspend(device_t dev)
+{
+	struct siba_bwn_softc *ssc = device_get_softc(dev);
+	struct siba_softc *siba = &ssc->ssc_siba;
+	device_t *devlistp;
+	int devcnt, error = 0, i, j;
+
+	error = device_get_children(dev, &devlistp, &devcnt);
+	if (error != 0)
+		return (error);
+
+	for (i = 0 ; i < devcnt ; i++) {
+		error = DEVICE_SUSPEND(devlistp[i]);
+		if (error) {
+			for (j = 0; j < i; i++)
+				DEVICE_RESUME(devlistp[j]);
+			return (error);
+		}
+	}
+	free(devlistp, M_TEMP);
+	return (siba_core_suspend(siba));
+}
+
+static int
+siba_bwn_resume(device_t dev)
+{
+	struct siba_bwn_softc *ssc = device_get_softc(dev);
+	struct siba_softc *siba = &ssc->ssc_siba;
+	device_t *devlistp;
+	int devcnt, error = 0, i;
+
+	error = siba_core_resume(siba);
+	if (error != 0)
+		return (error);
+
+	error = device_get_children(dev, &devlistp, &devcnt);
+	if (error != 0)
+		return (error);
+
+	for (i = 0 ; i < devcnt ; i++)
+		DEVICE_RESUME(devlistp[i]);
+	free(devlistp, M_TEMP);
+	return (0);
+}
+
+static device_t
+siba_bwn_add_child(device_t dev, int order, const char *name, int unit)
+{
+	struct siba_bwn_softc *ssc = device_get_softc(dev);
+	struct siba_softc *siba = &ssc->ssc_siba;
+
+	return (siba_add_child(dev, siba, order, name, unit));
+}
+
+/* proxying to the parent */
+static struct resource *
+siba_bwn_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+
+	return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+	    type, rid, start, end, count, flags));
+}
+
+/* proxying to the parent */
+static int
+siba_bwn_release_resource(device_t dev, device_t child, int type,
+    int rid, struct resource *r)
+{
+
+	return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type,
+	    rid, r));
+}
+
+/* proxying to the parent */
+static int
+siba_bwn_setup_intr(device_t dev, device_t child, struct resource *irq,
+    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
+    void **cookiep)
+{
+
+	return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags,
+	    filter, intr, arg, cookiep));
+}
+
+/* proxying to the parent */
+static int
+siba_bwn_teardown_intr(device_t dev, device_t child, struct resource *irq,
+    void *cookie)
+{
+
+	return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie));
+}
+
+static int
+siba_bwn_find_extcap(device_t dev, device_t child, int capability,
+    int *capreg)
+{
+
+	return (pci_find_extcap(dev, capability, capreg));
+}
+
+static int
+siba_bwn_alloc_msi(device_t dev, device_t child, int *count)
+{
+	struct siba_bwn_softc *ssc;
+	int error;
+
+	ssc = device_get_softc(dev);
+	if (ssc->ssc_msi_child != NULL)
+		return (EBUSY);
+	error = pci_alloc_msi(dev, count);
+	if (error == 0)
+		ssc->ssc_msi_child = child;
+	return (error);
+}
+
+static int
+siba_bwn_release_msi(device_t dev, device_t child)
+{
+	struct siba_bwn_softc *ssc;
+	int error;
+
+	ssc = device_get_softc(dev);
+	if (ssc->ssc_msi_child != child)
+		return (ENXIO);
+	error = pci_release_msi(dev);
+	if (error == 0)
+		ssc->ssc_msi_child = NULL;
+	return (error);
+}
+
+static int
+siba_bwn_msi_count(device_t dev, device_t child)
+{
+
+	return (pci_msi_count(dev));
+}
+
+static device_method_t siba_bwn_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		siba_bwn_probe),
+	DEVMETHOD(device_attach,	siba_bwn_attach),
+	DEVMETHOD(device_detach,	siba_bwn_detach),
+	DEVMETHOD(device_shutdown,	siba_bwn_shutdown),
+	DEVMETHOD(device_suspend,	siba_bwn_suspend),
+	DEVMETHOD(device_resume,	siba_bwn_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_add_child,	siba_bwn_add_child),
+	DEVMETHOD(bus_alloc_resource,   siba_bwn_alloc_resource),
+	DEVMETHOD(bus_release_resource, siba_bwn_release_resource),
+	DEVMETHOD(bus_setup_intr,       siba_bwn_setup_intr),
+	DEVMETHOD(bus_teardown_intr,    siba_bwn_teardown_intr),
+
+	/* PCI interface */
+	DEVMETHOD(pci_find_extcap,	siba_bwn_find_extcap),
+	DEVMETHOD(pci_alloc_msi,	siba_bwn_alloc_msi),
+	DEVMETHOD(pci_release_msi,	siba_bwn_release_msi),
+	DEVMETHOD(pci_msi_count,	siba_bwn_msi_count),
+
+	{ 0,0 }
+};
+static driver_t siba_bwn_driver = {
+	"siba_bwn",
+	siba_bwn_methods,
+	sizeof(struct siba_bwn_softc)
+};
+static devclass_t siba_bwn_devclass;
+DRIVER_MODULE(siba_bwn, pci, siba_bwn_driver, siba_bwn_devclass, 0, 0);
+MODULE_VERSION(siba_bwn, 1);
Index: siba_core.c
===================================================================
--- siba_core.c	(revision 0)
+++ siba_core.c	(revision 0)
@@ -0,0 +1,2007 @@
+/*-
+ * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * the Sonics Silicon Backplane driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/sibavar.h>
+
+#ifdef SIBA_DEBUG
+enum {
+	SIBA_DEBUG_SCAN		= 0x00000001,	/* scan */
+	SIBA_DEBUG_PMU		= 0x00000002,	/* PMU */
+	SIBA_DEBUG_PLL		= 0x00000004,	/* PLL */
+	SIBA_DEBUG_SWITCHCORE	= 0x00000008,	/* switching core */
+	SIBA_DEBUG_SPROM	= 0x00000010,	/* SPROM */
+	SIBA_DEBUG_CORE		= 0x00000020,	/* handling cores */
+	SIBA_DEBUG_ANY		= 0xffffffff
+};
+#define DPRINTF(siba, m, fmt, ...) do {			\
+	if (siba->siba_debug & (m))			\
+		printf(fmt, __VA_ARGS__);		\
+} while (0)
+#else
+#define DPRINTF(siba, m, fmt, ...) do { (void) siba; } while (0)
+#endif
+#define	N(a)			(sizeof(a) / sizeof(a[0]))
+
+static void	siba_pci_gpio(struct siba_softc *, uint32_t, int);
+static void	siba_scan(struct siba_softc *);
+static int	siba_switchcore(struct siba_softc *, uint8_t);
+static int	siba_pci_switchcore_sub(struct siba_softc *, uint8_t);
+static uint32_t	siba_scan_read_4(struct siba_softc *, uint8_t, uint16_t);
+static uint16_t	siba_dev2chipid(struct siba_softc *);
+static uint16_t	siba_pci_read_2(struct siba_dev_softc *, uint16_t);
+static uint32_t	siba_pci_read_4(struct siba_dev_softc *, uint16_t);
+static void	siba_pci_write_2(struct siba_dev_softc *, uint16_t, uint16_t);
+static void	siba_pci_write_4(struct siba_dev_softc *, uint16_t, uint32_t);
+static void	siba_cc_clock(struct siba_cc *,
+		    enum siba_clock);
+static void	siba_cc_pmu_init(struct siba_cc *);
+static void	siba_cc_power_init(struct siba_cc *);
+static void	siba_cc_powerup_delay(struct siba_cc *);
+static int	siba_cc_clockfreq(struct siba_cc *, int);
+static void	siba_cc_pmu1_pll0_init(struct siba_cc *, uint32_t);
+static void	siba_cc_pmu0_pll0_init(struct siba_cc *, uint32_t);
+static enum siba_clksrc siba_cc_clksrc(struct siba_cc *);
+static const struct siba_cc_pmu1_plltab *siba_cc_pmu1_plltab_find(uint32_t);
+static uint32_t	siba_cc_pll_read(struct siba_cc *, uint32_t);
+static void	siba_cc_pll_write(struct siba_cc *, uint32_t,
+		    uint32_t);
+static const struct siba_cc_pmu0_plltab *
+		siba_cc_pmu0_plltab_findentry(uint32_t);
+static int	siba_pci_sprom(struct siba_softc *, struct siba_sprom *);
+static int	siba_sprom_read(struct siba_softc *, uint16_t *, uint16_t);
+static int	sprom_check_crc(const uint16_t *, size_t);
+static uint8_t	siba_crc8(uint8_t, uint8_t);
+static void	siba_sprom_r123(struct siba_sprom *, const uint16_t *);
+static void	siba_sprom_r45(struct siba_sprom *, const uint16_t *);
+static void	siba_sprom_r8(struct siba_sprom *, const uint16_t *);
+static int8_t	siba_sprom_r123_antgain(uint8_t, const uint16_t *, uint16_t,
+		    uint16_t);
+static uint32_t	siba_tmslow_reject_bitmask(struct siba_dev_softc *);
+static uint32_t	siba_pcicore_read_4(struct siba_pci *, uint16_t);
+static void	siba_pcicore_write_4(struct siba_pci *, uint16_t, uint32_t);
+static uint32_t	siba_pcie_read(struct siba_pci *, uint32_t);
+static void	siba_pcie_write(struct siba_pci *, uint32_t, uint32_t);
+static void	siba_pcie_mdio_write(struct siba_pci *, uint8_t, uint8_t,
+		    uint16_t);
+static void	siba_pci_read_multi_1(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+static void	siba_pci_read_multi_2(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+static void	siba_pci_read_multi_4(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+static void	siba_pci_write_multi_1(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+static void	siba_pci_write_multi_2(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+static void	siba_pci_write_multi_4(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+static const char *siba_core_name(uint16_t);
+static void	siba_pcicore_init(struct siba_pci *);
+device_t	siba_add_child(device_t, struct siba_softc *, int, const char *,
+		    int);
+int		siba_core_attach(struct siba_softc *);
+int		siba_core_detach(struct siba_softc *);
+int		siba_core_suspend(struct siba_softc *);
+int		siba_core_resume(struct siba_softc *);
+uint8_t		siba_getncores(device_t, uint16_t);
+
+static const struct siba_bus_ops siba_pci_ops = {
+	.read_2		= siba_pci_read_2,
+	.read_4		= siba_pci_read_4,
+	.write_2	= siba_pci_write_2,
+	.write_4	= siba_pci_write_4,
+	.read_multi_1	= siba_pci_read_multi_1,
+	.read_multi_2	= siba_pci_read_multi_2,
+	.read_multi_4	= siba_pci_read_multi_4,
+	.write_multi_1	= siba_pci_write_multi_1,
+	.write_multi_2	= siba_pci_write_multi_2,
+	.write_multi_4	= siba_pci_write_multi_4,
+};
+
+static const struct siba_cc_pmu_res_updown siba_cc_pmu_4325_updown[] =
+    SIBA_CC_PMU_4325_RES_UPDOWN;
+static const struct siba_cc_pmu_res_depend siba_cc_pmu_4325_depend[] =
+    SIBA_CC_PMU_4325_RES_DEPEND;
+static const struct siba_cc_pmu_res_updown siba_cc_pmu_4328_updown[] =
+    SIBA_CC_PMU_4328_RES_UPDOWN;
+static const struct siba_cc_pmu_res_depend siba_cc_pmu_4328_depend[] =
+    SIBA_CC_PMU_4328_RES_DEPEND;
+static const struct siba_cc_pmu0_plltab siba_cc_pmu0_plltab[] =
+    SIBA_CC_PMU0_PLLTAB_ENTRY;
+static const struct siba_cc_pmu1_plltab siba_cc_pmu1_plltab[] =
+    SIBA_CC_PMU1_PLLTAB_ENTRY;
+
+int
+siba_core_attach(struct siba_softc *siba)
+{
+	struct siba_cc *scc;
+	int error;
+
+	KASSERT(siba->siba_type == SIBA_TYPE_PCI,
+	    ("unsupported BUS type (%#x)", siba->siba_type));
+
+	siba->siba_ops = &siba_pci_ops;
+
+	siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 1);
+	siba_scan(siba);
+
+	/* XXX init PCI or PCMCIA host devices */
+
+	siba_powerup(siba, 0);
+
+	/* init ChipCommon */
+	scc = &siba->siba_cc;
+	if (scc->scc_dev != NULL) {
+		siba_cc_pmu_init(scc);
+		siba_cc_power_init(scc);
+		siba_cc_clock(scc, SIBA_CLOCK_FAST);
+		siba_cc_powerup_delay(scc);
+	}
+
+	/* fetch various internal informations for PCI */
+	siba->siba_board_vendor = pci_read_config(siba->siba_dev,
+	    PCIR_SUBVEND_0, 2);
+	siba->siba_board_type = pci_read_config(siba->siba_dev, PCIR_SUBDEV_0,
+	    2);
+	siba->siba_board_rev = pci_read_config(siba->siba_dev, PCIR_REVID, 2);
+	error = siba_pci_sprom(siba, &siba->siba_sprom);
+	if (error) {
+		siba_powerdown(siba);
+		return (error);
+	}
+
+	siba_powerdown(siba);
+	return (0);
+}
+
+int
+siba_core_detach(struct siba_softc *siba)
+{
+	device_t *devlistp;
+	int devcnt, error = 0, i;
+
+	error = device_get_children(siba->siba_dev, &devlistp, &devcnt);
+	if (error != 0)
+		return (0);
+
+	for ( i = 0 ; i < devcnt ; i++)
+		device_delete_child(siba->siba_dev, devlistp[i]);
+	free(devlistp, M_TEMP);
+	return (0);
+}
+
+static void
+siba_pci_gpio(struct siba_softc *siba, uint32_t what, int on)
+{
+	uint32_t in, out;
+	uint16_t status;
+
+	if (siba->siba_type != SIBA_TYPE_PCI)
+		return;
+
+	out = pci_read_config(siba->siba_dev, SIBA_GPIO_OUT, 4);
+	if (on == 0) {
+		if (what & SIBA_GPIO_PLL)
+			out |= SIBA_GPIO_PLL;
+		if (what & SIBA_GPIO_CRYSTAL)
+			out &= ~SIBA_GPIO_CRYSTAL;
+		pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4);
+		pci_write_config(siba->siba_dev, SIBA_GPIO_OUT_EN,
+		    pci_read_config(siba->siba_dev,
+			SIBA_GPIO_OUT_EN, 4) | what, 4);
+		return;
+	}
+
+	in = pci_read_config(siba->siba_dev, SIBA_GPIO_IN, 4);
+	if ((in & SIBA_GPIO_CRYSTAL) != SIBA_GPIO_CRYSTAL) {
+		if (what & SIBA_GPIO_CRYSTAL) {
+			out |= SIBA_GPIO_CRYSTAL;
+			if (what & SIBA_GPIO_PLL)
+				out |= SIBA_GPIO_PLL;
+			pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4);
+			pci_write_config(siba->siba_dev,
+			    SIBA_GPIO_OUT_EN, pci_read_config(siba->siba_dev,
+				SIBA_GPIO_OUT_EN, 4) | what, 4);
+			DELAY(1000);
+		}
+		if (what & SIBA_GPIO_PLL) {
+			out &= ~SIBA_GPIO_PLL;
+			pci_write_config(siba->siba_dev, SIBA_GPIO_OUT, out, 4);
+			DELAY(5000);
+		}
+	}
+
+	status = pci_read_config(siba->siba_dev, PCIR_STATUS, 2);
+	status &= ~PCIM_STATUS_STABORT;
+	pci_write_config(siba->siba_dev, PCIR_STATUS, status, 2);
+}
+
+static void
+siba_scan(struct siba_softc *siba)
+{
+	struct siba_dev_softc *sd;
+	uint32_t idhi, tmp;
+	int base, dev_i = 0, error, i, is_pcie, n_80211 = 0, n_cc = 0,
+	    n_pci = 0;
+
+	KASSERT(siba->siba_type == SIBA_TYPE_PCI,
+	    ("unsupported BUS type (%#x)", siba->siba_type));
+
+	siba->siba_ndevs = 0;
+	error = siba_switchcore(siba, 0); /* need the first core */
+	if (error)
+		return;
+
+	idhi = siba_scan_read_4(siba, 0, SIBA_IDHIGH);
+	if (SIBA_IDHIGH_CORECODE(idhi) == SIBA_DEVID_CHIPCOMMON) {
+		tmp = siba_scan_read_4(siba, 0, SIBA_CC_CHIPID);
+		siba->siba_chipid = SIBA_CC_ID(tmp);
+		siba->siba_chiprev = SIBA_CC_REV(tmp);
+		siba->siba_chippkg = SIBA_CC_PKG(tmp);
+		if (SIBA_IDHIGH_REV(idhi) >= 4)
+			siba->siba_ndevs = SIBA_CC_NCORES(tmp);
+		siba->siba_cc.scc_caps = siba_scan_read_4(siba, 0,
+		    SIBA_CC_CAPS);
+	} else {
+		if (siba->siba_type == SIBA_TYPE_PCI) {
+			siba->siba_chipid = siba_dev2chipid(siba);
+			siba->siba_chiprev = pci_read_config(siba->siba_dev,
+			    PCIR_REVID, 2);
+			siba->siba_chippkg = 0;
+		} else {
+			siba->siba_chipid = 0x4710;
+			siba->siba_chiprev = 0;
+			siba->siba_chippkg = 0;
+		}
+	}
+	if (siba->siba_ndevs == 0)
+		siba->siba_ndevs = siba_getncores(siba->siba_dev,
+		    siba->siba_chipid);
+	if (siba->siba_ndevs > SIBA_MAX_CORES) {
+		device_printf(siba->siba_dev,
+		    "too many siba cores (max %d %d)\n",
+		    SIBA_MAX_CORES, siba->siba_ndevs);
+		return;
+	}
+
+	/* looking basic information about each cores/devices */
+	for (i = 0; i < siba->siba_ndevs; i++) {
+		error = siba_switchcore(siba, i);
+		if (error)
+			return;
+		sd = &(siba->siba_devs[dev_i]);
+		idhi = siba_scan_read_4(siba, i, SIBA_IDHIGH);
+		sd->sd_bus = siba;
+		sd->sd_id.sd_device = SIBA_IDHIGH_CORECODE(idhi);
+		sd->sd_id.sd_rev = SIBA_IDHIGH_REV(idhi);
+		sd->sd_id.sd_vendor = SIBA_IDHIGH_VENDOR(idhi);
+		sd->sd_ops = siba->siba_ops;
+		sd->sd_coreidx = i;
+
+		DPRINTF(siba, SIBA_DEBUG_SCAN,
+		    "core %d (%s) found (cc %#xrev %#x vendor %#x)\n",
+		    i, siba_core_name(sd->sd_id.sd_device),
+		    sd->sd_id.sd_device, sd->sd_id.sd_rev, sd->sd_id.vendor);
+
+		switch (sd->sd_id.sd_device) {
+		case SIBA_DEVID_CHIPCOMMON:
+			n_cc++;
+			if (n_cc > 1) {
+				device_printf(siba->siba_dev,
+				    "warn: multiple ChipCommon\n");
+				break;
+			}
+			siba->siba_cc.scc_dev = sd;
+			break;
+		case SIBA_DEVID_80211:
+			n_80211++;
+			if (n_80211 > 1) {
+				device_printf(siba->siba_dev,
+				    "warn: multiple 802.11 core\n");
+				continue;
+			}
+			break;
+		case SIBA_DEVID_PCI:
+		case SIBA_DEVID_PCIE:
+			n_pci++;
+			error = pci_find_extcap(siba->siba_dev, PCIY_EXPRESS,
+			    &base);
+			is_pcie = (error == 0) ? 1 : 0;
+
+			if (n_pci > 1) {
+				device_printf(siba->siba_dev,
+				    "warn: multiple PCI(E) cores\n");
+				break;
+			}
+			if (sd->sd_id.sd_device == SIBA_DEVID_PCI &&
+			    is_pcie == 1)
+				continue;
+			if (sd->sd_id.sd_device == SIBA_DEVID_PCIE &&
+			    is_pcie == 0)
+				continue;
+			siba->siba_pci.spc_dev = sd;
+			break;
+		case SIBA_DEVID_MODEM:
+		case SIBA_DEVID_PCMCIA:
+			break;
+		default:
+			device_printf(siba->siba_dev,
+			    "unsupported coreid (%s)\n",
+			    siba_core_name(sd->sd_id.sd_device));
+			break;
+		}
+		dev_i++;
+	}
+	siba->siba_ndevs = dev_i;
+}
+
+static int
+siba_switchcore(struct siba_softc *siba, uint8_t idx)
+{
+
+	switch (siba->siba_type) {
+	case SIBA_TYPE_PCI:
+		return (siba_pci_switchcore_sub(siba, idx));
+	default:
+		KASSERT(0 == 1,
+		    ("%s: unsupported bustype %#x", __func__,
+		    siba->siba_type));
+	}
+	return (0);
+}
+
+static int
+siba_pci_switchcore_sub(struct siba_softc *siba, uint8_t idx)
+{
+#define RETRY_MAX	50
+	int i;
+	uint32_t dir;
+
+	dir = SIBA_REGWIN(idx);
+
+	for (i = 0; i < RETRY_MAX; i++) {
+		pci_write_config(siba->siba_dev, SIBA_BAR0, dir, 4);
+		if (pci_read_config(siba->siba_dev, SIBA_BAR0, 4) == dir)
+			return (0);
+		DELAY(10);
+	}
+	return (ENODEV);
+#undef RETRY_MAX
+}
+
+static int
+siba_pci_switchcore(struct siba_softc *siba, struct siba_dev_softc *sd)
+{
+	int error;
+
+	DPRINTF(siba, SIBA_DEBUG_SWITCHCORE, "Switching to %s core, index %d\n",
+	    siba_core_name(sd->sd_id.sd_device), sd->sd_coreidx);
+
+	error = siba_pci_switchcore_sub(siba, sd->sd_coreidx);
+	if (error == 0)
+		siba->siba_curdev = sd;
+
+	return (error);
+}
+
+static uint32_t
+siba_scan_read_4(struct siba_softc *siba, uint8_t coreidx,
+    uint16_t offset)
+{
+
+	(void)coreidx;
+	KASSERT(siba->siba_type == SIBA_TYPE_PCI,
+	    ("unsupported BUS type (%#x)", siba->siba_type));
+
+	return (SIBA_READ_4(siba, offset));
+}
+
+static uint16_t
+siba_dev2chipid(struct siba_softc *siba)
+{
+	uint16_t chipid = 0;
+
+	switch (siba->siba_pci_did) {
+	case 0x4301:
+		chipid = 0x4301;
+		break;
+	case 0x4305:
+	case 0x4306:
+	case 0x4307:
+		chipid = 0x4307;
+		break;
+	case 0x4403:
+		chipid = 0x4402;
+		break;
+	case 0x4610:
+	case 0x4611:
+	case 0x4612:
+	case 0x4613:
+	case 0x4614:
+	case 0x4615:
+		chipid = 0x4610;
+		break;
+	case 0x4710:
+	case 0x4711:
+	case 0x4712:
+	case 0x4713:
+	case 0x4714:
+	case 0x4715:
+		chipid = 0x4710;
+		break;
+	case 0x4320:
+	case 0x4321:
+	case 0x4322:
+	case 0x4323:
+	case 0x4324:
+	case 0x4325:
+		chipid = 0x4309;
+		break;
+	case PCI_DEVICE_ID_BCM4401:
+	case PCI_DEVICE_ID_BCM4401B0:
+	case PCI_DEVICE_ID_BCM4401B1:
+		chipid = 0x4401;
+		break;
+	default:
+		device_printf(siba->siba_dev, "unknown PCI did (%d)\n",
+		    siba->siba_pci_did);
+	}
+
+	return (chipid);
+}
+
+/*
+ * Earlier ChipCommon revisions have hardcoded number of cores
+ * present dependent on the ChipCommon ID.
+ */
+uint8_t
+siba_getncores(device_t dev, uint16_t chipid)
+{
+	switch (chipid) {
+	case 0x4401:
+	case 0x4402:
+		return (3);
+	case 0x4301:
+	case 0x4307:
+		return (5);
+	case 0x4306:
+		return (6);
+	case SIBA_CCID_SENTRY5:
+		return (7);
+	case 0x4310:
+		return (8);
+	case SIBA_CCID_BCM4710:
+	case 0x4610:
+	case SIBA_CCID_BCM4704:
+		return (9);
+	default:
+		device_printf(dev, "unknown the chipset ID %#x\n", chipid);
+	}
+
+	return (1);
+}
+
+static const char *
+siba_core_name(uint16_t coreid)
+{
+
+	switch (coreid) {
+	case SIBA_DEVID_CHIPCOMMON:
+		return ("ChipCommon");
+	case SIBA_DEVID_ILINE20:
+		return ("ILine 20");
+	case SIBA_DEVID_SDRAM:
+		return ("SDRAM");
+	case SIBA_DEVID_PCI:
+		return ("PCI");
+	case SIBA_DEVID_MIPS:
+		return ("MIPS");
+	case SIBA_DEVID_ETHERNET:
+		return ("Fast Ethernet");
+	case SIBA_DEVID_MODEM:
+		return ("Modem");
+	case SIBA_DEVID_USB11_HOSTDEV:
+		return ("USB 1.1 Hostdev");
+	case SIBA_DEVID_ADSL:
+		return ("ADSL");
+	case SIBA_DEVID_ILINE100:
+		return ("ILine 100");
+	case SIBA_DEVID_IPSEC:
+		return ("IPSEC");
+	case SIBA_DEVID_PCMCIA:
+		return ("PCMCIA");
+	case SIBA_DEVID_INTERNAL_MEM:
+		return ("Internal Memory");
+	case SIBA_DEVID_SDRAMDDR:
+		return ("MEMC SDRAM");
+	case SIBA_DEVID_EXTIF:
+		return ("EXTIF");
+	case SIBA_DEVID_80211:
+		return ("IEEE 802.11");
+	case SIBA_DEVID_MIPS_3302:
+		return ("MIPS 3302");
+	case SIBA_DEVID_USB11_HOST:
+		return ("USB 1.1 Host");
+	case SIBA_DEVID_USB11_DEV:
+		return ("USB 1.1 Device");
+	case SIBA_DEVID_USB20_HOST:
+		return ("USB 2.0 Host");
+	case SIBA_DEVID_USB20_DEV:
+		return ("USB 2.0 Device");
+	case SIBA_DEVID_SDIO_HOST:
+		return ("SDIO Host");
+	case SIBA_DEVID_ROBOSWITCH:
+		return ("Roboswitch");
+	case SIBA_DEVID_PARA_ATA:
+		return ("PATA");
+	case SIBA_DEVID_SATA_XORDMA:
+		return ("SATA XOR-DMA");
+	case SIBA_DEVID_ETHERNET_GBIT:
+		return ("GBit Ethernet");
+	case SIBA_DEVID_PCIE:
+		return ("PCI-Express");
+	case SIBA_DEVID_MIMO_PHY:
+		return ("MIMO PHY");
+	case SIBA_DEVID_SRAM_CTRLR:
+		return ("SRAM Controller");
+	case SIBA_DEVID_MINI_MACPHY:
+		return ("Mini MACPHY");
+	case SIBA_DEVID_ARM_1176:
+		return ("ARM 1176");
+	case SIBA_DEVID_ARM_7TDMI:
+		return ("ARM 7TDMI");
+	}
+	return ("unknown");
+}
+
+static uint16_t
+siba_pci_read_2(struct siba_dev_softc *sd, uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return (0xffff);
+
+	return (SIBA_READ_2(siba, offset));
+}
+
+static uint32_t
+siba_pci_read_4(struct siba_dev_softc *sd, uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return (0xffff);
+
+	return (SIBA_READ_4(siba, offset));
+}
+
+static void
+siba_pci_write_2(struct siba_dev_softc *sd, uint16_t offset, uint16_t value)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return;
+
+	SIBA_WRITE_2(siba, offset, value);
+}
+
+static void
+siba_pci_write_4(struct siba_dev_softc *sd, uint16_t offset, uint32_t value)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return;
+
+	SIBA_WRITE_4(siba, offset, value);
+}
+
+static void
+siba_pci_read_multi_1(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) {
+		memset(buffer, 0xff, count);
+		return;
+	}
+
+	SIBA_READ_MULTI_1(siba, offset, buffer, count);
+}
+
+static void
+siba_pci_read_multi_2(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) {
+		memset(buffer, 0xff, count);
+		return;
+	}
+
+	KASSERT(!(count & 1), ("%s:%d: fail", __func__, __LINE__));
+	SIBA_READ_MULTI_2(siba, offset, buffer, count >> 1);
+}
+
+static void
+siba_pci_read_multi_4(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0) {
+		memset(buffer, 0xff, count);
+		return;
+	}
+
+	KASSERT(!(count & 3), ("%s:%d: fail", __func__, __LINE__));
+	SIBA_READ_MULTI_4(siba, offset, buffer, count >> 2);
+}
+
+static void
+siba_pci_write_multi_1(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return;
+
+	SIBA_WRITE_MULTI_1(siba, offset, buffer, count);
+}
+
+static void
+siba_pci_write_multi_2(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return;
+
+	KASSERT(!(count & 1), ("%s:%d: fail", __func__, __LINE__));
+	SIBA_WRITE_MULTI_2(siba, offset, buffer, count >> 1);
+}
+
+static void
+siba_pci_write_multi_4(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (siba->siba_curdev != sd && siba_pci_switchcore(siba, sd) != 0)
+		return;
+
+	KASSERT(!(count & 3), ("%s:%d: fail", __func__, __LINE__));
+	SIBA_WRITE_MULTI_4(siba, offset, buffer, count >> 2);
+}
+
+void
+siba_powerup(struct siba_softc *siba, int dynamic)
+{
+
+	siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 1);
+	siba_cc_clock(&siba->siba_cc,
+	    (dynamic != 0) ? SIBA_CLOCK_DYNAMIC : SIBA_CLOCK_FAST);
+}
+
+static void
+siba_cc_clock(struct siba_cc *scc, enum siba_clock clock)
+{
+	struct siba_dev_softc *sd = scc->scc_dev;
+	struct siba_softc *siba;
+	uint32_t tmp;
+
+	if (sd == NULL)
+		return;
+	siba = sd->sd_bus;
+	/*
+	 * chipcommon < r6 (no dynamic clock control)
+	 * chipcommon >= r10 (unknown)
+	 */
+	if (sd->sd_id.sd_rev < 6 || sd->sd_id.sd_rev >= 10 ||
+	    (scc->scc_caps & SIBA_CC_CAPS_PWCTL) == 0)
+		return;
+
+	switch (clock) {
+	case SIBA_CLOCK_DYNAMIC:
+		tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) &
+		    ~(SIBA_CC_CLKSLOW_ENXTAL | SIBA_CC_CLKSLOW_FSLOW |
+		    SIBA_CC_CLKSLOW_IPLL);
+		if ((tmp & SIBA_CC_CLKSLOW_SRC) != SIBA_CC_CLKSLOW_SRC_CRYSTAL)
+			tmp |= SIBA_CC_CLKSLOW_ENXTAL;
+		SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW, tmp);
+		if (tmp & SIBA_CC_CLKSLOW_ENXTAL)
+			siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL, 0);
+		break;
+	case SIBA_CLOCK_SLOW:
+		SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW,
+		    SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) |
+		    SIBA_CC_CLKSLOW_FSLOW);
+		break;
+	case SIBA_CLOCK_FAST:
+		/* crystal on */
+		siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL, 1);
+		SIBA_CC_WRITE32(scc, SIBA_CC_CLKSLOW,
+		    (SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) |
+			SIBA_CC_CLKSLOW_IPLL) & ~SIBA_CC_CLKSLOW_FSLOW);
+		break;
+	default:
+		KASSERT(0 == 1,
+		    ("%s: unsupported clock %#x", __func__, clock));
+	}
+}
+
+uint16_t
+siba_read_2(struct siba_dev_softc *sd, uint16_t offset)
+{
+
+	return (sd->sd_ops->read_2(sd, offset));
+}
+
+uint32_t
+siba_read_4(struct siba_dev_softc *sd, uint16_t offset)
+{
+
+	return (sd->sd_ops->read_4(sd, offset));
+}
+
+void
+siba_write_2(struct siba_dev_softc *sd, uint16_t offset, uint16_t value)
+{
+
+	sd->sd_ops->write_2(sd, offset, value);
+}
+
+void
+siba_write_4(struct siba_dev_softc *sd, uint16_t offset, uint32_t value)
+{
+
+	sd->sd_ops->write_4(sd, offset, value);
+}
+
+void
+siba_read_multi_1(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+
+	sd->sd_ops->read_multi_1(sd, buffer, count, offset);
+}
+
+void
+siba_read_multi_2(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+
+	sd->sd_ops->read_multi_2(sd, buffer, count, offset);
+}
+
+void
+siba_read_multi_4(struct siba_dev_softc *sd, void *buffer, size_t count,
+    uint16_t offset)
+{
+
+	sd->sd_ops->read_multi_4(sd, buffer, count, offset);
+}
+
+void
+siba_write_multi_1(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+
+	sd->sd_ops->write_multi_1(sd, buffer, count, offset);
+}
+
+void
+siba_write_multi_2(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+
+	sd->sd_ops->write_multi_2(sd, buffer, count, offset);
+}
+
+void
+siba_write_multi_4(struct siba_dev_softc *sd, const void *buffer,
+    size_t count, uint16_t offset)
+{
+
+	sd->sd_ops->write_multi_4(sd, buffer, count, offset);
+}
+
+static void
+siba_cc_pmu_init(struct siba_cc *scc)
+{
+	const struct siba_cc_pmu_res_updown *updown = NULL;
+	const struct siba_cc_pmu_res_depend *depend = NULL;
+	struct siba_dev_softc *sd = scc->scc_dev;
+	struct siba_softc *siba = sd->sd_bus;
+	uint32_t min = 0, max = 0, pmucap;
+	unsigned int i, updown_size, depend_size;
+
+	if ((scc->scc_caps & SIBA_CC_CAPS_PMU) == 0)
+		return;
+
+	pmucap = SIBA_CC_READ32(scc, SIBA_CC_PMUCAPS);
+	scc->scc_pmu.rev = (pmucap & SIBA_CC_PMUCAPS_REV);
+
+	DPRINTF(siba, SIBA_DEBUG_PMU, "PMU(r%u) found (caps %#x)\n",
+	    scc->scc_pmu.rev, pmucap);
+
+	if (scc->scc_pmu.rev >= 1) {
+		if (siba->siba_chiprev < 2 && siba->siba_chipid == 0x4325)
+			SIBA_CC_MASK32(scc, SIBA_CC_PMUCTL,
+			    ~SIBA_CC_PMUCTL_NOILP);
+		else
+			SIBA_CC_SET32(scc, SIBA_CC_PMUCTL,
+			    SIBA_CC_PMUCTL_NOILP);
+	}
+
+	/* initialize PLL & PMU resources */
+	switch (siba->siba_chipid) {
+	case 0x4312:
+		siba_cc_pmu1_pll0_init(scc, 0 /* use default */);
+		/* use the default: min = 0xcbb max = 0x7ffff */
+		break;
+	case 0x4325:
+		siba_cc_pmu1_pll0_init(scc, 0 /* use default */);
+
+		updown = siba_cc_pmu_4325_updown;
+		updown_size = N(siba_cc_pmu_4325_updown);
+		depend = siba_cc_pmu_4325_depend;
+		depend_size = N(siba_cc_pmu_4325_depend);
+
+		min = (1 << SIBA_CC_PMU_4325_BURST) |
+		    (1 << SIBA_CC_PMU_4325_LN);
+		if (SIBA_CC_READ32(scc, SIBA_CC_CHIPSTAT) &
+		    SIBA_CC_CHST_4325_PMUTOP_2B)
+			min |= (1 << SIBA_CC_PMU_4325_CLBURST);
+		max = 0xfffff;
+		break;
+	case 0x4328:
+		siba_cc_pmu0_pll0_init(scc, 0 /* use default */);
+
+		updown = siba_cc_pmu_4328_updown;
+		updown_size = N(siba_cc_pmu_4328_updown);
+		depend = siba_cc_pmu_4328_depend;
+		depend_size = N(siba_cc_pmu_4328_depend);
+
+		min = (1 << SIBA_CC_PMU_4328_EXT_SWITCH_PWM) |
+			  (1 << SIBA_CC_PMU_4328_BB_SWITCH_PWM) |
+			  (1 << SIBA_CC_PMU_4328_CRYSTAL_EN);
+
+		max = 0xfffff;
+		break;
+	case 0x5354:
+		siba_cc_pmu0_pll0_init(scc, 0 /* use default */);
+
+		max = 0xfffff;
+		break;
+	default:
+		device_printf(siba->siba_dev,
+		    "unknown chipid %#x for PLL & PMU init\n",
+		    siba->siba_chipid);
+	}
+
+	if (updown) {
+		for (i = 0; i < updown_size; i++) {
+			SIBA_CC_WRITE32(scc, SIBA_CC_PMU_TABSEL,
+			    updown[i].res);
+			SIBA_CC_WRITE32(scc, SIBA_CC_PMU_UPDNTM,
+			    updown[i].updown);
+		}
+	}
+	if (depend) {
+		for (i = 0; i < depend_size; i++) {
+			SIBA_CC_WRITE32(scc, SIBA_CC_PMU_TABSEL,
+			    depend[i].res);
+			switch (depend[i].task) {
+			case SIBA_CC_PMU_DEP_SET:
+				SIBA_CC_WRITE32(scc, SIBA_CC_PMU_DEPMSK,
+				    depend[i].depend);
+				break;
+			case SIBA_CC_PMU_DEP_ADD:
+				SIBA_CC_SET32(scc, SIBA_CC_PMU_DEPMSK,
+				    depend[i].depend);
+				break;
+			case SIBA_CC_PMU_DEP_REMOVE:
+				SIBA_CC_MASK32(scc, SIBA_CC_PMU_DEPMSK,
+				    ~(depend[i].depend));
+				break;
+			default:
+				KASSERT(0 == 1,
+				    ("%s:%d: assertion failed",
+					__func__, __LINE__));
+			}
+		}
+	}
+
+	if (min)
+		SIBA_CC_WRITE32(scc, SIBA_CC_PMU_MINRES, min);
+	if (max)
+		SIBA_CC_WRITE32(scc, SIBA_CC_PMU_MAXRES, max);
+}
+
+static void
+siba_cc_power_init(struct siba_cc *scc)
+{
+	struct siba_softc *siba = scc->scc_dev->sd_bus;
+	int maxfreq;
+
+	if (siba->siba_chipid == 0x4321) {
+		if (siba->siba_chiprev == 0)
+			SIBA_CC_WRITE32(scc, SIBA_CC_CHIPCTL, 0x3a4);
+		else if (siba->siba_chiprev == 1)
+			SIBA_CC_WRITE32(scc, SIBA_CC_CHIPCTL, 0xa4);
+	}
+
+	if ((scc->scc_caps & SIBA_CC_CAPS_PWCTL) == 0)
+		return;
+
+	if (scc->scc_dev->sd_id.sd_rev >= 10)
+		SIBA_CC_WRITE32(scc, SIBA_CC_CLKSYSCTL,
+		    (SIBA_CC_READ32(scc, SIBA_CC_CLKSYSCTL) &
+		    0xffff) | 0x40000);
+	else {
+		maxfreq = siba_cc_clockfreq(scc, 1);
+		SIBA_CC_WRITE32(scc, SIBA_CC_PLLONDELAY,
+		    (maxfreq * 150 + 999999) / 1000000);
+		SIBA_CC_WRITE32(scc, SIBA_CC_FREFSELDELAY,
+		    (maxfreq * 15 + 999999) / 1000000);
+	}
+}
+
+static void
+siba_cc_powerup_delay(struct siba_cc *scc)
+{
+	struct siba_softc *siba = scc->scc_dev->sd_bus;
+	int min;
+
+	if (siba->siba_type != SIBA_TYPE_PCI ||
+	    !(scc->scc_caps & SIBA_CC_CAPS_PWCTL))
+		return;
+
+	min = siba_cc_clockfreq(scc, 0);
+	scc->scc_powerup_delay =
+	    (((SIBA_CC_READ32(scc, SIBA_CC_PLLONDELAY) + 2) * 1000000) +
+	    (min - 1)) / min;
+}
+
+static int
+siba_cc_clockfreq(struct siba_cc *scc, int max)
+{
+	enum siba_clksrc src;
+	int div = 1, limit = 0;
+
+	src = siba_cc_clksrc(scc);
+	if (scc->scc_dev->sd_id.sd_rev < 6) {
+		div = (src == SIBA_CC_CLKSRC_PCI) ? 64 :
+		    (src == SIBA_CC_CLKSRC_CRYSTAL) ? 32 : 1;
+		KASSERT(div != 1,
+		    ("%s: unknown clock %d", __func__, src));
+	} else if (scc->scc_dev->sd_id.sd_rev < 10) {
+		switch (src) {
+		case SIBA_CC_CLKSRC_CRYSTAL:
+		case SIBA_CC_CLKSRC_PCI:
+			div = ((SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) >> 16) +
+			    1) * 4;
+			break;
+		case SIBA_CC_CLKSRC_LOWPW:
+			break;
+		}
+	} else
+		div = ((SIBA_CC_READ32(scc, SIBA_CC_CLKSYSCTL) >> 16) + 1) * 4;
+
+	switch (src) {
+	case SIBA_CC_CLKSRC_CRYSTAL:
+		limit = (max) ? 20200000 : 19800000;
+		break;
+	case SIBA_CC_CLKSRC_LOWPW:
+		limit = (max) ? 43000 : 25000;
+		break;
+	case SIBA_CC_CLKSRC_PCI:
+		limit = (max) ? 34000000 : 25000000;
+		break;
+	}
+
+	return (limit / div);
+}
+
+static void
+siba_cc_pmu1_pll0_init(struct siba_cc *scc, uint32_t freq)
+{
+	struct siba_dev_softc *sd = scc->scc_dev;
+	struct siba_softc *siba = sd->sd_bus;
+	const struct siba_cc_pmu1_plltab *e = NULL;
+	uint32_t bufsth = 0, pll, pmu;
+	unsigned int i;
+
+	KASSERT(freq == 0, ("%s:%d: assertion vail", __func__, __LINE__));
+	if (siba->siba_chipid == 0x4312) {
+		scc->scc_pmu.freq = 20000;
+		return;
+	}
+
+	e = siba_cc_pmu1_plltab_find(SIBA_CC_PMU1_DEFAULT_FREQ);
+	KASSERT(e != NULL, ("%s:%d: assertion vail", __func__, __LINE__));
+	scc->scc_pmu.freq = e->freq;
+
+	pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL);
+	if (SIBA_CC_PMUCTL_XF_VAL(pmu) == e->xf)
+		return;
+
+	DPRINTF(siba, SIBA_DEBUG_PLL, "change PLL value to %u.%03u MHz\n",
+	    (e->freq / 1000), (e->freq % 1000));
+
+	/* turn PLL off */
+	switch (siba->siba_chipid) {
+	case 0x4325:
+		bufsth = 0x222222;
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES,
+		    ~((1 << SIBA_CC_PMU_4325_BBPLL_PWR) |
+		      (1 << SIBA_CC_PMU_4325_HT)));
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES,
+		    ~((1 << SIBA_CC_PMU_4325_BBPLL_PWR) |
+		      (1 << SIBA_CC_PMU_4325_HT)));
+		break;
+	default:
+		KASSERT(0 == 1,
+		    ("%s:%d: assertion failed", __func__, __LINE__));
+	}
+	for (i = 0; i < 1500; i++) {
+		if (!(SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS) &
+		      SIBA_CC_CLKCTLSTATUS_HT))
+			break;
+		DELAY(10);
+	}
+	if (SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS) & SIBA_CC_CLKCTLSTATUS_HT)
+		device_printf(siba->siba_dev, "failed to turn PLL off!\n");
+
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL0);
+	pll &= ~(SIBA_CC_PMU1_PLL0_P1DIV | SIBA_CC_PMU1_PLL0_P2DIV);
+	pll |= ((uint32_t)e->p1div << 20) & SIBA_CC_PMU1_PLL0_P1DIV;
+	pll |= ((uint32_t)e->p2div << 24) & SIBA_CC_PMU1_PLL0_P2DIV;
+	siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL0, pll);
+
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL2);
+	pll &= ~(SIBA_CC_PMU1_PLL2_NDIVINT | SIBA_CC_PMU1_PLL2_NDIVMODE);
+	pll |= ((uint32_t)e->ndiv_int << 20) & SIBA_CC_PMU1_PLL2_NDIVINT;
+	pll |= (1 << 17) & SIBA_CC_PMU1_PLL2_NDIVMODE;
+	siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL2, pll);
+
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL3);
+	pll &= ~SIBA_CC_PMU1_PLL3_NDIVFRAC;
+	pll |= ((uint32_t)e->ndiv_frac << 0) & SIBA_CC_PMU1_PLL3_NDIVFRAC;
+	siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL3, pll);
+
+	if (bufsth) {
+		pll = siba_cc_pll_read(scc, SIBA_CC_PMU1_PLL5);
+		pll &= ~SIBA_CC_PMU1_PLL5_CLKDRV;
+		pll |= (bufsth << 8) & SIBA_CC_PMU1_PLL5_CLKDRV;
+		siba_cc_pll_write(scc, SIBA_CC_PMU1_PLL5, pll);
+	}
+
+	pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL);
+	pmu &= ~(SIBA_CC_PMUCTL_ILP | SIBA_CC_PMUCTL_XF);
+	pmu |= ((((uint32_t)e->freq + 127) / 128 - 1) << 16) &
+	    SIBA_CC_PMUCTL_ILP;
+	pmu |= ((uint32_t)e->xf << 2) & SIBA_CC_PMUCTL_XF;
+	SIBA_CC_WRITE32(scc, SIBA_CC_PMUCTL, pmu);
+}
+
+static void
+siba_cc_pmu0_pll0_init(struct siba_cc *scc, uint32_t xtalfreq)
+{
+	struct siba_dev_softc *sd = scc->scc_dev;
+	struct siba_softc *siba = sd->sd_bus;
+	const struct siba_cc_pmu0_plltab *e = NULL;
+	uint32_t pmu, tmp, pll;
+	unsigned int i;
+
+	if ((siba->siba_chipid == 0x5354) && !xtalfreq)
+		xtalfreq = 25000;
+	if (xtalfreq)
+		e = siba_cc_pmu0_plltab_findentry(xtalfreq);
+	if (!e)
+		e = siba_cc_pmu0_plltab_findentry(
+		    SIBA_CC_PMU0_DEFAULT_XTALFREQ);
+	KASSERT(e != NULL, ("%s:%d: fail", __func__, __LINE__));
+	xtalfreq = e->freq;
+	scc->scc_pmu.freq = e->freq;
+
+	pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL);
+	if (((pmu & SIBA_CC_PMUCTL_XF) >> 2) == e->xf)
+		return;
+
+	DPRINTF(siba, SIBA_DEBUG_PLL, "change PLL value to %u.%03u mhz\n",
+	    (xtalfreq / 1000), (xtalfreq % 1000));
+
+	KASSERT(siba->siba_chipid == 0x4328 || siba->siba_chipid == 0x5354,
+	    ("%s:%d: fail", __func__, __LINE__));
+
+	switch (siba->siba_chipid) {
+	case 0x4328:
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES,
+		    ~(1 << SIBA_CC_PMU_4328_BB_PLL_PU));
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES,
+		    ~(1 << SIBA_CC_PMU_4328_BB_PLL_PU));
+		break;
+	case 0x5354:
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MINRES,
+		    ~(1 << SIBA_CC_PMU_5354_BB_PLL_PU));
+		SIBA_CC_MASK32(scc, SIBA_CC_PMU_MAXRES,
+		    ~(1 << SIBA_CC_PMU_5354_BB_PLL_PU));
+		break;
+	}
+	for (i = 1500; i; i--) {
+		tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS);
+		if (!(tmp & SIBA_CC_CLKCTLSTATUS_HT))
+			break;
+		DELAY(10);
+	}
+	tmp = SIBA_CC_READ32(scc, SIBA_CC_CLKCTLSTATUS);
+	if (tmp & SIBA_CC_CLKCTLSTATUS_HT)
+		device_printf(siba->siba_dev, "failed to turn PLL off!\n");
+
+	/* set PDIV */
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL0);
+	if (xtalfreq >= SIBA_CC_PMU0_PLL0_PDIV_FREQ)
+		pll |= SIBA_CC_PMU0_PLL0_PDIV_MSK;
+	else
+		pll &= ~SIBA_CC_PMU0_PLL0_PDIV_MSK;
+	siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL0, pll);
+
+	/* set WILD */
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL1);
+	pll &= ~(SIBA_CC_PMU0_PLL1_STOPMOD | SIBA_CC_PMU0_PLL1_IMSK |
+	    SIBA_CC_PMU0_PLL1_FMSK);
+	pll |= ((uint32_t)e->wb_int << 28) & SIBA_CC_PMU0_PLL1_IMSK;
+	pll |= ((uint32_t)e->wb_frac << 8) & SIBA_CC_PMU0_PLL1_FMSK;
+	if (e->wb_frac == 0)
+		pll |= SIBA_CC_PMU0_PLL1_STOPMOD;
+	siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL1, pll);
+
+	/* set WILD */
+	pll = siba_cc_pll_read(scc, SIBA_CC_PMU0_PLL2);
+	pll &= ~SIBA_CC_PMU0_PLL2_IMSKHI;
+	pll |= (((uint32_t)e->wb_int >> 4) << 0) & SIBA_CC_PMU0_PLL2_IMSKHI;
+	siba_cc_pll_write(scc, SIBA_CC_PMU0_PLL2, pll);
+
+	/* set freq and divisor. */
+	pmu = SIBA_CC_READ32(scc, SIBA_CC_PMUCTL);
+	pmu &= ~SIBA_CC_PMUCTL_ILP;
+	pmu |= (((xtalfreq + 127) / 128 - 1) << 16) & SIBA_CC_PMUCTL_ILP;
+	pmu &= ~SIBA_CC_PMUCTL_XF;
+	pmu |= ((uint32_t)e->xf << 2) & SIBA_CC_PMUCTL_XF;
+	SIBA_CC_WRITE32(scc, SIBA_CC_PMUCTL, pmu);
+}
+
+static enum siba_clksrc
+siba_cc_clksrc(struct siba_cc *scc)
+{
+	struct siba_dev_softc *sd = scc->scc_dev;
+	struct siba_softc *siba = sd->sd_bus;
+
+	if (sd->sd_id.sd_rev < 6) {
+		if (siba->siba_type == SIBA_TYPE_PCI) {
+			if (pci_read_config(siba->siba_dev, SIBA_GPIO_OUT, 4) &
+			    0x10)
+				return (SIBA_CC_CLKSRC_PCI);
+			return (SIBA_CC_CLKSRC_CRYSTAL);
+		}
+		if (siba->siba_type == SIBA_TYPE_SSB ||
+		    siba->siba_type == SIBA_TYPE_PCMCIA)
+			return (SIBA_CC_CLKSRC_CRYSTAL);
+	}
+	if (sd->sd_id.sd_rev < 10) {
+		switch (SIBA_CC_READ32(scc, SIBA_CC_CLKSLOW) & 0x7) {
+		case 0:
+			return (SIBA_CC_CLKSRC_LOWPW);
+		case 1:
+			return (SIBA_CC_CLKSRC_CRYSTAL);
+		case 2:
+			return (SIBA_CC_CLKSRC_PCI);
+		default:
+			break;
+		}
+	}
+
+	return (SIBA_CC_CLKSRC_CRYSTAL);
+}
+
+static const struct siba_cc_pmu1_plltab *
+siba_cc_pmu1_plltab_find(uint32_t crystalfreq)
+{
+	const struct siba_cc_pmu1_plltab *e;
+	unsigned int i;
+
+	for (i = 0; i < N(siba_cc_pmu1_plltab); i++) {
+		e = &siba_cc_pmu1_plltab[i];
+		if (crystalfreq == e->freq)
+			return (e);
+	}
+
+	return (NULL);
+}
+
+static uint32_t
+siba_cc_pll_read(struct siba_cc *scc, uint32_t offset)
+{
+
+	SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_ADDR, offset);
+	return (SIBA_CC_READ32(scc, SIBA_CC_PLLCTL_DATA));
+}
+
+static void
+siba_cc_pll_write(struct siba_cc *scc, uint32_t offset, uint32_t value)
+{
+
+	SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_ADDR, offset);
+	SIBA_CC_WRITE32(scc, SIBA_CC_PLLCTL_DATA, value);
+}
+
+static const struct siba_cc_pmu0_plltab *
+siba_cc_pmu0_plltab_findentry(uint32_t crystalfreq)
+{
+	const struct siba_cc_pmu0_plltab *e;
+	unsigned int i;
+
+	for (i = 0; i < N(siba_cc_pmu0_plltab); i++) {
+		e = &siba_cc_pmu0_plltab[i];
+		if (e->freq == crystalfreq)
+			return (e);
+	}
+
+	return (NULL);
+}
+
+static int
+siba_pci_sprom(struct siba_softc *siba, struct siba_sprom *sprom)
+{
+	int error = ENOMEM;
+	uint16_t *buf;
+
+	buf = malloc(SIBA_SPROMSIZE_R123 * sizeof(uint16_t),
+	    M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (buf == NULL)
+		return (ENOMEM);
+	siba_sprom_read(siba, buf, SIBA_SPROMSIZE_R123);
+	error = sprom_check_crc(buf, siba->siba_spromsize);
+	if (error) {
+		free(buf, M_DEVBUF);
+		buf = malloc(SIBA_SPROMSIZE_R4 * sizeof(uint16_t),
+		    M_DEVBUF, M_NOWAIT | M_ZERO);
+		if (buf == NULL)
+			return (ENOMEM);
+		siba_sprom_read(siba, buf, SIBA_SPROMSIZE_R4);
+		error = sprom_check_crc(buf, siba->siba_spromsize);
+		if (error)
+			device_printf(siba->siba_dev, "warn: bad SPROM CRC\n");
+	}
+
+	bzero(sprom, sizeof(*sprom));
+
+	sprom->rev = buf[siba->siba_spromsize - 1] & 0x00FF;
+	DPRINTF(siba, SIBA_DEBUG_SPROM, "SPROM rev %d\n",
+	    sprom->rev);
+	memset(sprom->mac_eth, 0xff, 6);
+	memset(sprom->mac_80211a, 0xff, 6);
+	if ((siba->siba_chipid & 0xff00) == 0x4400) {
+		sprom->rev = 1;
+		siba_sprom_r123(sprom, buf);
+	} else if (siba->siba_chipid == 0x4321) {
+		sprom->rev = 4;
+		siba_sprom_r45(sprom, buf);
+	} else {
+		switch (sprom->rev) {
+		case 1:
+		case 2:
+		case 3:
+			siba_sprom_r123(sprom, buf);
+			break;
+		case 4:
+		case 5:
+			siba_sprom_r45(sprom, buf);
+			break;
+		case 8:
+			siba_sprom_r8(sprom, buf);
+			break;
+		default:
+			device_printf(siba->siba_dev,
+			    "unknown SPROM revision %d.\n", sprom->rev);
+			siba_sprom_r123(sprom, buf);
+		}
+	}
+
+	if (sprom->bf_lo == 0xffff)
+		sprom->bf_lo = 0;
+	if (sprom->bf_hi == 0xffff)
+		sprom->bf_hi = 0;
+
+	free(buf, M_DEVBUF);
+	return (error);
+}
+
+static int
+siba_sprom_read(struct siba_softc *siba, uint16_t *sprom, uint16_t len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		sprom[i] = SIBA_READ_2(siba, SIBA_SPROM_BASE + (i * 2));
+
+	siba->siba_spromsize = len;
+	return (0);
+}
+
+static int
+sprom_check_crc(const uint16_t *sprom, size_t size)
+{
+	int word;
+	uint8_t crc0, crc1 = 0xff;
+
+	crc0 = (sprom[size - 1] & SIBA_SPROM_REV_CRC) >> 8;
+	for (word = 0; word < size - 1; word++) {
+		crc1 = siba_crc8(crc1, sprom[word] & 0x00ff);
+		crc1 = siba_crc8(crc1, (sprom[word] & 0xff00) >> 8);
+	}
+	crc1 = siba_crc8(crc1, sprom[size - 1] & 0x00ff);
+	crc1 ^= 0xff;
+
+	return ((crc0 != crc1) ? EPROTO : 0);
+}
+
+static uint8_t
+siba_crc8(uint8_t crc, uint8_t data)
+{
+	static const uint8_t ct[] = {
+		0x00, 0xf7, 0xb9, 0x4e, 0x25, 0xd2, 0x9c, 0x6b,
+		0x4a, 0xbd, 0xf3, 0x04, 0x6f, 0x98, 0xd6, 0x21,
+		0x94, 0x63, 0x2d, 0xda, 0xb1, 0x46, 0x08, 0xff,
+		0xde, 0x29, 0x67, 0x90, 0xfb, 0x0c, 0x42, 0xb5,
+		0x7f, 0x88, 0xc6, 0x31, 0x5a, 0xad, 0xe3, 0x14,
+		0x35, 0xc2, 0x8c, 0x7b, 0x10, 0xe7, 0xa9, 0x5e,
+		0xeb, 0x1c, 0x52, 0xa5, 0xce, 0x39, 0x77, 0x80,
+		0xa1, 0x56, 0x18, 0xef, 0x84, 0x73, 0x3d, 0xca,
+		0xfe, 0x09, 0x47, 0xb0, 0xdb, 0x2c, 0x62, 0x95,
+		0xb4, 0x43, 0x0d, 0xfa, 0x91, 0x66, 0x28, 0xdf,
+		0x6a, 0x9d, 0xd3, 0x24, 0x4f, 0xb8, 0xf6, 0x01,
+		0x20, 0xd7, 0x99, 0x6e, 0x05, 0xf2, 0xbc, 0x4b,
+		0x81, 0x76, 0x38, 0xcf, 0xa4, 0x53, 0x1d, 0xea,
+		0xcb, 0x3c, 0x72, 0x85, 0xee, 0x19, 0x57, 0xa0,
+		0x15, 0xe2, 0xac, 0x5b, 0x30, 0xc7, 0x89, 0x7e,
+		0x5f, 0xa8, 0xe6, 0x11, 0x7a, 0x8d, 0xc3, 0x34,
+		0xab, 0x5c, 0x12, 0xe5, 0x8e, 0x79, 0x37, 0xc0,
+		0xe1, 0x16, 0x58, 0xaf, 0xc4, 0x33, 0x7d, 0x8a,
+		0x3f, 0xc8, 0x86, 0x71, 0x1a, 0xed, 0xa3, 0x54,
+		0x75, 0x82, 0xcc, 0x3b, 0x50, 0xa7, 0xe9, 0x1e,
+		0xd4, 0x23, 0x6d, 0x9a, 0xf1, 0x06, 0x48, 0xbf,
+		0x9e, 0x69, 0x27, 0xd0, 0xbb, 0x4c, 0x02, 0xf5,
+		0x40, 0xb7, 0xf9, 0x0e, 0x65, 0x92, 0xdc, 0x2b,
+		0x0a, 0xfd, 0xb3, 0x44, 0x2f, 0xd8, 0x96, 0x61,
+		0x55, 0xa2, 0xec, 0x1b, 0x70, 0x87, 0xc9, 0x3e,
+		0x1f, 0xe8, 0xa6, 0x51, 0x3a, 0xcd, 0x83, 0x74,
+		0xc1, 0x36, 0x78, 0x8f, 0xe4, 0x13, 0x5d, 0xaa,
+		0x8b, 0x7c, 0x32, 0xc5, 0xae, 0x59, 0x17, 0xe0,
+		0x2a, 0xdd, 0x93, 0x64, 0x0f, 0xf8, 0xb6, 0x41,
+		0x60, 0x97, 0xd9, 0x2e, 0x45, 0xb2, 0xfc, 0x0b,
+		0xbe, 0x49, 0x07, 0xf0, 0x9b, 0x6c, 0x22, 0xd5,
+		0xf4, 0x03, 0x4d, 0xba, 0xd1, 0x26, 0x68, 0x9f,
+	};
+	return (ct[crc ^ data]);
+}
+
+#define	SIBA_LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
+#define SIBA_OFFSET(offset)	\
+	(((offset) - SIBA_SPROM_BASE) / sizeof(uint16_t))
+#define	SIBA_SHIFTOUT_SUB(__x, __mask)					\
+	(((__x) & (__mask)) / SIBA_LOWEST_SET_BIT(__mask))
+#define	SIBA_SHIFTOUT(_var, _offset, _mask)				\
+	out->_var = SIBA_SHIFTOUT_SUB(in[SIBA_OFFSET(_offset)], (_mask))
+
+static void
+siba_sprom_r123(struct siba_sprom *out, const uint16_t *in)
+{
+	int i;
+	uint16_t v;
+	int8_t gain;
+	uint16_t loc[3];
+
+	if (out->rev == 3)
+		loc[0] = SIBA_SPROM3_MAC_80211BG;
+	else {
+		loc[0] = SIBA_SPROM1_MAC_80211BG;
+		loc[1] = SIBA_SPROM1_MAC_ETH;
+		loc[2] = SIBA_SPROM1_MAC_80211A;
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SIBA_OFFSET(loc[0]) + i];
+		*(((uint16_t *)out->mac_80211bg) + i) = htobe16(v);
+	}
+	if (out->rev < 3) {
+		for (i = 0; i < 3; i++) {
+			v = in[SIBA_OFFSET(loc[1]) + i];
+			*(((uint16_t *)out->mac_eth) + i) = htobe16(v);
+		}
+		for (i = 0; i < 3; i++) {
+			v = in[SIBA_OFFSET(loc[2]) + i];
+			*(((uint16_t *)out->mac_80211a) + i) = htobe16(v);
+		}
+	}
+	SIBA_SHIFTOUT(mii_eth0, SIBA_SPROM1_ETHPHY,
+	    SIBA_SPROM1_ETHPHY_MII_ETH0);
+	SIBA_SHIFTOUT(mii_eth1, SIBA_SPROM1_ETHPHY,
+	    SIBA_SPROM1_ETHPHY_MII_ETH1);
+	SIBA_SHIFTOUT(mdio_eth0, SIBA_SPROM1_ETHPHY,
+	    SIBA_SPROM1_ETHPHY_MDIO_ETH0);
+	SIBA_SHIFTOUT(mdio_eth1, SIBA_SPROM1_ETHPHY,
+	    SIBA_SPROM1_ETHPHY_MDIO_ETH1);
+	SIBA_SHIFTOUT(brev, SIBA_SPROM1_BOARDINFO, SIBA_SPROM1_BOARDINFO_BREV);
+	SIBA_SHIFTOUT(ccode, SIBA_SPROM1_BOARDINFO,
+	    SIBA_SPROM1_BOARDINFO_CCODE);
+	SIBA_SHIFTOUT(ant_a, SIBA_SPROM1_BOARDINFO, SIBA_SPROM1_BOARDINFO_ANTA);
+	SIBA_SHIFTOUT(ant_bg, SIBA_SPROM1_BOARDINFO,
+	    SIBA_SPROM1_BOARDINFO_ANTBG);
+	SIBA_SHIFTOUT(pa0b0, SIBA_SPROM1_PA0B0, 0xffff);
+	SIBA_SHIFTOUT(pa0b1, SIBA_SPROM1_PA0B1, 0xffff);
+	SIBA_SHIFTOUT(pa0b2, SIBA_SPROM1_PA0B2, 0xffff);
+	SIBA_SHIFTOUT(pa1b0, SIBA_SPROM1_PA1B0, 0xffff);
+	SIBA_SHIFTOUT(pa1b1, SIBA_SPROM1_PA1B1, 0xffff);
+	SIBA_SHIFTOUT(pa1b2, SIBA_SPROM1_PA1B2, 0xffff);
+	SIBA_SHIFTOUT(gpio0, SIBA_SPROM1_GPIOA, SIBA_SPROM1_GPIOA_P0);
+	SIBA_SHIFTOUT(gpio1, SIBA_SPROM1_GPIOA, SIBA_SPROM1_GPIOA_P1);
+	SIBA_SHIFTOUT(gpio2, SIBA_SPROM1_GPIOB, SIBA_SPROM1_GPIOB_P2);
+	SIBA_SHIFTOUT(gpio3, SIBA_SPROM1_GPIOB, SIBA_SPROM1_GPIOB_P3);
+	SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM1_MAXPWR, SIBA_SPROM1_MAXPWR_A);
+	SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM1_MAXPWR, SIBA_SPROM1_MAXPWR_BG);
+	SIBA_SHIFTOUT(tssi_a, SIBA_SPROM1_TSSI, SIBA_SPROM1_TSSI_A);
+	SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM1_TSSI, SIBA_SPROM1_TSSI_BG);
+	SIBA_SHIFTOUT(bf_lo, SIBA_SPROM1_BFLOW, 0xffff);
+	if (out->rev >= 2)
+		SIBA_SHIFTOUT(bf_hi, SIBA_SPROM2_BFHIGH, 0xffff);
+
+	/* antenna gain */
+	gain = siba_sprom_r123_antgain(out->rev, in, SIBA_SPROM1_AGAIN_BG, 0);
+	out->again.ghz24.a0 = out->again.ghz24.a1 = gain;
+	out->again.ghz24.a2 = out->again.ghz24.a3 = gain;
+	gain = siba_sprom_r123_antgain(out->rev, in, SIBA_SPROM1_AGAIN_A, 8);
+	out->again.ghz5.a0 = out->again.ghz5.a1 = gain;
+	out->again.ghz5.a2 = out->again.ghz5.a3 = gain;
+}
+
+static void
+siba_sprom_r45(struct siba_sprom *out, const uint16_t *in)
+{
+	int i;
+	uint16_t v;
+	uint16_t mac_80211bg_offset;
+
+	if (out->rev == 4)
+		mac_80211bg_offset = SIBA_SPROM4_MAC_80211BG;
+	else
+		mac_80211bg_offset = SIBA_SPROM5_MAC_80211BG;
+	for (i = 0; i < 3; i++) {
+		v = in[SIBA_OFFSET(mac_80211bg_offset) + i];
+		*(((uint16_t *)out->mac_80211bg) + i) = htobe16(v);
+	}
+	SIBA_SHIFTOUT(mii_eth0, SIBA_SPROM4_ETHPHY, SIBA_SPROM4_ETHPHY_ET0A);
+	SIBA_SHIFTOUT(mii_eth1, SIBA_SPROM4_ETHPHY, SIBA_SPROM4_ETHPHY_ET1A);
+	if (out->rev == 4) {
+		SIBA_SHIFTOUT(ccode, SIBA_SPROM4_CCODE, 0xffff);
+		SIBA_SHIFTOUT(bf_lo, SIBA_SPROM4_BFLOW, 0xffff);
+		SIBA_SHIFTOUT(bf_hi, SIBA_SPROM4_BFHIGH, 0xffff);
+	} else {
+		SIBA_SHIFTOUT(ccode, SIBA_SPROM5_CCODE, 0xffff);
+		SIBA_SHIFTOUT(bf_lo, SIBA_SPROM5_BFLOW, 0xffff);
+		SIBA_SHIFTOUT(bf_hi, SIBA_SPROM5_BFHIGH, 0xffff);
+	}
+	SIBA_SHIFTOUT(ant_a, SIBA_SPROM4_ANTAVAIL, SIBA_SPROM4_ANTAVAIL_A);
+	SIBA_SHIFTOUT(ant_bg, SIBA_SPROM4_ANTAVAIL, SIBA_SPROM4_ANTAVAIL_BG);
+	SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM4_MAXP_BG, SIBA_SPROM4_MAXP_BG_MASK);
+	SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM4_MAXP_BG, SIBA_SPROM4_TSSI_BG);
+	SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM4_MAXP_A, SIBA_SPROM4_MAXP_A_MASK);
+	SIBA_SHIFTOUT(tssi_a, SIBA_SPROM4_MAXP_A, SIBA_SPROM4_TSSI_A);
+	if (out->rev == 4) {
+		SIBA_SHIFTOUT(gpio0, SIBA_SPROM4_GPIOA, SIBA_SPROM4_GPIOA_P0);
+		SIBA_SHIFTOUT(gpio1, SIBA_SPROM4_GPIOA, SIBA_SPROM4_GPIOA_P1);
+		SIBA_SHIFTOUT(gpio2, SIBA_SPROM4_GPIOB, SIBA_SPROM4_GPIOB_P2);
+		SIBA_SHIFTOUT(gpio3, SIBA_SPROM4_GPIOB, SIBA_SPROM4_GPIOB_P3);
+	} else {
+		SIBA_SHIFTOUT(gpio0, SIBA_SPROM5_GPIOA, SIBA_SPROM5_GPIOA_P0);
+		SIBA_SHIFTOUT(gpio1, SIBA_SPROM5_GPIOA, SIBA_SPROM5_GPIOA_P1);
+		SIBA_SHIFTOUT(gpio2, SIBA_SPROM5_GPIOB, SIBA_SPROM5_GPIOB_P2);
+		SIBA_SHIFTOUT(gpio3, SIBA_SPROM5_GPIOB, SIBA_SPROM5_GPIOB_P3);
+	}
+
+	/* antenna gain */
+	SIBA_SHIFTOUT(again.ghz24.a0, SIBA_SPROM4_AGAIN01, SIBA_SPROM4_AGAIN0);
+	SIBA_SHIFTOUT(again.ghz24.a1, SIBA_SPROM4_AGAIN01, SIBA_SPROM4_AGAIN1);
+	SIBA_SHIFTOUT(again.ghz24.a2, SIBA_SPROM4_AGAIN23, SIBA_SPROM4_AGAIN2);
+	SIBA_SHIFTOUT(again.ghz24.a3, SIBA_SPROM4_AGAIN23, SIBA_SPROM4_AGAIN3);
+	bcopy(&out->again.ghz24, &out->again.ghz5, sizeof(out->again.ghz5));
+}
+
+static void
+siba_sprom_r8(struct siba_sprom *out, const uint16_t *in)
+{
+	int i;
+	uint16_t v;
+
+	for (i = 0; i < 3; i++) {
+		v = in[SIBA_OFFSET(SIBA_SPROM1_MAC_80211BG) + i];
+		*(((uint16_t *)out->mac_80211bg) + i) = htobe16(v);
+	}
+	SIBA_SHIFTOUT(ccode, SIBA_SPROM8_CCODE, 0xffff);
+	SIBA_SHIFTOUT(bf_lo, SIBA_SPROM8_BFLOW, 0xffff);
+	SIBA_SHIFTOUT(bf_hi, SIBA_SPROM8_BFHIGH, 0xffff);
+	SIBA_SHIFTOUT(ant_a, SIBA_SPROM8_ANTAVAIL, SIBA_SPROM8_ANTAVAIL_A);
+	SIBA_SHIFTOUT(ant_bg, SIBA_SPROM8_ANTAVAIL, SIBA_SPROM8_ANTAVAIL_BG);
+	SIBA_SHIFTOUT(maxpwr_bg, SIBA_SPROM8_MAXP_BG, SIBA_SPROM8_MAXP_BG_MASK);
+	SIBA_SHIFTOUT(tssi_bg, SIBA_SPROM8_MAXP_BG, SIBA_SPROM8_TSSI_BG);
+	SIBA_SHIFTOUT(maxpwr_a, SIBA_SPROM8_MAXP_A, SIBA_SPROM8_MAXP_A_MASK);
+	SIBA_SHIFTOUT(tssi_a, SIBA_SPROM8_MAXP_A, SIBA_SPROM8_TSSI_A);
+	SIBA_SHIFTOUT(gpio0, SIBA_SPROM8_GPIOA, SIBA_SPROM8_GPIOA_P0);
+	SIBA_SHIFTOUT(gpio1, SIBA_SPROM8_GPIOA, SIBA_SPROM8_GPIOA_P1);
+	SIBA_SHIFTOUT(gpio2, SIBA_SPROM8_GPIOB, SIBA_SPROM8_GPIOB_P2);
+	SIBA_SHIFTOUT(gpio3, SIBA_SPROM8_GPIOB, SIBA_SPROM8_GPIOB_P3);
+
+	/* antenna gain */
+	SIBA_SHIFTOUT(again.ghz24.a0, SIBA_SPROM8_AGAIN01, SIBA_SPROM8_AGAIN0);
+	SIBA_SHIFTOUT(again.ghz24.a1, SIBA_SPROM8_AGAIN01, SIBA_SPROM8_AGAIN1);
+	SIBA_SHIFTOUT(again.ghz24.a2, SIBA_SPROM8_AGAIN23, SIBA_SPROM8_AGAIN2);
+	SIBA_SHIFTOUT(again.ghz24.a3, SIBA_SPROM8_AGAIN23, SIBA_SPROM8_AGAIN3);
+	bcopy(&out->again.ghz24, &out->again.ghz5, sizeof(out->again.ghz5));
+}
+
+static int8_t
+siba_sprom_r123_antgain(uint8_t sprom_revision, const uint16_t *in,
+    uint16_t mask, uint16_t shift)
+{
+	uint16_t v;
+	uint8_t gain;
+
+	v = in[SIBA_OFFSET(SIBA_SPROM1_AGAIN)];
+	gain = (v & mask) >> shift;
+	gain = (gain == 0xff) ? 2 : (sprom_revision == 1) ? gain << 2 :
+	    ((gain & 0xc0) >> 6) | ((gain & 0x3f) << 2);
+
+	return ((int8_t)gain);
+}
+
+#undef SIBA_LOWEST_SET_BIT
+#undef SIBA_OFFSET
+#undef SIBA_SHIFTOUT_SUB
+#undef SIBA_SHIFTOUT
+
+int
+siba_powerdown(struct siba_softc *siba)
+{
+	struct siba_cc *scc;
+
+	if (siba->siba_type == SIBA_TYPE_SSB)
+		return (0);
+
+	scc = &siba->siba_cc;
+	if (!scc->scc_dev || scc->scc_dev->sd_id.sd_rev < 5)
+		return (0);
+	siba_cc_clock(scc, SIBA_CLOCK_SLOW);
+	siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 0);
+	return (0);
+}
+
+static void
+siba_pcicore_init(struct siba_pci *spc)
+{
+	struct siba_dev_softc *sd = spc->spc_dev;
+	struct siba_softc *siba;
+
+	if (sd == NULL)
+		return;
+
+	siba = sd->sd_bus;
+	if (!siba_dev_isup(sd))
+		siba_dev_up(sd, 0);
+
+	KASSERT(spc->spc_hostmode == 0,
+	    ("%s:%d: hostmode", __func__, __LINE__));
+	/* disable PCI interrupt */
+	siba_write_4(spc->spc_dev, SIBA_INTR_MASK, 0);
+}
+
+int
+siba_dev_isup(struct siba_dev_softc *sd)
+{
+	uint32_t reject, val;
+
+	reject = siba_tmslow_reject_bitmask(sd);
+	val = siba_read_4(sd, SIBA_TGSLOW);
+	val &= SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_RESET | reject;
+
+	return (val == SIBA_TGSLOW_CLOCK);
+}
+
+void
+siba_dev_up(struct siba_dev_softc *sd, uint32_t flags)
+{
+	uint32_t val;
+
+	siba_dev_down(sd, flags);
+	siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_RESET | SIBA_TGSLOW_CLOCK |
+	    SIBA_TGSLOW_FGC | flags);
+	siba_read_4(sd, SIBA_TGSLOW);
+	DELAY(1);
+
+	if (siba_read_4(sd, SIBA_TGSHIGH) & SIBA_TGSHIGH_SERR)
+		siba_write_4(sd, SIBA_TGSHIGH, 0);
+
+	val = siba_read_4(sd, SIBA_IAS);
+	if (val & (SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT)) {
+		val &= ~(SIBA_IAS_INBAND_ERR | SIBA_IAS_TIMEOUT);
+		siba_write_4(sd, SIBA_IAS, val);
+	}
+
+	siba_write_4(sd, SIBA_TGSLOW,
+	    SIBA_TGSLOW_CLOCK | SIBA_TGSLOW_FGC | flags);
+	siba_read_4(sd, SIBA_TGSLOW);
+	DELAY(1);
+
+	siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_CLOCK | flags);
+	siba_read_4(sd, SIBA_TGSLOW);
+	DELAY(1);
+}
+
+static uint32_t
+siba_tmslow_reject_bitmask(struct siba_dev_softc *sd)
+{
+	uint32_t rev = siba_read_4(sd, SIBA_IDLOW) & SIBA_IDLOW_SSBREV;
+
+	switch (rev) {
+	case SIBA_IDLOW_SSBREV_22:
+		return (SIBA_TGSLOW_REJECT_22);
+	case SIBA_IDLOW_SSBREV_23:
+		return (SIBA_TGSLOW_REJECT_23);
+	case SIBA_IDLOW_SSBREV_24:
+	case SIBA_IDLOW_SSBREV_25:
+	case SIBA_IDLOW_SSBREV_26:
+	case SIBA_IDLOW_SSBREV_27:
+		return (SIBA_TGSLOW_REJECT_23);
+	default:
+		KASSERT(0 == 1,
+		    ("%s:%d: unknown backplane rev %#x\n",
+			__func__, __LINE__, rev));
+	}
+	return (SIBA_TGSLOW_REJECT_22 | SIBA_TGSLOW_REJECT_23);
+}
+
+void
+siba_dev_down(struct siba_dev_softc *sd, uint32_t flags)
+{
+	struct siba_softc *siba = sd->sd_bus;
+	uint32_t reject, val;
+	int i;
+
+	if (siba_read_4(sd, SIBA_TGSLOW) & SIBA_TGSLOW_RESET)
+		return;
+
+	reject = siba_tmslow_reject_bitmask(sd);
+	siba_write_4(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_CLOCK);
+
+	for (i = 0; i < 1000; i++) {
+		val = siba_read_4(sd, SIBA_TGSLOW);
+		if (val & reject)
+			break;
+		DELAY(10);
+	}
+	if ((val & reject) == 0) {
+		device_printf(siba->siba_dev, "timeout (bit %#x reg %#x)\n",
+		    reject, SIBA_TGSLOW);
+	}
+	for (i = 0; i < 1000; i++) {
+		val = siba_read_4(sd, SIBA_TGSHIGH);
+		if (!(val & SIBA_TGSHIGH_BUSY))
+			break;
+		DELAY(10);
+	}
+	if ((val & SIBA_TGSHIGH_BUSY) != 0) {
+		device_printf(siba->siba_dev, "timeout (bit %#x reg %#x)\n",
+		    SIBA_TGSHIGH_BUSY, SIBA_TGSHIGH);
+	}
+
+	siba_write_4(sd, SIBA_TGSLOW, SIBA_TGSLOW_FGC | SIBA_TGSLOW_CLOCK |
+	    reject | SIBA_TGSLOW_RESET | flags);
+	siba_read_4(sd, SIBA_TGSLOW);
+	DELAY(1);
+	siba_write_4(sd, SIBA_TGSLOW, reject | SIBA_TGSLOW_RESET | flags);
+	siba_read_4(sd, SIBA_TGSLOW);
+	DELAY(1);
+}
+
+static void
+siba_pcicore_setup(struct siba_pci *spc, struct siba_dev_softc *sd)
+{
+	struct siba_dev_softc *psd = spc->spc_dev;
+	struct siba_softc *siba = psd->sd_bus;
+	uint32_t tmp;
+
+	if (psd->sd_id.sd_device == SIBA_DEVID_PCI) {
+		siba_pcicore_write_4(spc, SIBA_PCICORE_SBTOPCI2,
+		    siba_pcicore_read_4(spc, SIBA_PCICORE_SBTOPCI2) |
+		    SIBA_PCICORE_SBTOPCI_PREF | SIBA_PCICORE_SBTOPCI_BURST);
+
+		if (psd->sd_id.sd_rev < 5) {
+			tmp = siba_read_4(psd, SIBA_IMCFGLO);
+			tmp &= ~SIBA_IMCFGLO_SERTO;
+			tmp = (tmp | 2) & ~SIBA_IMCFGLO_REQTO;
+			tmp |= 3 << 4 /* SIBA_IMCFGLO_REQTO_SHIFT */;
+			siba_write_4(psd, SIBA_IMCFGLO, tmp);
+
+			/* broadcast value */
+			sd = (siba->siba_cc.scc_dev != NULL) ?
+			    siba->siba_cc.scc_dev : siba->siba_pci.spc_dev;
+			if (sd != NULL) {
+				siba_write_4(sd, SIBA_PCICORE_BCAST_ADDR,
+				    0xfd8);
+				siba_read_4(sd, SIBA_PCICORE_BCAST_ADDR);
+				siba_write_4(sd, SIBA_PCICORE_BCAST_DATA, 0);
+				siba_read_4(sd, SIBA_PCICORE_BCAST_DATA);
+			}
+		} else if (psd->sd_id.sd_rev >= 11) {
+			tmp = siba_pcicore_read_4(spc, SIBA_PCICORE_SBTOPCI2);
+			tmp |= SIBA_PCICORE_SBTOPCI_MRM;
+			siba_pcicore_write_4(spc, SIBA_PCICORE_SBTOPCI2, tmp);
+		}
+	} else {
+		KASSERT(psd->sd_id.sd_device == SIBA_DEVID_PCIE, ("only PCIE"));
+		if ((psd->sd_id.sd_rev == 0) || (psd->sd_id.sd_rev == 1))
+			siba_pcie_write(spc, 0x4,
+			    siba_pcie_read(spc, 0x4) | 0x8);
+		if (psd->sd_id.sd_rev == 0) {
+			siba_pcie_mdio_write(spc, 0x1f, 2, 0x8128); /* Timer */
+			siba_pcie_mdio_write(spc, 0x1f, 6, 0x0100); /* CDR */
+			siba_pcie_mdio_write(spc, 0x1f, 7, 0x1466); /* CDR BW */
+		} else if (psd->sd_id.sd_rev == 1)
+			siba_pcie_write(spc, 0x100,
+			    siba_pcie_read(spc, 0x100) | 0x40);
+	}
+	spc->spc_inited = 1;
+}
+
+void
+siba_pcicore_intr(struct siba_pci *spc, struct siba_dev_softc *sd)
+{
+	struct siba_dev_softc *psd = spc->spc_dev;
+	struct siba_softc *siba;
+	uint32_t tmp;
+
+	if (sd->sd_bus->siba_type != SIBA_TYPE_PCI || !psd)
+		return;
+
+	siba = psd->sd_bus;
+	/* enable interrupts */
+	if (siba->siba_dev != NULL &&
+	    (psd->sd_id.sd_rev >= 6 || psd->sd_id.sd_device == SIBA_DEVID_PCIE)) {
+		tmp = pci_read_config(siba->siba_dev, SIBA_IRQMASK, 4);
+		tmp |= (1 << sd->sd_coreidx) << 8;
+		pci_write_config(siba->siba_dev, SIBA_IRQMASK, tmp, 4);
+	} else {
+		tmp = siba_read_4(sd, SIBA_TPS);
+		tmp &= SIBA_TPS_BPFLAG;
+		siba_write_4(psd, SIBA_INTR_MASK,
+		    siba_read_4(psd, SIBA_INTR_MASK) | (1 << tmp));
+	}
+
+	/* setup PCIcore */
+	if (spc->spc_inited == 0)
+		siba_pcicore_setup(spc, sd);
+}
+
+static uint32_t
+siba_pcicore_read_4(struct siba_pci *spc, uint16_t offset)
+{
+
+	return (siba_read_4(spc->spc_dev, offset));
+}
+
+static void
+siba_pcicore_write_4(struct siba_pci *spc, uint16_t offset, uint32_t value)
+{
+
+	siba_write_4(spc->spc_dev, offset, value);
+}
+
+static uint32_t
+siba_pcie_read(struct siba_pci *spc, uint32_t address)
+{
+
+	siba_pcicore_write_4(spc, 0x130, address);
+	return (siba_pcicore_read_4(spc, 0x134));
+}
+
+static void
+siba_pcie_write(struct siba_pci *spc, uint32_t address, uint32_t data)
+{
+
+	siba_pcicore_write_4(spc, 0x130, address);
+	siba_pcicore_write_4(spc, 0x134, data);
+}
+
+static void
+siba_pcie_mdio_write(struct siba_pci *spc, uint8_t device, uint8_t address,
+    uint16_t data)
+{
+	int i;
+
+	siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_CTL, 0x80 | 0x2);
+	siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_DATA,
+	    (1 << 30) | (1 << 28) |
+	    ((uint32_t)device << 22) | ((uint32_t)address << 18) |
+	    (1 << 17) | data);
+	DELAY(10);
+	for (i = 0; i < 10; i++) {
+		if (siba_pcicore_read_4(spc, SIBA_PCICORE_MDIO_CTL) & 0x100)
+			break;
+		DELAY(1000);
+	}
+	siba_pcicore_write_4(spc, SIBA_PCICORE_MDIO_CTL, 0);
+}
+
+uint32_t
+siba_dma_translation(struct siba_dev_softc *sd)
+{
+
+	KASSERT(sd->sd_bus->siba_type == SIBA_TYPE_PCI,
+	    ("unsupported bustype %d\n", sd->sd_bus->siba_type));
+	return (SIBA_PCI_DMA);
+}
+
+void
+siba_barrier(struct siba_dev_softc *sd, int flags)
+{
+	struct siba_softc *siba = sd->sd_bus;
+
+	SIBA_BARRIER(siba, flags);
+}
+
+/*
+ * Attach it as child.
+ */
+device_t
+siba_add_child(device_t dev, struct siba_softc *siba, int order,
+    const char *name, int unit)
+{
+	struct siba_dev_softc *sd;
+	device_t child;
+	int idx = 0, i;
+
+	child = device_add_child(dev, name, unit);
+	if (child == NULL)
+		return (NULL);
+
+	siba_powerup(siba, 0);
+	siba_pcicore_init(&siba->siba_pci);
+	siba_powerdown(siba);
+
+	for (i = 0; i < siba->siba_ndevs; i++) {
+		sd = &(siba->siba_devs[i]);
+
+		if (sd->sd_id.sd_device != SIBA_DEVID_80211) {
+			DPRINTF(siba, SIBA_DEBUG_CORE,
+			    "skip to register coreid %#x (%s)\n",
+			    sd->sd_id.sd_device,
+			    siba_core_name(sd->sd_id.sd_device));
+			continue;
+		}
+
+		DPRINTF(siba, SIBA_DEBUG_CORE,
+		    "siba: attaching coreid %#x (%s) idx %d\n",
+		    sd->sd_id.sd_device,
+		    siba_core_name(sd->sd_id.sd_device), idx);
+
+		KASSERT(sd->sd_id.sd_device == SIBA_DEVID_80211,
+		    ("%s:%d: SIBA_DEVID_80211 is only supportted currently.",
+			__func__, __LINE__));
+
+		device_set_ivars(child, sd);
+		device_probe_and_attach(child);
+		idx++;
+	}
+	return (child);
+}
+
+static void
+siba_cc_suspend(struct siba_cc *scc)
+{
+
+	siba_cc_clock(scc, SIBA_CLOCK_SLOW);
+}
+
+static void
+siba_cc_resume(struct siba_cc *scc)
+{
+
+	siba_cc_power_init(scc);
+	siba_cc_clock(scc, SIBA_CLOCK_FAST);
+}
+
+int
+siba_core_suspend(struct siba_softc *siba)
+{
+
+	siba_cc_suspend(&siba->siba_cc);
+	siba_pci_gpio(siba, SIBA_GPIO_CRYSTAL | SIBA_GPIO_PLL, 0);
+	return (0);
+}
+
+int
+siba_core_resume(struct siba_softc *siba)
+{
+
+	siba->siba_pci.spc_inited = 0;
+	siba->siba_curdev = NULL;
+
+	siba_powerup(siba, 0);
+	/* XXX setup H/W for PCMCIA??? */
+	siba_cc_resume(&siba->siba_cc);
+	siba_powerdown(siba);
+
+	return (0);
+}
Index: siba_pcib.c
===================================================================
--- siba_pcib.c	(revision 202983)
+++ siba_pcib.c	(working copy)
@@ -55,9 +55,9 @@
 
 #include "pcib_if.h"
 
-#include <dev/siba/sibavar.h>
-#include <dev/siba/sibareg.h>
 #include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/sibavar.h>
 #include <dev/siba/siba_pcibvar.h>
 
 #ifndef MIPS_MEM_RID
@@ -79,10 +79,6 @@
 #define SBPCI_CFGBASE			0x0C000000
 #define SBPCI_CFGSIZE			0x01000000
 
-#define SBPCI_SBTOPCI0 0x100
-#define SBPCI_SBTOPCI1 0x104
-#define SBPCI_SBTOPCI2 0x108
-
 /*
  * TODO: implement type 1 config space access (ie beyond bus 0)
  * we may need to tweak the windows to do this
@@ -187,9 +183,12 @@
 	 * XXX we need to be able to do type 1 too.
 	 * we probably don't need to be able to do i/o cycles.
 	 */
-	SBPCI_WRITE_4(sc, SBPCI_SBTOPCI0, 1);	/* I/O read/write window */
-	SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2);	/* type 0 configuration only */
-	SBPCI_WRITE_4(sc, SBPCI_SBTOPCI2, 1 << 30); /* memory only */
+
+	/* I/O read/write window */
+	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1);
+	/* type 0 configuration only */
+	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2);
+	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */
 	DELAY(500);
 
 	/* XXX resource managers */
@@ -365,7 +364,7 @@
 	/*
 	 * The configuration tag on the broadcom is weird.
 	 */
-	SBPCI_WRITE_4(sc, SBPCI_SBTOPCI1, 2);	/* XXX again??? */
+	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2);	/* XXX again??? */
 	cfgtag = ((1 << slot) << 16) | (func << 8);
 	cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3);
 
Index: sibavar.h
===================================================================
--- sibavar.h	(revision 202983)
+++ sibavar.h	(working copy)
@@ -31,62 +31,341 @@
 
 #include <sys/rman.h>
 
-struct siba_softc {
-	device_t		 sc_dev;	/* Device ID */
-	struct resource		*sc_mem;	/* Memory window on nexus */
+struct siba_softc;
+struct siba_dev_softc;
 
-	bus_space_tag_t		 sc_bt;
-	bus_space_handle_t	 sc_bh;
-	bus_addr_t		 sc_maddr;
-	bus_size_t		 sc_msize;
-
-	uint8_t			 sc_ncores;
+enum siba_device_ivars {
+	SIBA_IVAR_VENDOR,
+	SIBA_IVAR_DEVICE,
+	SIBA_IVAR_REVID,
+	SIBA_IVAR_CORE_INDEX
 };
 
-struct siba_devinfo {
-	struct resource_list	 sdi_rl;
-	/*devhandle_t		 sdi_devhandle; XXX*/
-	/*struct rman sdi_intr_rman;*/
+#define	SIBA_ACCESSOR(var, ivar, type)				\
+	__BUS_ACCESSOR(siba, var, SIBA, ivar, type)
 
-	/* Accessors are needed for ivars below. */
-	uint16_t		 sdi_vid;
-	uint16_t		 sdi_devid;
-	uint8_t			 sdi_rev;
-	uint8_t			 sdi_idx;	/* core index on bus */
-	uint8_t			 sdi_irq;	/* TODO */
+SIBA_ACCESSOR(vendor,		VENDOR,		uint16_t)
+SIBA_ACCESSOR(device,		DEVICE,		uint16_t)
+SIBA_ACCESSOR(revid,		REVID,		uint8_t)
+SIBA_ACCESSOR(core_index,	CORE_INDEX,	uint8_t)
+
+#undef SIBA_ACCESSOR
+
+/* XXX just for SPROM1? */
+enum {
+	SIBA_CCODE_WORLD,
+	SIBA_CCODE_THAILAND,
+	SIBA_CCODE_ISRAEL,
+	SIBA_CCODE_JORDAN,
+	SIBA_CCODE_CHINA,
+	SIBA_CCODE_JAPAN,
+	SIBA_CCODE_USA_CANADA_ANZ,
+	SIBA_CCODE_EUROPE,
+	SIBA_CCODE_USA_LOW,
+	SIBA_CCODE_JAPAN_HIGH,
+	SIBA_CCODE_ALL,
+	SIBA_CCODE_NONE,
 };
 
-#define siba_read_2(sc, core, reg)				\
-	bus_space_read_2((sc)->sc_bt, (sc)->sc_bh,		\
+#define siba_mips_read_2(sc, core, reg)				\
+	bus_space_read_2((sc)->siba_mem_bt, (sc)->siba_mem_bh,	\
 			 (core * SIBA_CORE_LEN) + (reg))
 
-#define siba_read_4(sc, core, reg)				\
-	bus_space_read_4((sc)->sc_bt, (sc)->sc_bh,		\
+#define siba_mips_read_4(sc, core, reg)				\
+	bus_space_read_4((sc)->siba_mem_bt, (sc)->siba_mem_bh,	\
 			 (core * SIBA_CORE_LEN) + (reg))
 
-#define siba_write_2(sc, core, reg, val)			\
-	bus_space_write_2((sc)->sc_bt, (sc)->sc_bh,		\
+#define siba_mips_write_2(sc, core, reg, val)			\
+	bus_space_write_2((sc)->siba_mem_bt, (sc)->siba_mem_bh,	\
 			 (core * SIBA_CORE_LEN) + (reg), (val))
 
-#define siba_write_4(sc, core, reg, val)			\
-	bus_space_write_4((sc)->sc_bt, (sc)->sc_bh,		\
+#define siba_mips_write_4(sc, core, reg, val)			\
+	bus_space_write_4((sc)->siba_mem_bt, (sc)->siba_mem_bh,	\
 			 (core * SIBA_CORE_LEN) + (reg), (val))
 
-enum siba_device_ivars {
-	SIBA_IVAR_VENDOR,
-	SIBA_IVAR_DEVICE,
-	SIBA_IVAR_REVID,
-	SIBA_IVAR_CORE_INDEX
+#define	SIBA_READ_4(siba, reg)		\
+	bus_space_read_4((siba)->siba_mem_bt, (siba)->siba_mem_bh, (reg))
+#define	SIBA_READ_2(siba, reg)		\
+	bus_space_read_2((siba)->siba_mem_bt, (siba)->siba_mem_bh, (reg))
+#define	SIBA_READ_MULTI_1(siba, reg, addr, count)			\
+	bus_space_read_multi_1((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+#define	SIBA_READ_MULTI_2(siba, reg, addr, count)			\
+	bus_space_read_multi_2((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+#define	SIBA_READ_MULTI_4(siba, reg, addr, count)			\
+	bus_space_read_multi_4((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+
+#define	SIBA_WRITE_4(siba, reg, val)	\
+	bus_space_write_4((siba)->siba_mem_bt, (siba)->siba_mem_bh,	\
+	    (reg), (val))
+#define	SIBA_WRITE_2(siba, reg, val)	\
+	bus_space_write_2((siba)->siba_mem_bt, (siba)->siba_mem_bh,	\
+	    (reg), (val))
+#define	SIBA_WRITE_MULTI_1(siba, reg, addr, count)			\
+	bus_space_write_multi_1((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+#define	SIBA_WRITE_MULTI_2(siba, reg, addr, count)			\
+	bus_space_write_multi_2((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+#define	SIBA_WRITE_MULTI_4(siba, reg, addr, count)			\
+	bus_space_write_multi_4((siba)->siba_mem_bt, (siba)->siba_mem_bh,\
+	    (reg), (addr), (count))
+
+#define	SIBA_BARRIER(siba, flags)					\
+	bus_space_barrier((siba)->siba_mem_bt, (siba)->siba_mem_bh, (0),\
+	    (0), (flags))
+
+#define	SIBA_SETBITS_4(siba, reg, bits)	\
+	SIBA_WRITE_4((siba), (reg), SIBA_READ_4((siba), (reg)) | (bits))
+#define	SIBA_SETBITS_2(siba, reg, bits)	\
+	SIBA_WRITE_2((siba), (reg), SIBA_READ_2((siba), (reg)) | (bits))
+
+#define	SIBA_FILT_SETBITS_4(siba, reg, filt, bits) \
+	SIBA_WRITE_4((siba), (reg), (SIBA_READ_4((siba),	\
+	    (reg)) & (filt)) | (bits))
+#define	SIBA_FILT_SETBITS_2(siba, reg, filt, bits)	\
+	SIBA_WRITE_2((siba), (reg), (SIBA_READ_2((siba),	\
+	    (reg)) & (filt)) | (bits))
+
+#define	SIBA_CLRBITS_4(siba, reg, bits)	\
+	SIBA_WRITE_4((siba), (reg), SIBA_READ_4((siba), (reg)) & ~(bits))
+#define	SIBA_CLRBITS_2(siba, reg, bits)	\
+	SIBA_WRITE_2((siba), (reg), SIBA_READ_2((siba), (reg)) & ~(bits))
+
+#define	SIBA_CC_READ32(scc, offset) \
+	siba_read_4((scc)->scc_dev, offset)
+#define	SIBA_CC_WRITE32(scc, offset, val) \
+	siba_write_4((scc)->scc_dev, offset, val)
+#define	SIBA_CC_MASK32(scc, offset, mask) \
+	SIBA_CC_WRITE32(scc, offset, SIBA_CC_READ32(scc, offset) & (mask))
+#define	SIBA_CC_SET32(scc, offset, set) \
+	SIBA_CC_WRITE32(scc, offset, SIBA_CC_READ32(scc, offset) | (set))
+#define	SIBA_CC_MASKSET32(scc, offset, mask, set)	\
+	SIBA_CC_WRITE32(scc, offset,			\
+	    (SIBA_CC_READ32(scc, offset) & (mask)) | (set))
+
+enum siba_type {
+	SIBA_TYPE_SSB,
+	SIBA_TYPE_PCI,
+	SIBA_TYPE_PCMCIA,
 };
 
-#define	SIBA_ACCESSOR(var, ivar, type)				\
-	__BUS_ACCESSOR(siba, var, SIBA, ivar, type)
+enum siba_clock {
+	SIBA_CLOCK_DYNAMIC,
+	SIBA_CLOCK_SLOW,
+	SIBA_CLOCK_FAST,
+};
 
-SIBA_ACCESSOR(vendor,		VENDOR,		uint16_t)
-SIBA_ACCESSOR(device,		DEVICE,		uint16_t)
-SIBA_ACCESSOR(revid,		REVID,		uint8_t)
-SIBA_ACCESSOR(core_index,	CORE_INDEX,	uint8_t)
+enum siba_clksrc {
+	SIBA_CC_CLKSRC_PCI,
+	SIBA_CC_CLKSRC_CRYSTAL,
+	SIBA_CC_CLKSRC_LOWPW,
+};
 
-#undef SIBA_ACCESSOR
+struct siba_cc_pmu0_plltab {
+	uint16_t		freq;	/* in kHz.*/
+	uint8_t			xf;	/* crystal frequency */
+	uint8_t			wb_int;
+	uint32_t		wb_frac;
+};
 
+struct siba_cc_pmu1_plltab {
+	uint16_t		freq;
+	uint8_t			xf;
+	uint8_t			p1div;
+	uint8_t			p2div;
+	uint8_t			ndiv_int;
+	uint32_t		ndiv_frac;
+};
+
+struct siba_cc_pmu_res_updown {
+	uint8_t			res;
+	uint16_t		updown;
+};
+
+#define	SIBA_CC_PMU_DEP_SET	1
+#define	SIBA_CC_PMU_DEP_ADD	2
+#define	SIBA_CC_PMU_DEP_REMOVE	3
+
+struct siba_cc_pmu_res_depend {
+	uint8_t			res;
+	uint8_t			task;
+	uint32_t		depend;
+};
+
+struct siba_sprom {
+	uint8_t			rev;		/* revision */
+	uint8_t			mac_80211bg[6];	/* address for 802.11b/g */
+	uint8_t			mac_eth[6];	/* address for Ethernet */
+	uint8_t			mac_80211a[6];	/* address for 802.11a */
+	uint8_t			mii_eth0;	/* MII address for eth0 */
+	uint8_t			mii_eth1;	/* MII address for eth1 */
+	uint8_t			mdio_eth0;	/* MDIO for eth0 */
+	uint8_t			mdio_eth1;	/* MDIO for eth1 */
+	uint8_t			brev;		/* board revision */
+	uint8_t			ccode;		/* Country Code */
+	uint8_t			ant_a;		/* A-PHY antenna */
+	uint8_t			ant_bg;		/* B/G-PHY antenna */
+	uint16_t		pa0b0;
+	uint16_t		pa0b1;
+	uint16_t		pa0b2;
+	uint16_t		pa1b0;
+	uint16_t		pa1b1;
+	uint16_t		pa1b2;
+	uint8_t			gpio0;
+	uint8_t			gpio1;
+	uint8_t			gpio2;
+	uint8_t			gpio3;
+	uint16_t		maxpwr_a;	/* A-PHY Max Power */
+	uint16_t		maxpwr_bg;	/* BG-PHY Max Power */
+	uint8_t			tssi_a;		/* Idle TSSI */
+	uint8_t			tssi_bg;	/* Idle TSSI */
+	uint16_t		bf_lo;		/* boardflags */
+	uint16_t		bf_hi;		/* boardflags */
+	struct {
+		struct {
+			int8_t a0, a1, a2, a3;
+		} ghz24;
+		struct {
+			int8_t a0, a1, a2, a3;
+		} ghz5;
+	} again;	/* antenna gain */
+};
+
+struct siba_cc_pmu {
+	uint8_t				rev;	/* PMU rev */
+	uint32_t			freq;	/* crystal freq in kHz */
+};
+
+struct siba_cc {
+	struct siba_dev_softc		*scc_dev;
+	uint32_t			scc_caps;
+	struct siba_cc_pmu		scc_pmu;
+	uint16_t			scc_powerup_delay;
+};
+
+struct siba_pci {
+	struct siba_dev_softc		*spc_dev;
+	uint8_t				spc_inited;
+	uint8_t				spc_hostmode;
+};
+
+struct siba_bus_ops {
+	uint16_t		(*read_2)(struct siba_dev_softc *,
+				    uint16_t);
+	uint32_t		(*read_4)(struct siba_dev_softc *,
+				    uint16_t);
+	void			(*write_2)(struct siba_dev_softc *,
+				    uint16_t, uint16_t);
+	void			(*write_4)(struct siba_dev_softc *,
+				    uint16_t, uint32_t);
+	void			(*read_multi_1)(struct siba_dev_softc *,
+				    void *, size_t, uint16_t);
+	void			(*read_multi_2)(struct siba_dev_softc *,
+				    void *, size_t, uint16_t);
+	void			(*read_multi_4)(struct siba_dev_softc *,
+				    void *, size_t, uint16_t);
+	void			(*write_multi_1)(struct siba_dev_softc *,
+				    const void *, size_t, uint16_t);
+	void			(*write_multi_2)(struct siba_dev_softc *,
+				    const void *, size_t, uint16_t);
+	void			(*write_multi_4)(struct siba_dev_softc *,
+				    const void *, size_t, uint16_t);
+};
+
+struct siba_dev_softc {
+	struct siba_softc		*sd_bus;
+	struct siba_devid		sd_id;
+	const struct siba_bus_ops	*sd_ops;
+
+	uint8_t				sd_coreidx;
+};
+
+struct siba_devinfo {
+	struct resource_list		 sdi_rl;
+	/*devhandle_t			 sdi_devhandle; XXX*/
+	/*struct rman sdi_intr_rman;*/
+
+	/* Accessors are needed for ivars below. */
+	uint16_t			 sdi_vid;
+	uint16_t			 sdi_devid;
+	uint8_t				 sdi_rev;
+	uint8_t				 sdi_idx;	/* core index on bus */
+	uint8_t				 sdi_irq;	/* TODO */
+};
+
+struct siba_softc {
+	/*
+	 * common variables which used for siba(4) bus and siba_bwn bridge.
+	 */
+	device_t			siba_dev;	/* Device ID */
+	struct resource			*siba_mem_res;
+	bus_space_tag_t			siba_mem_bt;
+	bus_space_handle_t		siba_mem_bh;
+	bus_addr_t			siba_maddr;
+	bus_size_t			siba_msize;
+	uint8_t				siba_ncores;
+
+	/*
+	 * the following variables are only used for siba_bwn bridge.
+	 */
+
+	enum siba_type			siba_type;
+	int				siba_invalid;
+
+	struct siba_dev_softc		*siba_curdev;	/* only for PCI */
+	struct siba_dev_softc		siba_devs[SIBA_MAX_CORES];
+	int				siba_ndevs;
+
+	uint16_t			siba_pci_vid;
+	uint16_t			siba_pci_did;
+	uint16_t			siba_pci_subvid;
+	uint16_t			siba_pci_subdid;
+	int				siba_mem_rid;
+
+	uint16_t			siba_chipid;	/* for CORE 0 */
+	uint16_t			siba_chiprev;
+	uint8_t				siba_chippkg;
+
+	struct siba_cc			siba_cc;		/* ChipCommon */
+	struct siba_pci			siba_pci;	/* PCI-core */
+	const struct siba_bus_ops	*siba_ops;
+
+	/* board informations */
+	uint16_t			siba_board_vendor;
+	uint16_t			siba_board_type;
+	uint16_t			siba_board_rev;
+	struct siba_sprom		siba_sprom;	/* SPROM */
+	uint16_t			siba_spromsize;	/* in word size */
+};
+
+void		siba_powerup(struct siba_softc *, int);
+uint16_t	siba_read_2(struct siba_dev_softc *, uint16_t);
+void		siba_write_2(struct siba_dev_softc *, uint16_t, uint16_t);
+uint32_t	siba_read_4(struct siba_dev_softc *, uint16_t);
+void		siba_write_4(struct siba_dev_softc *, uint16_t, uint32_t);
+void		siba_dev_up(struct siba_dev_softc *, uint32_t);
+void		siba_dev_down(struct siba_dev_softc *, uint32_t);
+int		siba_powerdown(struct siba_softc *);
+int		siba_dev_isup(struct siba_dev_softc *);
+void		siba_pcicore_intr(struct siba_pci *, struct siba_dev_softc *);
+uint32_t	siba_dma_translation(struct siba_dev_softc *);
+void		*siba_dma_alloc_consistent(struct siba_dev_softc *, size_t,
+		    bus_addr_t *);
+void		siba_read_multi_1(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+void		siba_read_multi_2(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+void		siba_read_multi_4(struct siba_dev_softc *, void *, size_t,
+		    uint16_t);
+void		siba_write_multi_1(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+void		siba_write_multi_2(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+void		siba_write_multi_4(struct siba_dev_softc *, const void *,
+		    size_t, uint16_t);
+void		siba_barrier(struct siba_dev_softc *, int);
+
 #endif /* _SIBA_SIBAVAR_H_ */

--YiEDa0DAkWCtVeE4--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100127205338.GA28399>