lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 29 Mar 2011 11:40:19 +0200
From:	"Arend van Spriel" <arend@...adcom.com>
To:	linux-kernel@...r.kernel.org, akpm@...ux-foundation.org,
	rmk+kernel@....linux.org.uk
cc:	gregkh@...e.de, linux-wireless@...r.kernel.org,
	devel@...uxdriverproject.org
Subject: [PATCH 1/1] drivers: brcmaxi: provide amba axi functionality in
 separate module

The open-source community is looking for a library which will detect
cores in a chip using axi backplane. This is an initial delivery of
what it could look like. Tested it with the Broadcom open-source
mac80211 wireless driver located in drivers/staging/brcm80211.

Reviewed-by: Randy Dunlap <rdunlap@...otime.net>
Reviewed-by: Henry Ptasinski <henryp@...adcom.com>
Signed-off-by: Arend van Spriel <arend@...adcom.com>
---
 drivers/Kconfig            |    2 +
 drivers/Makefile           |    1 +
 drivers/brcmaxi/Kconfig    |   23 ++
 drivers/brcmaxi/Makefile   |   25 ++
 drivers/brcmaxi/axi.c      |  786 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/brcmaxi/axi_priv.h |   51 +++
 drivers/brcmaxi/pci.c      |  118 +++++++
 include/brcmaxi/amba.h     |   87 +++++
 include/brcmaxi/axi.h      |  310 +++++++++++++++++
 include/brcmaxi/pci.h      |  112 +++++++
 10 files changed, 1515 insertions(+), 0 deletions(-)
 create mode 100644 drivers/brcmaxi/Kconfig
 create mode 100644 drivers/brcmaxi/Makefile
 create mode 100644 drivers/brcmaxi/axi.c
 create mode 100644 drivers/brcmaxi/axi_priv.h
 create mode 100644 drivers/brcmaxi/pci.c
 create mode 100644 include/brcmaxi/amba.h
 create mode 100644 include/brcmaxi/axi.h
 create mode 100644 include/brcmaxi/pci.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 177c7d1..8617526 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -68,6 +68,8 @@ source "drivers/watchdog/Kconfig"
 
 source "drivers/ssb/Kconfig"
 
+source "drivers/brcmaxi/Kconfig"
+
 source "drivers/mfd/Kconfig"
 
 source "drivers/regulator/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index a125e0b..c970b92 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -110,6 +110,7 @@ obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_OF)		+= of/
 obj-$(CONFIG_SSB)		+= ssb/
+obj-$(CONFIG_BRCMAXI)		+= brcmaxi/
 obj-$(CONFIG_VHOST_NET)		+= vhost/
 obj-$(CONFIG_VLYNQ)		+= vlynq/
 obj-$(CONFIG_STAGING)		+= staging/
