[PATCH 1/1] drivers: brcmaxi: provide amba axi functionality inseparate module

From: Arend van Spriel
Date: Tue Mar 29 2011 - 05:40:44 EST


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@xxxxxxxxxxxx>
Reviewed-by: Henry Ptasinski <henryp@xxxxxxxxxxxx>
Signed-off-by: Arend van Spriel <arend@xxxxxxxxxxxx>
---
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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/