All of lore.kernel.org
 help / color / mirror / Atom feed
From: 21cnbao@gmail.com (Barry Song)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] ARM: prima2: add NetWork on Chip driver for atlas7
Date: Mon,  9 Mar 2015 14:05:07 +0800	[thread overview]
Message-ID: <1425881107-4597-1-git-send-email-21cnbao@gmail.com> (raw)

From: Guo Zeng <Guo.Zeng@csr.com>

CSR atlas7 uses a NoC bus, SoC is splitted into mutiple MACROs. Every MACRO
holds some hardware modules.
All the devices connected to NoC MRCROs are described using sub-node to this MARCO.
For  example, AUDMSCM MARCO includes multimediam nodes such as KAS, AC97, IACC, I2S,
USP0~3, LVDS etc.
For each MARCO, there is at least a firewall sub-node. This firewall can detect
illegal hardware access for security protection.
For CPU access, an external abort will generate for it; for other DMA access,
interrupts will trigger to CPU. In the abort and interrupt handlers, we can dump
the status.

Signed-off-by: Guo Zeng <Guo.Zeng@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
---
 .../devicetree/bindings/bus/atlas7-noc.txt         |  34 +
 arch/arm/mach-prima2/Kconfig                       |   8 +
 arch/arm/mach-prima2/Makefile                      |   2 +
 arch/arm/mach-prima2/common.c                      |   8 +
 arch/arm/mach-prima2/common.h                      |   6 +
 arch/arm/mach-prima2/noc.c                         | 931 +++++++++++++++++++++
 6 files changed, 989 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/atlas7-noc.txt
 create mode 100644 arch/arm/mach-prima2/noc.c

diff --git a/Documentation/devicetree/bindings/bus/atlas7-noc.txt b/Documentation/devicetree/bindings/bus/atlas7-noc.txt
new file mode 100644
index 0000000..449ddb5
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/atlas7-noc.txt
@@ -0,0 +1,34 @@
+Device tree bindings for CSRatlas7 NoC(Network on Chip)
+
+CSR atlas7 uses a NoC bus, SoC is splitted into mutiple MACROs. Every MACRO
+holds some hardware modules. For each MACRO
+properties:
+- compatible : Should be "arteris, flexnoc"
+- #address-cells: should be 1
+- #size-cells: should be 1
+- ranges : the child address space are mapped 1:1 onto the parent address space
+
+Sub-nodes:
+All the devices connected to noc are described using sub-node to noc. For
+example, AUDMSCM MARCO includes multimediam nodes such as KAS, AC97, IACC, I2S,
+USP0~3, LVDS.
+For each MARCO, there is at least a firewall sub-node. This firewall can detect
+illegal hardware access for security protection.
+
+Firewall sub-nodes:
+properties:
+- compatible : Should be one of
+	"sirf,nocfw-cpum",
+	"sirf,nocfw-cgum",
+	"sirf,nocfw-btm",
+	"sirf,nocfw-gnssm",
+	"sirf,nocfw-gpum",
+	"sirf,nocfw-mediam",
+	"sirf,nocfw-vdifm",
+	"sirf,nocfw-audiom",
+	"sirf,nocfw-ddrm",
+	"sirf,nocfw-rtcm",
+	"sirf,nocfw-dramfw",
+	"sirf,nocfw-spramfw"
+- reg: A resource specifier for the register space
+- interrupts : Should be the interrupt number - optional
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
index e03d8b5..ed868d1 100644
--- a/arch/arm/mach-prima2/Kconfig
+++ b/arch/arm/mach-prima2/Kconfig
@@ -41,4 +41,12 @@ config ARCH_PRIMA2
 config SIRF_IRQ
 	bool
 
+config ATLAS7DA_NOC
+        bool "CSR A7DA NOC"
+        default y
+	help
+          Support CSR SiRFSoC A7DA Platform NOC bus, with security dram/reg
+          firewall and related configure for validation, with errlog shown
+          on data abort or interrupt handler when bus transaction failed.
+
 endif
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index d7d02b0..1248418 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -2,6 +2,8 @@ obj-y += rstc.o
 obj-y += common.o
 obj-y += rtciobrg.o
 obj-$(CONFIG_SUSPEND) += pm.o sleep.o
+
+obj-$(CONFIG_ATLAS7DA_NOC) += noc.o
 obj-$(CONFIG_SMP) += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)  += hotplug.o
 
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index 8cadb30..4a9dcad 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -15,6 +15,13 @@
 #include <linux/of_platform.h>
 #include "common.h"
 