diff --git a/drivers/brcmaxi/Kconfig b/drivers/brcmaxi/Kconfig
new file mode 100644
index 0000000..d5e384b
--- /dev/null
+++ b/drivers/brcmaxi/Kconfig
@@ -0,0 +1,23 @@
+menuconfig BRCMAXI
+	tristate "Broadcom AXI utility function module"
+	---help---
+	  This module provides utility functions for detecting, enabling,
+	  initializing, and configuring cores on Broadcom chips which are
+	  using the AMBA AXI bus.
+	  
+	  The module is called brcmaxi.ko.
+
+config BRCMAXI_AMBA
+	bool "Broadcom AXI direct access"
+	default y
+	depends on BRCMAXI
+	---help---
+	  Selecting Y here allows direct access to the cores on the AMBA
+	  AXI backplane.
+
+config BRCMAXI_PCI
+	bool "Broadcom AXI over PCI"
+	depends on BRCMAXI
+	---help---
+	  Selecting Y here allows access to cores on AMBA AXI backplane
+	  through the PCI host interface.
diff --git a/drivers/brcmaxi/Makefile b/drivers/brcmaxi/Makefile
new file mode 100644
index 0000000..91f7797
--- /dev/null
+++ b/drivers/brcmaxi/Makefile
@@ -0,0 +1,25 @@
+#
+# Makefile for Broadcom AMBA AXI utility module
+#
+# Copyright (c) 2011 Broadcom Corporation
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+MODULEPFX := brcmaxi
+
+ccflags-$(CONFIG_DEBUG_KERNEL)		+= -DDEBUG
+
+obj-$(CONFIG_BRCMAXI)			+= $(MODULEPFX).o
+
+$(MODULEPFX)-y				+= axi.o
+$(MODULEPFX)-$(CONFIG_BRCMAXI_PCI)	+= pci.o
diff --git a/drivers/brcmaxi/axi.c b/drivers/brcmaxi/axi.c
new file mode 100644
index 0000000..9243d64
--- /dev/null
+++ b/drivers/brcmaxi/axi.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <brcmaxi/axi.h>
+
+#include "axi_priv.h"
+
+#define AXI_DESCRIPTION "Broadcom AXI utility library"
+
+MODULE_DESCRIPTION(AXI_DESCRIPTION);
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* Core enumeration ROM registers */
+#define	ER_EROMENTRY		0x000
+#define	ER_REMAPCONTROL		0xe00
+#define	ER_REMAPSELECT		0xe04
+#define	ER_MASTERSELECT		0xe10
+#define	ER_ITCR			0xf00
+#define	ER_ITIP			0xf04
+
+/* Core enumeration ROM entries */
+#define	ER_TAG			0xe
+#define	ER_TAG1			0x6
+#define	ER_VALID		1
+#define	ER_CI			0
+#define	ER_MP			2
+#define	ER_ADD			4
+#define	ER_END			0xe
+#define	ER_BAD			0xffffffff
+
+/* Core enumeration ROM CompIdentA */
+#define	CIA_MFG_MASK		0xfff00000
+#define	CIA_MFG_SHIFT		20
+#define	CIA_CID_MASK		0x000fff00
+#define	CIA_CID_SHIFT		8
+#define	CIA_CCL_MASK		0x000000f0
+#define	CIA_CCL_SHIFT		4
+
+/* Core enumeration ROM CompIdentB */
+#define	CIB_REV_MASK		0xff000000
+#define	CIB_REV_SHIFT		24
+#define	CIB_NSW_MASK		0x00f80000
+#define	CIB_NSW_SHIFT		19
+#define	CIB_NMW_MASK		0x0007c000
+#define	CIB_NMW_SHIFT		14
+#define	CIB_NSP_MASK		0x00003e00
+#define	CIB_NSP_SHIFT		9
+#define	CIB_NMP_MASK		0x000001f0
+#define	CIB_NMP_SHIFT		4
+
+/* Core enumeration ROM MasterPortDesc */
+#define	MPD_MUI_MASK		0x0000ff00
+#define	MPD_MUI_SHIFT		8
+#define	MPD_MP_MASK		0x000000f0
+#define	MPD_MP_SHIFT		4
+
+/* Core enumeration ROM AddrDesc */
+#define	AD_ADDR_MASK		0xfffff000
+#define	AD_SP_MASK		0x00000f00
+#define	AD_SP_SHIFT		8
+#define	AD_ST_MASK		0x000000c0
+#define	AD_ST_SHIFT		6
+#define	AD_ST_SLAVE		0x00000000
+#define	AD_ST_BRIDGE		0x00000040
+#define	AD_ST_SWRAP		0x00000080
+#define	AD_ST_MWRAP		0x000000c0
+#define	AD_SZ_MASK		0x00000030
+#define	AD_SZ_SHIFT		4
+#define	AD_SZ_4K		0x00000000
+#define	AD_SZ_8K		0x00000010
+#define	AD_SZ_16K		0x00000020
+#define	AD_SZ_SZD		0x00000030
+#define	AD_AG32			0x00000008
+#define	AD_ADDR_ALIGN		0x00000fff
+#define	AD_SZ_BASE		0x00001000	/* 4KB */
+
+/* Core enumeration ROM SizeDesc */
+#define	SD_SZ_MASK		0xfffff000
+#define	SD_SG32			0x00000008
+#define	SD_SZ_ALIGN		0x00000fff
+
+/* resetctrl */
+#define	AIRC_RESET		1
+
+/* definition for specifying padding fields */
+#define	_PADLINE(line)	pad ## line
+#define	_XSTR(line)	_PADLINE(line)
+#define	PAD		_XSTR(__LINE__)
+
+/*
+ * struct aidmp - device management plugin "wrapper" registers.
+ */
+struct aidmp {
+	u32 oobselina30;	/* 0x000 */
+	u32 oobselina74;	/* 0x004 */
+	u32 PAD[6];
+	u32 oobselinb30;	/* 0x020 */
+	u32 oobselinb74;	/* 0x024 */
+	u32 PAD[6];
+	u32 oobselinc30;	/* 0x040 */
+	u32 oobselinc74;	/* 0x044 */
+	u32 PAD[6];
+	u32 oobselind30;	/* 0x060 */
+	u32 oobselind74;	/* 0x064 */
+	u32 PAD[38];
+	u32 oobselouta30;	/* 0x100 */
+	u32 oobselouta74;	/* 0x104 */
+	u32 PAD[6];
+	u32 oobseloutb30;	/* 0x120 */
+	u32 oobseloutb74;	/* 0x124 */
+	u32 PAD[6];
+	u32 oobseloutc30;	/* 0x140 */
+	u32 oobseloutc74;	/* 0x144 */
+	u32 PAD[6];
+	u32 oobseloutd30;	/* 0x160 */
+	u32 oobseloutd74;	/* 0x164 */
+	u32 PAD[38];
+	u32 oobsynca;	/* 0x200 */
+	u32 oobseloutaen;	/* 0x204 */
+	u32 PAD[6];
+	u32 oobsyncb;	/* 0x220 */
+	u32 oobseloutben;	/* 0x224 */
+	u32 PAD[6];
+	u32 oobsyncc;	/* 0x240 */
+	u32 oobseloutcen;	/* 0x244 */
+	u32 PAD[6];
+	u32 oobsyncd;	/* 0x260 */
+	u32 oobseloutden;	/* 0x264 */
+	u32 PAD[38];
+	u32 oobaextwidth;	/* 0x300 */
+	u32 oobainwidth;	/* 0x304 */
+	u32 oobaoutwidth;	/* 0x308 */
+	u32 PAD[5];
+	u32 oobbextwidth;	/* 0x320 */
+	u32 oobbinwidth;	/* 0x324 */
+	u32 oobboutwidth;	/* 0x328 */
+	u32 PAD[5];
+	u32 oobcextwidth;	/* 0x340 */
+	u32 oobcinwidth;	/* 0x344 */
+	u32 oobcoutwidth;	/* 0x348 */
+	u32 PAD[5];
+	u32 oobdextwidth;	/* 0x360 */
+	u32 oobdinwidth;	/* 0x364 */
+	u32 oobdoutwidth;	/* 0x368 */
+	u32 PAD[37];
+	u32 ioctrlset;	/* 0x400 */
+	u32 ioctrlclear;	/* 0x404 */
+	u32 ioctrl;		/* 0x408 */
+	u32 PAD[61];
+	u32 iostatus;	/* 0x500 */
+	u32 PAD[127];
+	u32 ioctrlwidth;	/* 0x700 */
+	u32 iostatuswidth;	/* 0x704 */
+	u32 PAD[62];
+	u32 resetctrl;	/* 0x800 */
+	u32 resetstatus;	/* 0x804 */
+	u32 resetreadid;	/* 0x808 */
+	u32 resetwriteid;	/* 0x80c */
+	u32 PAD[60];
+	u32 errlogctrl;	/* 0x900 */
+	u32 errlogdone;	/* 0x904 */
+	u32 errlogstatus;	/* 0x908 */
+	u32 errlogaddrlo;	/* 0x90c */
+	u32 errlogaddrhi;	/* 0x910 */
+	u32 errlogid;	/* 0x914 */
+	u32 errloguser;	/* 0x918 */
+	u32 errlogflags;	/* 0x91c */
+	u32 PAD[56];
+	u32 intstatus;	/* 0xa00 */
+	u32 PAD[127];
+	u32 config;		/* 0xe00 */
+	u32 PAD[63];
+	u32 itcr;		/* 0xf00 */
+	u32 PAD[3];
+	u32 itipooba;	/* 0xf10 */
+	u32 itipoobb;	/* 0xf14 */
+	u32 itipoobc;	/* 0xf18 */
+	u32 itipoobd;	/* 0xf1c */
+	u32 PAD[4];
+	u32 itipoobaout;	/* 0xf30 */
+	u32 itipoobbout;	/* 0xf34 */
+	u32 itipoobcout;	/* 0xf38 */
+	u32 itipoobdout;	/* 0xf3c */
+	u32 PAD[4];
+	u32 itopooba;	/* 0xf50 */
+	u32 itopoobb;	/* 0xf54 */
+	u32 itopoobc;	/* 0xf58 */
+	u32 itopoobd;	/* 0xf5c */
+	u32 PAD[4];
+	u32 itopoobain;	/* 0xf70 */
+	u32 itopoobbin;	/* 0xf74 */
+	u32 itopoobcin;	/* 0xf78 */
+	u32 itopoobdin;	/* 0xf7c */
+	u32 PAD[4];
+	u32 itopreset;	/* 0xf90 */
+	u32 PAD[15];
+	u32 peripherialid4;	/* 0xfd0 */
+	u32 peripherialid5;	/* 0xfd4 */
+	u32 peripherialid6;	/* 0xfd8 */
+	u32 peripherialid7;	/* 0xfdc */
+	u32 peripherialid0;	/* 0xfe0 */
+	u32 peripherialid1;	/* 0xfe4 */
+	u32 peripherialid2;	/* 0xfe8 */
+	u32 peripherialid3;	/* 0xfec */
+	u32 componentid0;	/* 0xff0 */
+	u32 componentid1;	/* 0xff4 */
+	u32 componentid2;	/* 0xff8 */
+	u32 componentid3;	/* 0xffc */
+};
+
+/* register access macros */
+#ifdef __LITTLE_ENDIAN
+#ifndef __mips__
+#define R_REG(r) \
+	(sizeof(*(r)) == sizeof(u8) ? \
+		readb((volatile u8*)(r)) : \
+	sizeof(*(r)) == sizeof(u16) ? \
+		readw((volatile u16*)(r)) : \
+	readl((volatile u32*)(r)))
+
+#else	/* __mips__ */
+#define R_REG(r) \
+	({ \
+		__typeof(*(r)) __reg_val; \
+		__asm__ __volatile__("sync"); \
+		switch (sizeof(*(r))) { \
+		case sizeof(u8): \
+			__reg_val = readb((volatile u8*)(r)); \
+			break; \
+		case sizeof(u16): \
+			__reg_val = readw((volatile u16*)(r)); \
+			break; \
+		case sizeof(u32): \
+			__reg_val = readl((volatile u32*)(r)); \
+			break; \
+		} \
+		__asm__ __volatile__("sync"); \
+		__reg_val; \
+	})
+#endif	/* __mips__ */
+#define W_REG(r, v) \
+	do { \
+		switch (sizeof(*(r))) { \
+		case sizeof(u8): \
+			writeb((u8)(v), (volatile u8*)(r)); break; \
+		case sizeof(u16): \
+			writew((u16)(v), (volatile u16*)(r)); break; \
+		case sizeof(u32): \
+			writel((u32)(v), (volatile u32*)(r)); break; \
+		} \
+	} while (0)
+#else	/* __LITTLE_ENDIAN */
+#define R_REG(r) \
+	({ \
+		__typeof(*(r)) __reg_val; \
+		switch (sizeof(*(r))) { \
+		case sizeof(u8): \
+			__reg_val = readb((volatile u8*)((r)^3)); \
+			break; \
+		case sizeof(u16): \
+			__reg_val = readw((volatile u16*)((r)^2)); \
+			break; \
+		case sizeof(u32): \
+			__reg_val = readl((volatile u32*)(r)); \
+			break; \
+		} \
+		__reg_val; \
+	})
+#define W_REG(r, v) \
+	do { \
+		switch (sizeof(*(r))) { \
+		case sizeof(u8):	\
+			writeb((u8)(v), \
+			(volatile u8*)((r)^3)); break; \
+		case sizeof(u16):	\
+			writew((u16)(v), \
+			(volatile u16*)((r)^2)); break; \
+		case sizeof(u32):	\
+			writel((u32)(v), \
+			(volatile u32*)(r)); break; \
+		} \
+	} while (0)
+#endif	/* __LITTLE_ENDIAN */
+
+static void *find_core_handler(struct axi_instance *aih,
+			       u32 mfg_id, u32 core_id)
+{
+	const struct axi_core_handler *handler = aih->handler_list;
+	int i;
+
+	for (i = 0; i < aih->num_handler; i++, handler++) {
+		if ((handler->mfg_id != AXI_ANY_ID) &&
+		    (handler->mfg_id != mfg_id))
+			continue;
+		if ((handler->core_id != AXI_ANY_ID) &&
+		    (handler->mfg_id != mfg_id) &&
+		    (handler->core_id != core_id))
+			continue;
+
+		return handler->handler;
+	}
+
+	return NULL;
+}
+
+/*
+ * get_erom_ent - axi core enumeration rom parsing
+ * @eromptr: pointer progressing through enumeration rom.
+ * @mask: mask used on entry to check with provided match.
+ * @match: entry to find in enumeration rom.
+ *
+ * @returns enumeration rom entry
+ */
+static u32
+get_erom_ent(u32 **eromptr, u32 mask, u32 match)
+{
+	u32 ent;
+	uint inv = 0, nom = 0;
+
+	while (true) {
+		ent = R_REG(*eromptr);
+		(*eromptr)++;
+
+		if (mask == 0)
+			break;
+
+		if ((ent & ER_VALID) == 0) {
+			inv++;
+			continue;
+		}
+
+		if (ent == (ER_END | ER_VALID))
+			break;
+
+		if ((ent & mask) == match)
+			break;
+
+		nom++;
+	}
+
+	if (inv + nom) {
+		pr_debug("%d invalid and %d non-matching entries\n",
+		       inv, nom);
+	}
+	pr_debug("%s: Returning ent 0x%08x\n", __func__, ent);
+	return ent;
+}
+
+/*
+ * get_asd - retrieve address descriptor from axi enumeration rom
+ * @eromptr: pointer progressing through enumeration rom.
+ * @sp: slave port for which the descriptor is retrieved.
+ * @ad: address descriptor for which the descriptor is retrieved.
+ * @st: slave type for which the descriptor is retrieved.
+ * @addrl: low part of physical address.
+ * @addrh: high part of physical address.
+ * @sizel: low part of physical area size.
+ * @sizeh: high part of physical area size.
+ */
+static u32
+get_asd(u32 **eromptr, uint sp, uint ad, uint st,
+	u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh)
+{
+	u32 asd, sz, szd;
+
+	asd = get_erom_ent(eromptr, ER_VALID, ER_VALID);
+	if (((asd & ER_TAG1) != ER_ADD) ||
+	    (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
+	    ((asd & AD_ST_MASK) != st)) {
+		/* This is not what we want, "push" it back */
+		(*eromptr)--;
+		return 0;
+	}
+	*addrl = asd & AD_ADDR_MASK;
+	if (asd & AD_AG32)
+		*addrh = get_erom_ent(eromptr, 0, 0);
+	else
+		*addrh = 0;
+	*sizeh = 0;
+	sz = asd & AD_SZ_MASK;
+	if (sz == AD_SZ_SZD) {
+		szd = get_erom_ent(eromptr, 0, 0);
+		*sizel = szd & SD_SZ_MASK;
+		if (szd & SD_SG32)
+			*sizeh = get_erom_ent(eromptr, 0, 0);
+	} else
+		*sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
+
+	pr_debug("  SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
+	       sp, ad, st, *sizeh, *sizel, *addrh, *addrl);
+
+	return asd;
+}
+
+struct axi_local *axi_create(u32 priv_len)
+{
+	struct axi_local *inst;
+	int size = ALIGN(sizeof(*inst), 4) + priv_len;
+
+	inst = kzalloc(size, GFP_ATOMIC);
+	try_module_get(THIS_MODULE);
+
+	return inst;
+}
+struct axi_instance *axi_open(void *regs, u32 erombase, u32 priv_len)
+{
+	struct axi_local *inst = axi_create(priv_len);
+
+	/* fill public fields */
+	inst->pub.regs = regs;
+	inst->pub.priv = (char *)inst + ALIGN(sizeof(*inst), 4);
+
+	inst->enum_rom_ptr = ioremap_nocache((unsigned long)erombase,
+					     AXI_CORE_SIZE);
+
+	return &inst->pub;
+}
+
+void axi_close(struct axi_instance *aih)
+{
+	kfree(aih);
+	module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL(axi_close);
+
+int axi_scan(struct axi_instance *aih)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = NULL;
+	u32 *eromlim, *eromptr = ail->enum_rom_ptr;
+	int numcores = 0;
+
+	eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32));
+
+	pr_debug("axi_scan: erom: ptr = 0x%p, limit = 0x%p\n",
+		 eromptr, eromlim);
+
+	while (eromptr < eromlim) {
+		bool (*handler)(struct axi_instance *ai, struct axi_core *core);
+		u32 cia, cib, cid, mfg, crev;
+		u32 n_master_wrap, n_slave_wrap, n_master_port, n_slave_port;
+		u32 mst_port_desc, addr_space_desc, addrl, addrh, sizel, sizeh;
+		u32 *base;
+		uint i, j;
+		bool br;
+
+		br = false;
+		core = NULL;
+
+		/* Grok a component */
+		cia = get_erom_ent(&eromptr, ER_TAG, ER_CI);
+		if (cia == (ER_END | ER_VALID)) {
+			pr_debug("Found END of erom after %d cores\n",
+				 numcores);
+			return numcores;
+		}
+		base = eromptr - 1;
+		cib = get_erom_ent(&eromptr, 0, 0);
+
+		if ((cib & ER_TAG) != ER_CI) {
+			pr_err("CIA not followed by CIB\n");
+			return 0;
+		}
+
+		cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
+		mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
+		crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+		n_master_wrap = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
+		n_slave_wrap = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
+		n_master_port = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
+		n_slave_port = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
+
+		pr_debug("Found component 0x%04x/0x%04x rev %d at "
+		       "erom addr 0x%p, with nmw = %d, nsw = %d, nmp = %d & "
+		       "nsp = %d\n", mfg, cid, crev, base, n_master_wrap,
+		       n_slave_wrap, n_master_port, n_slave_port);
+
+		/* ??ignore processor core?? */
+		if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) ||
+		    (n_slave_port == 0))
+			continue;
+
+		/* alloc space to store core information */
+		core = kzalloc(sizeof(struct axi_core), GFP_ATOMIC);
+		if (!core)
+			return 0;
+
+		core->id = cid;
+		core->mfg = mfg;
+		core->rev = crev;
+
+		if ((n_master_wrap + n_slave_wrap) == 0) {
+			/* A component which is not a core */
+			if (cid == OOB_ROUTER_CORE_ID) {
+				addr_space_desc = get_asd(&eromptr, 0, 0,
+					AD_ST_SLAVE, &addrl, &addrh,
+					&sizel, &sizeh);
+				if (addr_space_desc != 0) {
+					core->phys_address = addrl;
+					handler = find_core_handler(aih,
+								     mfg, cid);
+					if (!handler ||
+					    handler(aih, core) == true) {
+						kfree(core);
+					}
+				} else {
+					kfree(core);
+				}
+			}
+			continue;
+		}
+
+		for (i = 0; i < n_master_port; i++) {
+			mst_port_desc =
+				get_erom_ent(&eromptr, ER_VALID, ER_VALID);
+			if ((mst_port_desc & ER_TAG) != ER_MP) {
+				pr_err("Not enough MP entries for "
+				       "component 0x%x\n", cid);
+				goto error;
+			}
+			pr_debug("  Master port %d, mp: %d id: %d\n", i,
+				 (mst_port_desc & MPD_MP_MASK) >> MPD_MP_SHIFT,
+				 (mst_port_desc & MPD_MUI_MASK) >> MPD_MUI_SHIFT
+			);
+		}
+
+		/* First Slave Address Descriptor should be port 0:
+		 * the main register space for the core
+		 */
+		addr_space_desc =
+		    get_asd(&eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh,
+			    &sizel, &sizeh);
+		if (addr_space_desc == 0) {
+			/* Try again to see if it is a bridge */
+			addr_space_desc =
+			    get_asd(&eromptr, 0, 0, AD_ST_BRIDGE, &addrl,
+				    &addrh, &sizel, &sizeh);
+			if (addr_space_desc != 0)
+				br = true;
+			else if ((addrh != 0) || (sizeh != 0)
+				 || (sizel != AXI_CORE_SIZE)) {
+				pr_err("First Slave ASD for core "
+				       "0x%04x malformed (0x%08x)\n",
+				       cid, addr_space_desc);
+				goto error;
+			}
+		}
+
+		core->phys_address = addrl;
+		core->phys_space = sizel;
+
+		/* Get any more ASDs in port 0 */
+		j = 1;
+		do {
+			addr_space_desc =
+			    get_asd(&eromptr, 0, j, AD_ST_SLAVE, &addrl,
+				    &addrh, &sizel, &sizeh);
+			if ((addr_space_desc != 0) && (j == 1) &&
+			    (sizel == AXI_CORE_SIZE)) {
+				core->sec_phys_address = addrl;
+				core->sec_phys_space = sizel;
+			}
+			j++;
+		} while (addr_space_desc != 0);
+
+		/* Go through the ASDs for other slave ports */
+		for (i = 1; i < n_slave_port; i++) {
+			j = 0;
+			do {
+				addr_space_desc =
+				    get_asd(&eromptr, i, j++, AD_ST_SLAVE,
+					    &addrl, &addrh, &sizel, &sizeh);
+			} while (addr_space_desc != 0);
+			if (j == 0) {
+				pr_err("SP %d has no address "
+				       "descriptors\n", i);
+				goto error;
+			}
+		}
+
+		/* Now get master wrappers */
+		for (i = 0; i < n_master_wrap; i++) {
+			addr_space_desc =
+			    get_asd(&eromptr, i, 0, AD_ST_MWRAP, &addrl,
+				    &addrh, &sizel, &sizeh);
+			if (addr_space_desc == 0) {
+				pr_err("Missing descriptor for MW %d\n"
+				       , i);
+				goto error;
+			}
+			if ((sizeh != 0) || (sizel != AXI_CORE_SIZE)) {
+				pr_err("Master wrapper %d is not 4KB\n"
+				       , i);
+				goto error;
+			}
+			if (i == 0)
+				core->wrap_phys_address = addrl;
+		}
+
+		/* And finally slave wrappers */
+		for (i = 0; i < n_slave_wrap; i++) {
+			uint fwp = (n_slave_port == 1) ? 0 : 1;
+			addr_space_desc =
+			    get_asd(&eromptr, fwp + i, 0, AD_ST_SWRAP,
+				    &addrl, &addrh, &sizel, &sizeh);
+			if (addr_space_desc == 0) {
+				pr_err("Missing descriptor for SW %d\n", i);
+				goto error;
+			}
+			if ((sizeh != 0) || (sizel != AXI_CORE_SIZE)) {
+				pr_err("Slave wrapper %d is not 4KB\n", i);
+				goto error;
+			}
+			if ((n_master_wrap == 0) && (i == 0))
+				core->wrap_phys_address = addrl;
+		}
+
+		/* Don't record bridges */
+		if (br)
+			continue;
+
+		/* first core is current core */
+		pci_axi_set_curcore(aih, core);
+
+		/* Done with core */
+		handler = find_core_handler(aih, mfg, cid);
+		if (handler && handler(aih, core) == false)
+			numcores++;
+		else
+			kfree(core);
+	}
+
+	pr_err("Reached end of erom without finding END");
+
+error:
+	kfree(core);
+	return 0;
+}
+EXPORT_SYMBOL(axi_scan);
+
+bool axi_iscoreup(struct axi_core *core)
+{
+	struct aidmp *ai;
+
+	ai = core->wrap;
+
+	return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) ==
+		 SICF_CLOCK_EN)
+		&& ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0));
+}
+
+void axi_core_disable(struct axi_core *core, u32 bits)
+{
+	volatile u32 dummy;
+	struct aidmp *ai;
+
+	ai = core->wrap;
+
+	/* if core is already in reset, just return */
+	if (R_REG(&ai->resetctrl) & AIRC_RESET)
+		return;
+
+	W_REG(&ai->ioctrl, bits);
+	dummy = R_REG(&ai->ioctrl);
+	udelay(10);
+
+	W_REG(&ai->resetctrl, AIRC_RESET);
+	udelay(1);
+}
+
+void axi_core_reset(struct axi_core *core, u32 bits, u32 resetbits)
+{
+	struct aidmp *ai;
+	volatile u32 dummy;
+
+	ai = core->wrap;
+
+	/*
+	 * Must do the disable sequence first to work for
+	 * arbitrary current core state.
+	 */
+	axi_core_disable(core, (bits | resetbits));
+
+	/*
+	 * Now do the initialization sequence.
+	 */
+	W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
+	dummy = R_REG(&ai->ioctrl);
+	W_REG(&ai->resetctrl, 0);
+	udelay(1);
+
+	W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN));
+	dummy = R_REG(&ai->ioctrl);
+	udelay(1);
+}
+
+uint axi_flag(struct axi_core *core)
+{
+	struct aidmp *ai;
+
+	/* TODO: what is with BCM47162 DMP */
+	ai = core->wrap;
+
+	return R_REG(&ai->oobselouta30) & 0x1f;
+}
+
+u32 axi_core_cflags(struct axi_core *core, u32 mask, u32 val)
+{
+	struct aidmp *ai;
+	u32 w;
+
+	/* TODO: what is with BCM47162 DMP */
+	ai = core->wrap;
+
+	WARN_ON((val & ~mask) == 0);
+
+	if (mask || val) {
+		w = ((R_REG(&ai->ioctrl) & ~mask) | val);
+		W_REG(&ai->ioctrl, w);
+	}
+
+	return R_REG(&ai->ioctrl);
+}
+
+u32 axi_core_sflags(struct axi_core *core, u32 mask, u32 val)
+{
+	struct aidmp *ai;
+	u32 w;
+
+	/* TODO: what is with BCM47162 DMP */
+	ai = core->wrap;
+
+	WARN_ON((val & ~mask) == 0);
+	WARN_ON((mask & ~SISF_CORE_BITS) == 0);
+
+	if (mask || val) {
+		w = ((R_REG(&ai->iostatus) & ~mask) | val);
+		W_REG(&ai->iostatus, w);
+	}
+
+	return R_REG(&ai->iostatus);
+}
+
+#ifdef CONFIG_BRCMAXI_AMBA
+EXPORT_SYMBOL(axi_open);
+EXPORT_SYMBOL(axi_iscoreup);
+EXPORT_SYMBOL(axi_core_disable);
+EXPORT_SYMBOL(axi_core_reset);
+EXPORT_SYMBOL(axi_flag);
+EXPORT_SYMBOL(axi_core_cflags);
+EXPORT_SYMBOL(axi_core_sflags);
+#endif
+
+static int __init axi_init(void)
+{
+	pr_info(AXI_DESCRIPTION "\n");
+	return 0;
+}
+
+static void __exit axi_exit(void)
+{
+}
+
+module_init(axi_init);
+module_exit(axi_exit);
diff --git a/drivers/brcmaxi/axi_priv.h b/drivers/brcmaxi/axi_priv.h
new file mode 100644
index 0000000..c2b64f8
--- /dev/null
+++ b/drivers/brcmaxi/axi_priv.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef AXI_PRIV_H_
+#define AXI_PRIV_H_
+
+#include <brcmaxi/axi.h>
+
+/*
+ * struct axi_local - internal instance data
+ *
+ * @pub: &struct axi_instance pointer to public instance data.
+ * @curcore: &struct axi_core pointer to active core.
+ * @bustype: enum axi_bus referring to type of bus between axi and caller.
+ * @enum_rom_ptr: pointer to system discovery enumeration rom.
+ */
+struct axi_local {
+	struct axi_instance pub;
+#ifdef CONFIG_BRCMAXI_PCI
+	struct axi_core *curcore;
+#endif
+	u32 *enum_rom_ptr;
+};
+
+extern struct axi_local *axi_create(u32 priv_len);
+
+#ifdef CONFIG_BRCMAXI_PCI
+static inline void pci_axi_set_curcore(struct axi_instance *aih,
+					      struct axi_core *core)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	if (ail->curcore == NULL)
+		ail->curcore = core;
+}
+#else
+#define pci_axi_set_curcore(a,b)
+#endif
+
+#endif /* AXI_PRIV_H_ */
diff --git a/drivers/brcmaxi/pci.c b/drivers/brcmaxi/pci.c
new file mode 100644
index 0000000..f706806
--- /dev/null
+++ b/drivers/brcmaxi/pci.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/pci.h>
+#include <brcmaxi/axi.h>
+#include <brcmaxi/amba.h>
+
+#include "axi_priv.h"
+
+/* backplane address space accessed by BAR0 */
+#define	PCI_BAR0_WIN		0x80
+/* backplane address space accessed by second 4KB of BAR0 */
+#define	PCI_BAR0_WIN2		0xac
+
+struct axi_instance *pci_axi_open(void *pbus, void *regs,
+				  u32 erombase, u32 priv_len)
+{
+	struct axi_local *inst = axi_create(priv_len);
+
+	/* fill public fields */
+	inst->pub.pbus = pbus;
+	inst->pub.regs = regs;
+	inst->pub.priv = (char *)inst + ALIGN(sizeof(*inst), 4);
+
+	/* Now point the window at the core enumeration rom */
+	pci_write_config_dword(inst->pub.pbus, PCI_BAR0_WIN, erombase);
+	inst->enum_rom_ptr = regs;
+
+	return &inst->pub;
+}
+EXPORT_SYMBOL(pci_axi_open);
+
+void *pci_axi_set_active_core(struct axi_instance *aih, struct axi_core *ach)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+
+	u32 addr = ach->phys_address;
+	u32 wrap = ach->sec_phys_address;
+
+	/* point bar0 window */
+	pci_write_config_dword(aih->pbus, PCI_BAR0_WIN, addr);
+	ach->regs = ail->curcore->regs;
+	/* point bar0 2nd 4KB window */
+	pci_write_config_dword(aih->pbus, PCI_BAR0_WIN2, wrap);
+	ach->wrap = ail->curcore->wrap;
+
+	ail->curcore = ach;
+
+	return ach->regs;
+}
+EXPORT_SYMBOL(pci_axi_set_active_core);
+
+bool pci_axi_iscoreup(struct axi_instance *aih)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	return axi_iscoreup(core);
+}
+EXPORT_SYMBOL(pci_axi_iscoreup);
+
+void pci_axi_core_disable(struct axi_instance *aih, u32 bits)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	axi_core_disable(core, bits);
+}
+EXPORT_SYMBOL(pci_axi_core_disable);
+
+void pci_axi_core_reset(struct axi_instance *aih, u32 bits, u32 resetbits)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	axi_core_reset(core, bits, resetbits);
+}
+EXPORT_SYMBOL(pci_axi_core_reset);
+
+uint pci_axi_flag(struct axi_instance *aih)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	return axi_flag(core);
+}
+EXPORT_SYMBOL(pci_axi_flag);
+
+u32 pci_axi_core_cflags(struct axi_instance *aih, u32 mask, u32 val)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	return axi_core_cflags(core, mask, val);
+}
+EXPORT_SYMBOL(pci_axi_core_cflags);
+
+u32 pci_axi_core_sflags(struct axi_instance *aih, u32 mask, u32 val)
+{
+	struct axi_local *ail = (struct axi_local *)aih;
+	struct axi_core *core = ail->curcore;
+
+	return axi_core_sflags(core, mask, val);
+}
+EXPORT_SYMBOL(pci_axi_core_sflags);
diff --git a/include/brcmaxi/amba.h b/include/brcmaxi/amba.h
new file mode 100644
index 0000000..5940cb6
--- /dev/null
+++ b/include/brcmaxi/amba.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef AXI_AMBA_H_
+#define AXI_AMBA_H_
+
+/**
+ * axi_open - create instance.
+ * @regs: pointer to currently mapped register area.
+ * @erom_base: physical address where core enumeration rom is located.
+ * @priv_size: additional memory appended to instance for caller to use.
+ *
+ * Creates the instance filling in the provided details.
+ */
+struct axi_instance *axi_open(void *regs, u32 erom_base, u32 priv_size);
+/**
+ * axi_iscoreup - indicates core is reset and enabled.
+ * @core: &struct axi_core pointer to core of interest.
+ *
+ * Indicates whether the given core has reset and is enabled.
+ */
+bool axi_iscoreup(struct axi_core *core);
+/**
+ * axi_core_disable - disable the core.
+ * @core: &struct axi_core pointer to core of interest.
+ * @bits: core specific bits that are set during reset sequence.
+ *
+ * Disables the given core by reset. This will bring the core in
+ * the disabled state. Initialization is required to enable it again.
+ */
+void axi_core_disable(struct axi_core *core, u32 bits);
+/**
+ * axi_core_reset - reset and enable the core.
+ * @core: &struct axi_core pointer to core of interest.
+ * @bits: core specific bits that are set during and after the reset sequence.
+ * @resetbits: core specific bits that are set only during reset sequence.
+ *
+ * Resets and enables the given core.
+ */
+void axi_core_reset(struct axi_core *core, u32 bits, u32 resetbits);
+/**
+ * axi_flag - get axi flag.
+ * @core: &struct axi_core pointer to core of interest.
+ *
+ * Retrieves the axi flag for the given core.
+ */
+uint axi_flag(struct axi_core *core);
+/**
+ * axi_core_cflags - set core control flags.
+ * @core: &struct axi_core pointer to core of interest.
+ * @mask: mask indicating the bits to clear.
+ * @val: value with bits to set. bits must be within mask.
+ *
+ * Set I/O control flags for the given core. The function returns
+ * the resulting value of the control flags. When called with with
+ * mask and val parameters being 0 the current control flags are
+ * returned.
+ */
+u32 axi_core_cflags(struct axi_core *core, u32 mask, u32 val);
+/**
+ * axi_core_sflags - set core status flags.
+ * @core: &struct axi_core pointer to core of interest.
+ * @mask: mask indicating the bits to clear.
+ * @val: value with bits to set. bits must be within mask.
+ *
+ * Set I/O status flags for the given core. The function returns
+ * the resulting value of the status flags. When called with with
+ * mask and val parameters being 0 the current status flags are
+ * returned.
+ */
+u32 axi_core_sflags(struct axi_core *core, u32 mask, u32 val);
+
+#endif /* AXI_AMBA_H_ */
diff --git a/include/brcmaxi/axi.h b/include/brcmaxi/axi.h
new file mode 100644
index 0000000..f470312
--- /dev/null
+++ b/include/brcmaxi/axi.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef AXI_H_
+#define AXI_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/**
+ * DOC: Introduction
+ *
+ * brcmaxi provides detection of chip cores in chipsets using the AMBA AXI
+ * on-chip interconnect. It also provides basic functions to operate these
+ * cores and obtain/modify common core control and status flags.
+ */
+/**
+ * DOC: Host Interface Support
+ *
+ * The module provides two selectable intefaces. Direct access and by means
+ * of PCI host interface. For access by PCI bus you should use function prefixed
+ * by pci_ instead.
+ */
+/**
+ * DOC: Chip System Discovery
+ *
+ * The discovery of cores in the chip is done parsing through an enumeration
+ * rom located on the chip. After using the @axi_open() function by which the
+ * calling code provides the type of bus present between calling code and the
+ * enumeration rom, physical base address of the enumeration rom and virtual
+ * address of currently mapped memory, the calling code needs to provide a
+ * table of handlers using the macro @AXI_SET_HANDLERS. The argument should
+ * be declared using the macro @AXI_CORE_HANDLER_TABLE. The actual scan is
+ * initiated by calling @axi_scan().
+ *
+ * The user-provided handlers are called for each core that matches.
+ *
+ * NOTE: currently matching is only based on manufacturer and/or core ID.
+ */
+/**
+ * DOC: Core Utility Functions
+ *
+ * When accessing the cores directly over the AMBA AXI backplane the function
+ * with axi_core_ prefix should be used providing the core instance on which
+ * you want to perform the given function. For accessing the cores over a PCI
+ * interface you should use the pci_axi_core_ functions, which are operating on
+ * an active core. This is selected by using @pci_axi_set_active_core(). Before
+ * calling this function the calling code must assure that interrupts from the
+ * currently active core are disabled.
+ *
+ * The mechanism for PCI is needed as for this interface the BAR register window
+ * is changed and the virtual addresses for accessing the cores is the same for
+ * each core.
+ */
+/*
+ * Manufacturer Ids
+ */
+#define	MFGID_ARM			0x43b
+#define	MFGID_BRCM			0x4bf
+#define	MFGID_MIPS			0x4a7
+
+/*
+ * Component Classes
+ *
+ * This is used to have a more specific core identification.
+ */
+#define	CC_SIM				0
+#define	CC_EROM				1
+#define	CC_CORESIGHT			9
+#define	CC_VERIF			0xb
+#define	CC_OPTIMO			0xd
+#define	CC_GEN				0xe
+#define	CC_PRIMECELL			0xf
+
+/* Core Codes */
+#define	NODEV_CORE_ID		0x700	/* Invalid coreid */
+#define	CC_CORE_ID		0x800	/* chipcommon core */
+#define	ILINE20_CORE_ID		0x801	/* iline20 core */
+#define	SRAM_CORE_ID		0x802	/* sram core */
+#define	SDRAM_CORE_ID		0x803	/* sdram core */
+#define	PCI_CORE_ID		0x804	/* pci core */
+#define	MIPS_CORE_ID		0x805	/* mips core */
+#define	ENET_CORE_ID		0x806	/* enet mac core */
+#define	CODEC_CORE_ID		0x807	/* v90 codec core */
+#define	USB_CORE_ID		0x808	/* usb 1.1 host/device core */
+#define	ADSL_CORE_ID		0x809	/* ADSL core */
+#define	ILINE100_CORE_ID	0x80a	/* iline100 core */
+#define	IPSEC_CORE_ID		0x80b	/* ipsec core */
+#define	UTOPIA_CORE_ID		0x80c	/* utopia core */
+#define	PCMCIA_CORE_ID		0x80d	/* pcmcia core */
+#define	SOCRAM_CORE_ID		0x80e	/* internal memory core */
+#define	MEMC_CORE_ID		0x80f	/* memc sdram core */
+#define	OFDM_CORE_ID		0x810	/* OFDM phy core */
+#define	EXTIF_CORE_ID		0x811	/* external interface core */
+#define	D11_CORE_ID		0x812	/* 802.11 MAC core */
+#define	APHY_CORE_ID		0x813	/* 802.11a phy core */
+#define	BPHY_CORE_ID		0x814	/* 802.11b phy core */
+#define	GPHY_CORE_ID		0x815	/* 802.11g phy core */
+#define	MIPS33_CORE_ID		0x816	/* mips3302 core */
+#define	USB11H_CORE_ID		0x817	/* usb 1.1 host core */
+#define	USB11D_CORE_ID		0x818	/* usb 1.1 device core */
+#define	USB20H_CORE_ID		0x819	/* usb 2.0 host core */
+#define	USB20D_CORE_ID		0x81a	/* usb 2.0 device core */
+#define	SDIOH_CORE_ID		0x81b	/* sdio host core */
+#define	ROBO_CORE_ID		0x81c	/* roboswitch core */
+#define	ATA100_CORE_ID		0x81d	/* parallel ATA core */
+#define	SATAXOR_CORE_ID		0x81e	/* serial ATA & XOR DMA core */
+#define	GIGETH_CORE_ID		0x81f	/* gigabit ethernet core */
+#define	PCIE_CORE_ID		0x820	/* pci express core */
+#define	NPHY_CORE_ID		0x821	/* 802.11n 2x2 phy core */
+#define	SRAMC_CORE_ID		0x822	/* SRAM controller core */
+#define	MINIMAC_CORE_ID		0x823	/* MINI MAC/phy core */
+#define	ARM11_CORE_ID		0x824	/* ARM 1176 core */
+#define	ARM7S_CORE_ID		0x825	/* ARM7tdmi-s core */
+#define	LPPHY_CORE_ID		0x826	/* 802.11a/b/g phy core */
+#define	PMU_CORE_ID		0x827	/* PMU core */
+#define	SSNPHY_CORE_ID		0x828	/* 802.11n single-stream phy core */
+#define	SDIOD_CORE_ID		0x829	/* SDIO device core */
+#define	ARMCM3_CORE_ID		0x82a	/* ARM Cortex M3 core */
+#define	HTPHY_CORE_ID		0x82b	/* 802.11n 4x4 phy core */
+#define	MIPS74K_CORE_ID		0x82c	/* mips 74k core */
+#define	GMAC_CORE_ID		0x82d	/* Gigabit MAC core */
+#define	DMEMC_CORE_ID		0x82e	/* DDR1/2 memory controller core */
+#define	PCIERC_CORE_ID		0x82f	/* PCIE Root Complex core */
+#define	OCP_CORE_ID		0x830	/* OCP2OCP bridge core */
+#define	SC_CORE_ID		0x831	/* shared common core */
+#define	AHB_CORE_ID		0x832	/* OCP2AHB bridge core */
+#define	SPIH_CORE_ID		0x833	/* SPI host core */
+#define	I2S_CORE_ID		0x834	/* I2S core */
+#define	DMEMS_CORE_ID		0x835	/* SDR/DDR1 memory controller core */
+#define	DEF_SHIM_COMP		0x837	/* SHIM component in ubus/6362 */
+#define OOB_ROUTER_CORE_ID	0x367	/* OOB router core ID */
+#define	DEF_AI_COMP		0xfff	/* Default component, in ai chips it
+					 * maps all unused address ranges
+					 */
+
+#define AXI_CORE_SIZE		0x1000	/* each core has 4Kbytes registers */
+
+/* match for all values */
+#define AXI_ANY_ID		(~0)
+
+/*
+ * Common core control flags
+ *
+ * used in axi_core_cflags().
+ */
+#define	SICF_BIST_EN		0x8000
+#define	SICF_PME_EN		0x4000
+#define	SICF_CORE_BITS		0x3ffc
+#define	SICF_FGC		0x0002
+#define	SICF_CLOCK_EN		0x0001
+
+/*
+ * Common core status flags
+ *
+ * used in axi_core_sflags().
+ */
+#define	SISF_BIST_DONE		0x8000
+#define	SISF_BIST_ERROR		0x4000
+#define	SISF_GATED_CLK		0x2000
+#define	SISF_DMA64		0x1000
+#define	SISF_CORE_BITS		0x0fff
+
+/**
+ * struct axi_core - core information
+ * @mfg: manufacturer identifier (JEDEC JEP106).
+ * @id: component identifier (manufacturer assigned).
+ * @rev: core revision.
+ * @phys_address: physical backplane address.
+ * @phys_space: size of the area starting at phys_address.
+ * @sec_phys_address: physical backplane address of 2nd register set.
+ * @sec_phys_space: size of the area starting at sec_phys_address.
+ * @wrap_phys_address: physical backplane address of DMP wrapper registers.
+ * @regs: virtual address of mapped phys_address.
+ * @wrap: virtual address of mapped wrap_phys_address.
+ *
+ * The Manufacturer identifier is maintained by JEDEC. For more info refer to
+ * following webpage infocenter.arm.com/help/topic/com.arm.doc.faqs/ka14408.html
+ */
+struct axi_core {
+	u32	mfg;
+	u32	id;
+	u32	rev;
+	u32	phys_address;
+	u32	phys_space;
+	u32	sec_phys_address;
+	u32	sec_phys_space;
+	u32	wrap_phys_address;
+
+	void	*regs;
+	void	*wrap;
+};
+
+/*
+ * forward declaration for handler in axi_core_handler structure.
+ */
+struct axi_instance;
+
+/**
+ * struct axi_core_handler - associates a core with handler callback function
+ * @handler: callback function called for matching core.
+ * @mfg_id: manufacturer identifier of the core.
+ * @core_id: core identifier of the core.
+ * @core_class: component class of the core.
+ *
+ * The structure is to be used by the calling driver to provide a table
+ * of cores which is to be used during the AXI core scan. It is preferred
+ * to use the AXI_CORE_* macros and AXI_SET_CORE_HANDLERS macro.
+ */
+struct axi_core_handler {
+	bool (*handler)(struct axi_instance *ai, struct axi_core *core);
+	u32 mfg_id;
+	u32 core_id;
+	u32 core_class;
+};
+
+/*
+ * example:
+ *
+ * AXI_CORE_HANDLER_TABLE(drv_table) = {
+ * 	{ AXI_CORE(MFGID_MIPS, MIPS74K_CORE_ID, mips74k_handler) },
+ * 	{ AXI_CORE(MFGID_BRCM, D11_CORE_ID, brcm80211_d11core) },
+ * 	{ AXI_CORE(AXI_ANY_ID, AXI_ANY_ID, debug_axi_handler) }
+ * };
+ * The last entry uses the AXI_ANY_ID. The core matching function
+ * will iterate in sequence through the table so any entries after
+ * this one will be rendered useless.
+ */
+#define AXI_CORE_HANDLER_TABLE(_table) \
+	static const struct axi_core_handler _table[]
+
+#define AXI_CORE(mfg, core, _handler) \
+	.handler = (_handler), .core_id = (core), \
+	.mfg_id = (mfg), .core_class = AXI_ANY_ID
+
+#define AXI_CORE_CLASS(mfg, core, _class, _handler) \
+	.handler = (_handler), .core_id = (core) \
+	.mfg_id = (mfg), .core_class = (_class)
+
+#define AXI_SET_CORE_HANDLERS(aih, _table) \
+	axi_set_core_handlers((aih), ARRAY_SIZE(_table), _table)
+
+/**
+ * struct axi_instance - instance data
+ * @pbus: bus access object (ie. struct pci_dev pointer for PCI bus).
+ * @regs: currently mapped register space.
+ * @handler_list: list of handlers for detected cores during axi_scan().
+ * @num_handler: number of handler entries in the handler_list.
+ * @priv: pointer to memory space that can be used by calling driver.
+ */
+struct axi_instance {
+	const struct axi_core_handler *handler_list;
+	size_t num_handler;
+	void *regs;
+#ifdef CONFIG_BRCMAXI_PCI
+	void *pbus;
+#endif
+	void *priv;
+};
+
+/**
+ * axi_set_core_handlers - sets table of handler used in axi_scan()
+ * @aih: &struct axi_instance pointer to instance data.
+ * @n_handler: number of entries in the given handler list.
+ * @list: &struct axi_core_handler pointer to list of handlers.
+ *
+ * Instead of calling this function directly it is recommended to
+ * use the macro AXI_SET_CORE_HANDLERS.
+ */
+static inline void axi_set_core_handlers(struct axi_instance *aih,
+					 size_t n_handler,
+					 const struct axi_core_handler *list)
+{
+	aih->num_handler = n_handler;
+	aih->handler_list = list;
+}
+
+/**
+ * axi_close - release the instance.
+ * @aih: &struct axi_instance pointer to the instance.
+ */
+void axi_close(struct axi_instance *aih);
+/**
+ * axi_scan - scan the chipset for cores.
+ * @aih: &struct axi_instance pointer to the instance.
+ */
+int axi_scan(struct axi_instance *aih);
+
+#ifdef CONFIG_BRCMAXI_AMBA
+#include "amba.h"
+#endif
+#ifdef CONFIG_BRCMAXI_PCI
+#include "pci.h"
+#endif
+
+#endif /* AXI_H_ */
diff --git a/include/brcmaxi/pci.h b/include/brcmaxi/pci.h
new file mode 100644
index 0000000..76d81b8
--- /dev/null
+++ b/include/brcmaxi/pci.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef AXI_PCI_H_
+#define AXI_PCI_H_
+
+/**
+ * pci_axi_open - create instance.
+ * @pbus: pointer to bus device structure.
+ * @regs: pointer to currently mapped register area.
+ * @erom_base: physical address where core enumeration rom is located.
+ * @priv_size: additional memory appended to instance for caller to use.
+ *
+ * Creates the instance filling in the provided details.
+ */
+struct axi_instance *pci_axi_open(void *pbus, void *regs,
+				  u32 erom_base, u32 priv_size);
+/**
+ * pci_axi_close - wrapper for @axi_close()
+ * @inst: &struct axi_instance pointer to the instance.
+ *
+ * Just to keep the same naming convention.
+ */
+static inline void pci_axi_close(struct axi_instance *inst)
+{
+	axi_close(inst);
+}
+/**
+ * axi_set_active_core - activate given core.
+ * @aih: &struct axi_instance pointer to the instance.
+ * @ach: pointer to core to be activated.
+ *
+ * Activating a core will have the other operations
+ * be acted upon the core activated here.
+ */
+void *pci_axi_set_active_core(struct axi_instance *aih, struct axi_core *ach);
+/**
+ * axi_iscoreup - indicates core is reset and enabled.
+ * @aih: &struct axi_instance pointer to the instance.
+ *
+ * Indicates whether the active core has reset and is enabled.
+ * Active core is set using @axi_set_active_core().
+ */
+bool pci_axi_iscoreup(struct axi_instance *aih);
+/**
+ * axi_core_disable - disable the core.
+ * @aih: &struct axi_instance pointer to the instance.
+ * @bits: core specific bits that are set during reset sequence.
+ *
+ * Disables the active core by reset. This will bring the core in
+ * the disabled state. Initialization is required to enable it again.
+ * Active core is set using @axi_set_active_core().
+ */
+void pci_axi_core_disable(struct axi_instance *aih, u32 bits);
+/**
+ * axi_core_reset - reset and enable the core.
+ * @aih: &struct axi_instance pointer to the instance.
+ * @bits: core specific bits that are set during and after the reset sequence.
+ * @resetbits: core specific bits that are set only during reset sequence.
+ *
+ * Resets and enables the active core. Active core is set
+ * using @axi_set_active_core().
+ */
+void pci_axi_core_reset(struct axi_instance *aih, u32 bits, u32 resetbits);
+/**
+ * axi_flag - get axi flag.
+ * @aih: &struct axi_instance pointer to the instance.
+ *
+ * Retrieves the axi flag for the active core. Active core is set
+ * using @axi_set_active_core().
+ */
+uint pci_axi_flag(struct axi_instance *aih);
+/**
+ * axi_core_cflags - set core control flags.
+ * @aih: &struct axi_instance pointer to the instance.
+ * @mask: mask indicating the bits to clear.
+ * @val: value with bits to set. bits must be within mask.
+ *
+ * Set I/O control flags for the active core. Active core is set
+ * using @axi_set_active_core(). The function returns the resulting
+ * value of the control flags. When called with with mask and val
+ * parameters being 0 the current control flags are returned.
+ */
+u32 pci_axi_core_cflags(struct axi_instance *aih, u32 mask, u32 val);
+/**
+ * axi_core_sflags - set core status flags.
+ * @aih: &struct axi_instance pointer to the instance.
+ * @mask: mask indicating the bits to clear.
+ * @val: value with bits to set. bits must be within mask.
+ *
+ * Set I/O status flags for the active core. Active core is set
+ * using @axi_set_active_core(). The function returns the resulting
+ * value of the status flags. When called with with mask and val
+ * parameters being 0 the current status flags are returned.
+ */
+u32 pci_axi_core_sflags(struct axi_instance *aih, u32 mask, u32 val);
+
+#endif /* AXI_PCI_H_ */
-- 
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