+static void __init sirfsoc_init_mach(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	sirfsoc_noc_init();
+}
+
 static void __init sirfsoc_init_late(void)
 {
 	sirfsoc_pm_init();
@@ -60,6 +67,7 @@ static const char *const atlas7_dt_match[] __initconst = {
 DT_MACHINE_START(ATLAS7_DT, "Generic ATLAS7 (Flattened Device Tree)")
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
 	.smp            = smp_ops(sirfsoc_smp_ops),
+	.init_machine   = sirfsoc_init_mach,
 	.dt_compat      = atlas7_dt_match,
 MACHINE_END
 #endif
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 3916a66..122d8f9 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -28,4 +28,10 @@ extern int sirfsoc_pm_init(void);
 static inline int sirfsoc_pm_init(void) { return 0; }
 #endif
 
+#ifdef CONFIG_ATLAS7DA_NOC
+extern int sirfsoc_noc_init(void);
+#else
+static inline void sirfsoc_noc_init(void) { return 0; }
+#endif
+
 #endif
diff --git a/arch/arm/mach-prima2/noc.c b/arch/arm/mach-prima2/noc.c
new file mode 100644
index 0000000..2c74121
--- /dev/null
+++ b/arch/arm/mach-prima2/noc.c
@@ -0,0 +1,931 @@
+/*
+* Atlas7 NoC support
+*/
+
+#define pr_fmt(fmt) "NoC: " fmt
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <asm/signal.h>
+
+#define NOC_CPUM_ERRLOG   0x800
+#define NOC_CPUM_FAULTEN  0x900
+
+#define NOC_AUDMSCM_ERRLOG  0xC00
+#define NOC_AUDMSCM_FAULTEN 0x400
+
+
+#define NOC_DDRM_ERRLOG  0x180
+#define NOC_DDRM_FAULTEN 0x800
+
+
+#define NOC_RTCM_ERRLOG  0xA00
+#define NOC_RTCM_FAULTEN 0x900
+
+
+
+#define ERRORLOGGER_0_ID_COREID   0x0
+#define ERRORLOGGER_0_ID_REVISIONID 0x4
+#define ERRORLOGGER_0_FAULTEN   0x8
+#define ERRORLOGGER_0_ERRVLD       0xc
+#define ERRORLOGGER_0_ERRCLR  0x10
+#define ERRORLOGGER_0_ERRLOG0 0x14
+#define ERRORLOGGER_0_ERRLOG1 0x18
+#define ERRORLOGGER_0_ERRLOG3 0x20
+#define ERRORLOGGER_0_ERRLOG5 0x28
+
+#define NOC_SB_FAULTEN 0x08
+#define NOC_SB_FLAGINEN0 0x10
+
+#define FLAGS_CPU	BIT(0)
+#define FLAGS_STRICT	BIT(1)
+#define FLAGS_NS	BIT(2)
+#define FLAGS_S		BIT(3)
+#define FLAGS_INITIATOR_NS  BIT(4)
+#define FLAGS_INITIATOR_S   BIT(5)
+
+
+#define CPUMASK_KAS   3
+#define CPUMASK_CM3   2
+#define CPUMASK_CSSI   1
+#define CPUMASK_CA7   0
+
+#define ACCESS_READ      BIT(0)
+#define ACCESS_WRITE      BIT(1)
+#define ACCESS_INITIATOR_READ      BIT(2)
+#define ACCESS_INITIATOR_WRITE      BIT(3)
+
+
+#define FW_RP_ENABLE_SET   0x3F04
+
+struct sirfsoc_nocfw_dram_t {
+	u32 rpbase;
+	u32 startaddr;
+	u32 endaddr;
+	u32 initiator;
+	u32 access;
+	u32 initiator_access;
+	u32 rpnum;
+	u32 flags;
+};
+
+struct dramfw_regs_access_t {
+	u32 initiator_r_set;
+	u32 initiator_r_clr;
+	u32 initiator_w_set;
+	u32 initiator_w_clr;
+};
+
+
+/* dram fw */
+struct dramfw_regs_t {
+	u32 start;
+	u32 end;
+	u32 reserved_0[2];
+	struct dramfw_regs_access_t access[4];
+	u32 reserved_1[4];
+	u32 fw_cpu_set;
+	u32 fw_cpu_clr;
+	u32 reserved_2[2];
+	u32 prot_set;
+	u32 prot_clr;
+	u32 prot_val_set;
+	u32 prot_val_clr;
+	u32 target_set;
+	u32 target_clr;
+	u32 target_val_set;
+	u32 target_val_clr;
+};
+
+/* reg fw */
+struct regfw_regs_t {
+	u32 ns_set;
+	u32 ns_clr;
+	u32 ns_sts;
+	u32 a7_set;
+	u32 a7_clr;
+	u32 a7_sts;
+	u32 cssi_set;
+	u32 cssi_clr;
+	u32 cssi_sts;
+	u32 m3_set;
+	u32 m3_clr;
+	u32 m3_sts;
+	u32 kas_set;
+	u32 kas_clr;
+	u32 kas_sts;
+};
+
+struct sirfsoc_nocfw_reg_t {
+	u32 base;
+	u32 off;
+	u32 ns;
+	u32 a7;
+
+	u32 cssi;
+	u32 m3;
+	u32 kas;
+};
+
+#define ddrm_SecureState_ReadSet0    0x1050
+#define ddrm_SecureState_ReadClr0    0x1054
+#define ddrm_SecureState_ReadSts0    0x1058
+
+#define ddrm_SecureState_ReadSet1    0x105C
+#define ddrm_SecureState_ReadClr1    0x1060
+#define ddrm_SecureState_ReadSts1    0x1064
+
+#define ddrm_SecureState_ReadSet2    0x1068
+#define ddrm_SecureState_ReadClr2    0x106C
+#define ddrm_SecureState_ReadSts2    0x1070
+
+#define ddrm_SecureState_ReadSet3    0x1074
+#define ddrm_SecureState_ReadClr3    0x1078
+#define ddrm_SecureState_ReadSts3    0x107C
+
+
+#define ddrm_SecureState_WriteSet0    0x1080
+#define ddrm_SecureState_WriteClr0    0x1084
+#define ddrm_SecureState_WriteSts0    0x1088
+
+#define ddrm_SecureState_WriteSet1    0x108C
+#define ddrm_SecureState_WriteClr1    0x1090
+#define ddrm_SecureState_WriteSts1    0x1094
+
+#define ddrm_SecureState_WriteSet2    0x1098
+#define ddrm_SecureState_WriteClr2    0x109C
+#define ddrm_SecureState_WriteSts2    0x10A0
+
+#define ddrm_SecureState_WriteSet3    0x10A4
+#define ddrm_SecureState_WriteClr3    0x10A8
+#define ddrm_SecureState_WriteSts3    0x10AC
+
+struct dramfw_reg_secure_t {
+	u32 readset;
+	u32 readclr;
+	u32 writeset;
+	u32 writeclr;
+};
+
+static struct dramfw_reg_secure_t dramfw_reg_secure_list[] = {
+	{ddrm_SecureState_ReadSet0, ddrm_SecureState_ReadClr0,
+		ddrm_SecureState_WriteSet0, ddrm_SecureState_WriteClr0},
+	{ddrm_SecureState_ReadSet1, ddrm_SecureState_ReadClr1,
+		ddrm_SecureState_WriteSet1, ddrm_SecureState_WriteClr1},
+	{ddrm_SecureState_ReadSet2, ddrm_SecureState_ReadClr2,
+		ddrm_SecureState_WriteSet2, ddrm_SecureState_WriteClr2},
+	{ddrm_SecureState_ReadSet3, ddrm_SecureState_ReadClr3,
+		ddrm_SecureState_WriteSet3, ddrm_SecureState_WriteClr3}
+};
+
+struct noc_info_t {
+	const char *desc;
+};
+
+static struct noc_info_t noc_initator_id_list[] = {
+	{"dmac2_ac97_aux_fifo"},
+	{"kas_dram"},
+	{"afe_cvd_vip0"},
+	{"usp0_axi_i"},
+	{"sgx"},
+	{"sdr"},
+	{"dmac2_usp1rx"},
+	{"dmac2_usp1tx"},
+	{"usb0"},
+	{"usb1"},
+	{"dmac2_usp0rx"},
+	{"dmac2_usp0tx"},
+	{"dmac2_usp2rx"},
+	{"dmac2_usp2tx"},
+	{"reserved"},
+	{"reserved"},
+	{"dmac3_iaccrx"},
+	{"dmac3_i2s1rx"},
+	{"dmac3_i2s1tx"},
+	{"dmac3_iacctx2"},
+	{"reserved"},
+	{"reserved"},
+	{"dmac3_ac97rx_fifo"},
+	{"dmac3_iacctx0"},
+	{"dmac3_iacctx1"},
+	{"dmac3_iacctx3"},
+	{"dmac3_ac97tx_fifo5"},
+	{"dmac3_ac97tx_fifo6"},
+	{"dmac3_ac97tx_fifo1"},
+	{"dmac3_ac97tx_fifo2"},
+	{"dmac3_ac97tx_fifo3"},
+	{"dmac3_ac97tx_fifo4"},
+	{"dmac4_usp3rx"},
+	{"dmac4_usp3tx"},
+	{"vpp0"},
+	{"vpp1"},
+	{"vip1"},
+	{"dcu"},
+	{"g2d"},
+	{"nand"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"dmac4_uart6rx"},
+	{"dmac4_uart6tx"},
+	{"reserved"},
+	{"reserved"},
+	{"dmac0_uart4rx"},
+	{"dmac0_uart4tx"},
+	{"dmac0_uart0tx"},
+	{"dmac0_uart0rx"},
+	{"dmac0_uart3rx"},
+	{"dmac0_uart3tx"},
+	{"dmac0_uart2rx"},
+	{"dmac0_uart2tx"},
+	{"dmac0_uart5rx"},
+	{"dmac0_uart5tx"},
+	{"sec_secure"},
+	{"sec_public"},
+	{"dmac0_spi1rx"},
+	{"dmac0_spi1tx"},
+	{"reserved"},
+	{"reserved"},
+	{"sys2pci_vdifm"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"sys2pci_mediam"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"armm3_data"},
+	{"qspi"},
+	{"hash"},
+	{"cssi_etr_axi"},
+	{"eth_avb"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"lcd0_ly0_rd"},
+	{"lcd0_ly1_rd"},
+	{"lcd0_ly2_rd"},
+	{"lcd0_ly3_rd"},
+	{"lcd0_wb_rd"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"lcd1_ly1_rd"},
+	{"lcd1_ly1_rd"},
+	{"lcd1_ly2_rd"},
+	{"lcd1_ly3_rd"},
+	{"lcd1_wb_rd"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"vxd_mmu"},
+	{"vxd_dmac"},
+	{"vxd_vec"},
+	{"vxd_dmc"},
+	{"vxd_deb"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"jpeg_tar"},
+	{"jpeg_code"},
+	{"jpeg_thumb"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+};
+
+enum NOC_MACRO_IDX {
+	CPUM_IDX = 0,
+	CGUM_IDX,
+	BTM_IDX,
+	GNSSM_IDX,
+	GPUM_IDX,
+	MEDIAM_IDX,
+	VDIFM_IDX,
+	AUDIOM_IDX,
+	DDRM_IDX,
+	RTCM_IDX,
+	DRAMFW_IDX,
+	SPRFW_IDX,
+};
+
+/*register firewall offset based on macro index*/
+static u32 noc_regfw_offset_list[10] = {0x1050, 0x50, 0x1050, 0x1050,
+		0x1050, 0x1050, 0x2050, 0x2050, 0x2050, 0x2050};
+
+/*dram firewall sched port:six*/
+#define FW_A7 0x0
+#define FW_DDR_BE 0x4000
+#define FW_DDR_RTLL 0x8000
+#define FW_DDR_RT   0xC000
+#define FW_DDR_SGX 0x10000
+#define FW_DDR_VXD 0x14000
+
+#define NOC_MACRO_NUM 12
+#define NOC_MACRO_NAME_LEN 12
+
+struct noc_macro {
+	void __iomem *mbase;
+	spinlock_t		lock;
+	u32 idx;
+	u32 irq;
+	u32 errlogoff;
+	u32 faultenoff;
+	char name[NOC_MACRO_NAME_LEN];
+	int (*init_macro)(struct platform_device *);
+};
+
+static int noc_macro_init(struct platform_device *);
+static int noc_spram_firewall_init(struct platform_device *);
+static int noc_dram_firewall_init(struct platform_device *);
+static int noc_a7_init(struct platform_device *);
+
+static struct noc_macro noc_macro_list[] = {
+	{
+		.name = "cpum",
+		.idx = CPUM_IDX,
+		.errlogoff = NOC_CPUM_ERRLOG,
+		.faultenoff = NOC_CPUM_FAULTEN,
+		.init_macro = noc_a7_init,
+	}, {
+		.name = "cgum",
+		.idx = CGUM_IDX,
+	}, {
+		.name = "btm",
+		.idx = BTM_IDX,
+	}, {
+		.name = "gnssm",
+		.idx = GNSSM_IDX,
+	}, {
+		.name = "gpum",
+		.idx = GPUM_IDX,
+	}, {
+		.name = "mediam",
+		.idx = MEDIAM_IDX,
+	}, {
+		.name = "vdifm",
+		.idx = VDIFM_IDX,
+	}, {
+		.name = "audiom",
+		.idx = AUDIOM_IDX,
+		.errlogoff = NOC_AUDMSCM_ERRLOG,
+		.faultenoff = NOC_AUDMSCM_FAULTEN,
+		.init_macro = noc_macro_init,
+	}, {
+		.name = "ddrm",
+		.idx = DDRM_IDX,
+		.errlogoff = NOC_DDRM_ERRLOG,
+		.faultenoff = NOC_DDRM_FAULTEN,
+		.init_macro = noc_macro_init,
+	}, {
+		.name = "rtcm",
+		.idx = RTCM_IDX,
+		.errlogoff = NOC_RTCM_ERRLOG,
+		.faultenoff = NOC_RTCM_FAULTEN,
+		.init_macro = noc_macro_init,
+	}, {
+		.name = "dramfw",
+		.idx = DRAMFW_IDX,
+		.init_macro = noc_dram_firewall_init,
+	}, {
+		.name = "spramfw",
+		.idx = SPRFW_IDX,
+		.init_macro = noc_spram_firewall_init,
+	},
+};
+
+
+
+struct noc_dram_params_t {
+	void __iomem *mbase;
+	u32 startaddr;
+	u32 endaddr;
+	u32 initiator;
+	u32 access;
+	u32 initiator_access;
+	u32 rpnum;
+	u32 flags;
+};
+
+#define to_noc_fw_inf(d) container_of(d, struct noc_fw_inf, dev)
+
+static struct noc_info_t noc_err_list[] = {
+	{"target error detected by slave"},
+	{"address decode error"},
+	{"unsupported request"},
+	{"power disconnect"},
+	{"security violation"},
+	{"hidden security violation"},
+	{"timout"},
+	{"reserved"},
+};
+
+static struct noc_info_t noc_cpu_list[] = {
+	{"A7"},
+	{"coresight"},
+	{"M3"},
+	{"KAS"},
+};
+
+static struct noc_info_t noc_opc_list[] = {
+	{"read"},
+	{"wrap read"},
+	{"link read"},
+	{"exclusive read"},
+	{"write"},
+	{"wrap write"},
+	{"condition write"},
+	{"reserved"},
+	{"preable packet"},
+	{"urgency packet"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+	{"reserved"},
+};
+/*data abort handler can not get base list*/
+
+static int noc_has_err(void __iomem *noc_errlog_mbase)
+{
+	u32 vld;
+
+	vld = readl_relaxed(noc_errlog_mbase + ERRORLOGGER_0_ERRVLD);
+	vld &= 0x1;
+	/* 1 indicates an error has been logged (default: 0x0) */
+	return vld;
+}
+
+static int noc_dump_errlog(struct noc_macro *nocm)
+{
+	u32 errCode0, errCode1, errCode3, errCode5, vld;
+	void __iomem *noc_errlog_mbase;
+
+	if (!nocm)
+		goto err;
+
+	noc_errlog_mbase = (void __iomem *)(nocm->mbase + nocm->errlogoff);
+
+	/*return 1 for normal abort handler */
+	vld = noc_has_err(noc_errlog_mbase);
+	if (0 == vld)
+		goto err;
+
+	errCode0 = readl_relaxed(noc_errlog_mbase + ERRORLOGGER_0_ERRLOG0);
+	errCode1 = readl_relaxed(noc_errlog_mbase + ERRORLOGGER_0_ERRLOG1);
+	errCode3 = readl_relaxed(noc_errlog_mbase + ERRORLOGGER_0_ERRLOG3);
+	errCode5 = readl_relaxed(noc_errlog_mbase + ERRORLOGGER_0_ERRLOG5);
+
+	/*error type*/
+	pr_info("err:\t%s\n", noc_err_list[(errCode0>>8) & 0x7].desc);
+
+	/*initiator id*/
+	if (nocm->idx == CPUM_IDX)
+		pr_info("ID:\t%s\n", noc_cpu_list[(errCode5>>3) & 0x3].desc);
+	else	if (0 == (errCode5 & 0x1))
+		pr_info("ID:\t%s\n", noc_cpu_list[(errCode5>>2) & 0x3].desc);
+	else
+		pr_info("ID:\%s\n", noc_initator_id_list[(errCode5>>7 & 0x1F)
+				| ((errCode5>>2 & 0x3)<<5)].desc);
+
+	pr_info("Opc:\t%s\n", noc_opc_list[(errCode0>>1) & 0xF].desc);
+	pr_info("Addr\t%08x\n", errCode3);
+	pr_info("Len\t%08x\n", errCode0>>16 & 0x3F);
+
+	/* clear the NoC errlog */
+	writel_relaxed(0x1, noc_errlog_mbase + ERRORLOGGER_0_ERRCLR);
+
+	return 0;
+err:
+	return 1;
+}
+static int noc_abort_handler(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	int ret;
+
+	ret = noc_dump_errlog(&noc_macro_list[CPUM_IDX]);
+	if (0 != ret)
+		return 1;
+	/*
+	* If it was not an imprecise abort (Bit10==0),
+	* then we need to correct the
+	* return address to be _after_ the instruction.
+	*/
+	if (!(fsr & (1 << 10)))
+		regs->ARM_pc += 4;
+
+	return 0;
+}
+
+/* handler noc audio macro interrupt */
+static irqreturn_t noc_irq_handle(int irq, void *data)
+{
+	struct noc_macro *nocm = (struct noc_macro *)data;
+
+	noc_dump_errlog(nocm);
+	return IRQ_HANDLED;
+}
+
+static void  noc_fault_enable(struct noc_macro *nocm)
+{
+	writel_relaxed(0x1, nocm->mbase +
+		nocm->faultenoff + NOC_SB_FAULTEN);
+	/*
+	 *rtcm_sb_main_SidebandManager_FlagInEn0
+	 *0  StatAlarm  rtcm_probe  Statistics alarm
+	 *1  Fault  rtcm_observer  Error logging event
+	 */
+	writel_relaxed(0x3, nocm->mbase +
+		nocm->faultenoff + NOC_SB_FLAGINEN0);
+	writel_relaxed(0x1, nocm->mbase +
+		nocm->errlogoff + ERRORLOGGER_0_FAULTEN);
+}
+
+static void noc_dramfw_cpu_set(void __iomem *fw_cpu_clr,
+			void __iomem *fw_cpu_set, u32 initiator, u32 access)
+{
+	/*
+	 * clear all except r_CA7 and w_CA7,set r_CA7 and w_CA7
+	 * r_KAS r_CM3 r_CSSI r_CA7 w_KAS w_CM3 w_CSSI w_CA7
+	 */
+	writel_relaxed(0xFFFFFFFF, fw_cpu_clr);
+	if (access & ACCESS_READ)
+		writel_relaxed(1<<(initiator+4), fw_cpu_set);
+
+	if (access & ACCESS_WRITE)
+		writel_relaxed(1<<initiator, fw_cpu_set);
+}
+
+static void noc_dramfw_noncpu_acess_set(struct dramfw_regs_t *base,
+		void __iomem *ddrm_addr, u32 initiator, u32 access,
+		u32 initiator_access, u32 flags)
+{
+	u32 i = 0;
+	u32 val;
+
+	/* non-cpu initiator */
+	for (i = 0; i < 4; i++) {
+		writel_relaxed(0xFFFFFFFF,
+				&base->access[i].initiator_r_clr);
+		writel_relaxed(0xFFFFFFFF,
+				&base->access[i].initiator_w_clr);
+	}
+
+	i = initiator / 32;
+	val = 1<<(initiator - 32 * i);
+	/* dram access read/write */
+	if (access & ACCESS_READ)
+		writel_relaxed(val, &base->access[i].initiator_r_set);
+	if (access & ACCESS_WRITE)
+		writel_relaxed(val, &base->access[i].initiator_w_set);
+
+	/* initiator access read/write */
+	if (initiator_access & ACCESS_INITIATOR_READ) {
+		if (FLAGS_INITIATOR_S & flags)
+			writel_relaxed(val,
+				ddrm_addr +
+				dramfw_reg_secure_list[i].readclr);
+		else if (FLAGS_INITIATOR_NS & flags)
+			writel_relaxed(val,
+				ddrm_addr +
+			dramfw_reg_secure_list[i].readset);
+	}
+	if (initiator_access & ACCESS_INITIATOR_WRITE) {
+		if (FLAGS_INITIATOR_S & flags)
+			writel_relaxed(val,
+				ddrm_addr +
+			dramfw_reg_secure_list[i].writeclr);
+		else if (FLAGS_INITIATOR_NS & flags)
+			writel_relaxed(val,
+				ddrm_addr +
+			dramfw_reg_secure_list[i].writeset);
+	}
+}
+static void noc_dramfw_noncpu_secure_set(struct dramfw_regs_t *base,
+		u32 access, u32 flags)
+{
+	/*
+	 *clear AxPROT[0] and AxPROT[2] enable,set AxPROT[1]
+	 * arprot_2 arprot_1 arprot_0 r.awprot_2 awprot_1 awprot_0
+	 */
+	writel_relaxed(0x00000077, &base->prot_clr);
+	writel_relaxed(0x000000FF, &base->prot_val_clr);
+
+	/*
+	 * r_strict	arprot_2 arprot_1 arprot_0 w_strict
+	 *awprot_2 awprot_1 awprot_0
+	 */
+
+	if (access & ACCESS_READ) {
+		writel_relaxed(0x00000020, &base->prot_set);
+
+		if (FLAGS_STRICT & flags)
+			writel_relaxed(0x00000080, &base->prot_val_set);
+
+		if (FLAGS_NS & flags)
+			writel_relaxed(0x00000020, &base->prot_val_set);
+	}
+
+	if (access & ACCESS_WRITE) {
+		writel_relaxed(0x00000002, &base->prot_set);
+
+		if (FLAGS_STRICT & flags)
+			writel_relaxed(0x00000008, &base->prot_val_set);
+
+		if (FLAGS_NS & flags)
+			writel_relaxed(0x00000002, &base->prot_val_set);
+
+	}
+}
+
+static void noc_dramfw_set(struct noc_dram_params_t *params)
+{
+	struct dramfw_regs_t *base;
+	struct noc_macro *nocm;
+	void __iomem *mbase;
+	u32 startaddr;
+	u32 endaddr;
+	u32 initiator;
+	u32 access;
+	u32 initiator_access;
+	u32 rpnum;
+	u32 flags;
+
+	if (!params)
+		return;
+
+	mbase = params->mbase;
+	startaddr = params->startaddr;
+	endaddr = params->endaddr;
+	initiator = params->initiator;
+	access = params->access;
+	initiator_access = params->initiator_access;
+	rpnum = params->rpnum;
+	flags = params->flags;
+
+	base = (struct dramfw_regs_t *)(mbase +
+		0x100 * rpnum);
+
+	initiator &= 0xFF;
+
+	writel_relaxed(startaddr, &base->start);
+	writel_relaxed(endaddr, &base->end);
+
+	if (flags & FLAGS_CPU)
+		noc_dramfw_cpu_set(&base->fw_cpu_clr,
+			&base->fw_cpu_set, initiator, access);
+	else {
+		nocm = &noc_macro_list[DDRM_IDX];
+		noc_dramfw_noncpu_acess_set(base,
+				nocm->mbase,
+				initiator, access, initiator_access, flags);
+	}
+	noc_dramfw_noncpu_secure_set(base, access, flags);
+
+	/* last step enable rp */
+	writel_relaxed(1<<rpnum, mbase + FW_RP_ENABLE_SET);
+}
+
+static void noc_regfw_setval(void __iomem *addr_clr,
+			void __iomem *addr_set, u32 val)
+{
+	writel_relaxed(0xFFFFFFFF, addr_clr);
+	writel_relaxed(val, addr_set);
+}
+
+static void noc_regfw_set(void __iomem *mbase, u32 off, u32 ns,
+				u32 a7, u32 cssi, u32 m3, u32 kas)
+{
+	struct regfw_regs_t *base;
+
+	if (!mbase)
+		return;
+
+	base = (struct regfw_regs_t *)(mbase + off);
+	noc_regfw_setval(&base->ns_clr, &base->ns_set, ns);
+	noc_regfw_setval(&base->a7_clr, &base->a7_set, a7);
+	noc_regfw_setval(&base->m3_clr, &base->m3_set, m3);
+	noc_regfw_setval(&base->cssi_clr, &base->cssi_set, cssi);
+	noc_regfw_setval(&base->kas_clr, &base->kas_set, kas);
+}
+
+static ssize_t dramfw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct noc_dram_params_t params;
+	struct noc_macro *nocm;
+	u32 schedport_off;
+
+	if (sscanf(buf, "%x %x %x %x %x %x %x %x\n",
+				&schedport_off, &params.startaddr,
+				&params.endaddr, &params.initiator,
+				&params.access, &params.initiator_access,
+				&params.rpnum, &params.flags) != 8)
+		return -EINVAL;
+
+	nocm = &noc_macro_list[DRAMFW_IDX];
+	params.mbase = nocm->mbase + schedport_off;
+
+	noc_dramfw_set(&params);
+	return len;
+}
+static DEVICE_ATTR_WO(dramfw);
+
+static ssize_t spramfw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct noc_macro *nocm;
+	struct noc_dram_params_t params;
+
+	if (sscanf(buf, "%x %x %x %x %x %x %x\n",
+				&params.startaddr, &params.endaddr,
+				&params.initiator, &params.access,
+				&params.initiator_access,
+				&params.rpnum, &params.flags) != 7)
+
+		return -EINVAL;
+	nocm = &noc_macro_list[SPRFW_IDX];
+	params.mbase = nocm->mbase;
+	noc_dramfw_set(&params);
+	return len;
+}
+static DEVICE_ATTR_WO(spramfw);
+
+static ssize_t regfw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct noc_macro *nocm;
+
+	u32 idx, ns, a7, cssi, m3, kas;
+
+	if (sscanf(buf, "%x %x %x %x %x %x\n", &idx, &ns, &a7,
+				&cssi, &m3, &kas) != 6 || idx > 9)
+		return -EINVAL;
+
+	nocm = &noc_macro_list[idx];
+	noc_regfw_set(nocm->mbase,
+			noc_regfw_offset_list[idx], ns, a7, cssi, m3, kas);
+	return len;
+}
+
+static DEVICE_ATTR_WO(regfw);
+
+
+static const struct of_device_id sirfsoc_nocfw_ids[] = {
+	{ .compatible = "sirf,nocfw-cpum", .data = &noc_macro_list[0] },
+	{ .compatible = "sirf,nocfw-cgum", .data = &noc_macro_list[1] },
+	{ .compatible = "sirf,nocfw-btm", .data = &noc_macro_list[2] },
+	{ .compatible = "sirf,nocfw-gnssm", .data = &noc_macro_list[3] },
+	{ .compatible = "sirf,nocfw-gpum", .data = &noc_macro_list[4] },
+	{ .compatible = "sirf,nocfw-mediam", .data = &noc_macro_list[5] },
+	{ .compatible = "sirf,nocfw-vdifm", .data = &noc_macro_list[6] },
+	{ .compatible = "sirf,nocfw-audiom", .data = &noc_macro_list[7] },
+	{ .compatible = "sirf,nocfw-ddrm", .data = &noc_macro_list[8] },
+	{ .compatible = "sirf,nocfw-rtcm", .data = &noc_macro_list[9] },
+	{ .compatible = "sirf,nocfw-dramfw", .data = &noc_macro_list[10] },
+	{ .compatible = "sirf,nocfw-spramfw", .data = &noc_macro_list[11] },
+
+};
+
+static int noc_dram_firewall_init(struct platform_device *pdev)
+{
+	int ret;
+	/*
+	 * fireware has been set earlier in secure mode, here
+	 * it is only for debug purpose
+	 */
+	ret = device_create_file(&pdev->dev, &dev_attr_dramfw);
+	if (ret)
+		dev_err(&pdev->dev,
+			"failed to create dram firewall attribute, %d\n",
+			ret);
+
+	ret = device_create_file(&pdev->dev, &dev_attr_regfw);
+	if (ret)
+		dev_err(&pdev->dev,
+			"failed to create spram firewall attribute, %d\n",
+			ret);
+	return 0;
+}
+
+static int noc_spram_firewall_init(struct platform_device *pdev)
+{
+	int ret;
+	/*
+	 * fireware has been set earlier in secure mode, here
+	 * it is only for debug purpose
+	 */
+	ret = device_create_file(&pdev->dev, &dev_attr_spramfw);
+	if (ret)
+		dev_err(&pdev->dev,
+			"failed to create spram firewall attribute, %d\n",
+			ret);
+
+	return 0;
+}
+
+static int noc_a7_init(struct platform_device *pdev)
+{
+	struct noc_macro *nocm;
+
+	nocm = platform_get_drvdata(pdev);
+	/* enable errlog trigger, A7 use abort */
+	noc_fault_enable(nocm);
+
+	return 0;
+}
+
+static int noc_macro_init(struct platform_device *pdev)
+{
+	int ret;
+	struct noc_macro *nocm;
+
+	nocm = platform_get_drvdata(pdev);
+
+	ret = of_irq_get(pdev->dev.of_node, 0);
+	if (ret <= 0) {
+		dev_info(&pdev->dev,
+			"Unable to find IRQ number. ret=%d\n", ret);
+		goto err;
+	}
+	nocm->irq = ret;
+	/* enable errlog trigger, thus irq/abort could come */
+	noc_fault_enable(nocm);
+	ret = devm_request_irq(&pdev->dev,
+			nocm->irq,
+			noc_irq_handle,
+			0,
+			nocm->name, nocm);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	return ret;
+}
+
+__init int sirfsoc_noc_init(void)
+{
+	struct device_node *np;
+	const struct of_device_id *match;
+	struct noc_macro *nocm;
+	struct platform_device *pdev;
+
+	for_each_matching_node_and_match(np, sirfsoc_nocfw_ids, &match) {
+		if (!of_device_is_available(np))
+			continue;
+
+		nocm = (struct noc_macro *)match->data;
+		nocm->mbase = of_iomap(np, 0);
+		if (!nocm->mbase)
+			return -ENOMEM;
+
+		spin_lock_init(&nocm->lock);
+		pdev = of_find_device_by_node(np);
+		platform_set_drvdata(pdev, nocm);
+
+		hook_fault_code(8, noc_abort_handler, SIGBUS, 0,
+			"external abort on non-linefetch");
+
+		hook_fault_code(22, noc_abort_handler, SIGBUS, 0,
+			"imprecise external abort");
+
+		if (nocm->init_macro)
+			nocm->init_macro(pdev);
+	}
+
+	return 0;
+}
-- 
2.3.0

             reply	other threads:[~2015-03-09  6:05 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-09  6:05 Barry Song [this message]
2015-03-25 22:53 [PATCH] ARM: prima2: add NetWork on Chip driver for atlas7 Barry Song

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1425881107-4597-1-git-send-email-21cnbao@gmail.com \
    --to=21cnbao@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.