summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/board.h1
-rw-r--r--arch/arm/mach-tegra/common-t2.c191
-rw-r--r--arch/arm/mach-tegra/common.c1
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c65
5 files changed, 195 insertions, 64 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f02189fda030..419bb92384cd 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,4 +1,5 @@
obj-y += common.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += common-t2.o
obj-y += board-common.o
obj-y += io.o
obj-y += irq.o
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 702a52ff1936..a5cf92369052 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -25,6 +25,7 @@
struct tegra_suspend_platform_data;
+void __init tegra_mc_init(void);
void __init tegra_common_init(void);
void __init tegra_map_common_io(void);
void __init tegra_init_irq(void);
diff --git a/arch/arm/mach-tegra/common-t2.c b/arch/arm/mach-tegra/common-t2.c
new file mode 100644
index 000000000000..f9eade8311d9
--- /dev/null
+++ b/arch/arm/mach-tegra/common-t2.c
@@ -0,0 +1,191 @@
+/*
+ * arch/arm/mach-tegra/common-t2.c
+ *
+ * Tegra 2 SoC-specific initialization (memory controller, etc.)
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+
+#define MC_INT_STATUS 0x0
+#define MC_INT_MASK 0x4
+#define MC_INT_DECERR_EMEM_OTHERS (1<<6)
+#define MC_INT_INVALID_GART_PAGE (1<<7)
+#define MC_INT_SECURITY_VIOLATION (1<<8)
+
+#define MC_GART_ERROR_STATUS 0x30
+#define MC_GART_ERROR_ADDRESS 0x34
+
+#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
+#define MC_DECERR_EMEM_OTHERS_ADDRESS 0x5c
+
+#define MC_SECURITY_VIOLATION_STATUS 0x74
+#define MC_SECURITY_VIOLATION_ADDRESS 0x78
+
+struct mc_client {
+ bool write;
+ const char *name;
+};
+
+#define client(_name,_write) \
+ { \
+ .write = _write, \
+ .name = _name, \
+ }
+
+static const struct mc_client mc_clients[] = {
+ client("display0_wina", false), client("display1_wina", false),
+ client("display0_winb", false), client("display1_winb", false),
+ client("display0_winc", false), client("display1_winc", false),
+ client("display0_winb_vfilter", false),
+ client("display1_winb_vfilter", false),
+ client("epp", false), client("gr2d_pat", false),
+ client("gr2d_src", false), client("mpe_unified", false),
+ client("vi_chroma_filter", false), client("cop", false),
+ client("display0_cursor", false), client("display1_cursor", false),
+ client("gr3d_fdc", false), client("gr2d_dst", false),
+ client("host1x_dma", false), client("host1x_generic", false),
+ client("gr3d_idx", false), client("cpu_uncached", false),
+ client("mpe_intrapred", false), client("mpe_mpea", false),
+ client("mpe_mpec", false), client("ahb_dma", false),
+ client("ahb_slave", false), client("gr3d_tex", false),
+ client("vde_bsev", false), client("vde_mbe", false),
+ client("vde_mce", false), client("vde_tpe", false),
+ client("epp_u", true), client("epp_v", true),
+ client("epp_y", true), client("mpe_unified", true),
+ client("vi_sb", true), client("vi_u", true),
+ client("vi_v", true), client("vi_y", true),
+ client("gr2d_dst", true), client("gr3d_fdc", true),
+ client("host1x", true), client("isp", true),
+ client("cpu_uncached", true), client("mpe_mpec", true),
+ client("ahb_dma", true), client("ahb_slave", true),
+ client("avp_bsev", true), client("avp_mbe", true),
+ client("avp_tpm", true),
+};
+
+static DEFINE_SPINLOCK(mc_lock);
+static unsigned long error_count = 0;
+#define MAX_PRINTS 5
+
+static void unthrottle_prints(struct work_struct *work)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mc_lock, flags);
+ error_count = 0;
+ spin_unlock_irqrestore(&mc_lock, flags);
+}
+
+static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
+
+static irqreturn_t tegra_mc_error_isr(int irq, void *data)
+{
+ void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
+ unsigned long count;
+ u32 stat;
+
+ stat = readl(mc + MC_INT_STATUS);
+ stat &= (MC_INT_SECURITY_VIOLATION |
+ MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM_OTHERS);
+
+ cancel_delayed_work(&unthrottle_prints_work);
+
+ spin_lock(&mc_lock);
+ count = ++error_count;
+ spin_unlock(&mc_lock);
+
+ if (count >= MAX_PRINTS) {
+ if (count == MAX_PRINTS)
+ pr_err("Too many MC errors; throttling prints\n");
+ schedule_delayed_work(&unthrottle_prints_work, HZ/2);
+ goto out;
+ }
+
+ if (stat & MC_INT_DECERR_EMEM_OTHERS) {
+ const struct mc_client *client = NULL;
+ u32 addr, req;
+
+ req = readl(mc + MC_DECERR_EMEM_OTHERS_STATUS);
+ addr = readl(mc + MC_DECERR_EMEM_OTHERS_ADDRESS);
+ req &= 0x3f;
+ if (req < ARRAY_SIZE(mc_clients))
+ client = &mc_clients[req];
+
+ pr_err("MC_DECERR: %p %s (%s)\n", (void*)addr,
+ (client) ? client->name : "unknown",
+ (client && client->write) ? "write" : "read");
+ }
+
+ if (stat & MC_INT_INVALID_GART_PAGE) {
+ const struct mc_client *client = NULL;
+ u32 addr, req;
+
+ req = readl(mc + MC_GART_ERROR_STATUS);
+ addr = readl(mc + MC_GART_ERROR_ADDRESS);
+ req = (req >> 1) & 0x3f;
+
+ if (req < ARRAY_SIZE(mc_clients))
+ client = &mc_clients[req];
+
+ pr_err("MC_GART_ERR: %p %s (%s)\n", (void*)addr,
+ (client) ? client->name : "unknown",
+ (client && client->write) ? "write" : "read");
+ }
+
+ if (stat & MC_INT_SECURITY_VIOLATION) {
+ const struct mc_client *client = NULL;
+ const char *type = NULL;
+ u32 addr, req;
+
+ req = readl(mc + MC_SECURITY_VIOLATION_STATUS);
+ addr = readl(mc + MC_SECURITY_VIOLATION_ADDRESS);
+
+ type = (req & (1<<30)) ? "carveout" : "trustzone";
+
+ req &= 0x3f;
+ if (req < ARRAY_SIZE(mc_clients))
+ client = &mc_clients[req];
+
+ pr_err("MC_SECURITY_ERR (%s): %p %s (%s)\n", type, (void*)addr,
+ (client) ? client->name : "unknown",
+ (client && client->write) ? "write" : "read");
+ }
+out:
+ writel(stat, mc + MC_INT_STATUS);
+ return IRQ_HANDLED;
+}
+
+void __init tegra_mc_init(void)
+{
+ if (request_irq(INT_MC_GENERAL, tegra_mc_error_isr, 0,
+ "mc_status", NULL)) {
+ pr_err("%s: unable to register MC error interrupt\n", __func__);
+ } else {
+ void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
+ u32 reg = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM_OTHERS;
+ writel(reg, mc + MC_INT_MASK);
+ }
+}
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 33eb91e8c2ab..42a41d2442f8 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -68,5 +68,6 @@ void __init tegra_common_init(void)
tegra_init_clock();
tegra_init_cache();
tegra_dma_init();
+ tegra_mc_init();
arm_pm_restart = tegra_machine_restart;
}
diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
index d589049ed4b4..d034d5d145ae 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_memctrl.c
@@ -45,7 +45,6 @@ NvError NvRmPrivAp20McErrorMonitorStart(NvRmDeviceHandle hRm);
void NvRmPrivAp20McErrorMonitorStop(NvRmDeviceHandle hRm);
void NvRmPrivAp20SetupMc(NvRmDeviceHandle hRm);
static void McErrorIntHandler(void* args);
-static NvOsInterruptHandle s_McInterruptHandle = NULL;
void
McStatAp20_Start(
@@ -64,77 +63,15 @@ McStatAp20_Stop(
void McErrorIntHandler(void* args)
{
- NvU32 RegVal;
- NvU32 IntStatus;
- NvU32 IntClear = 0;
- NvRmDeviceHandle hRm = (NvRmDeviceHandle)args;
-
- IntStatus = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTSTATUS_0);
- if ( NV_DRF_VAL(MC, INTSTATUS, SECURITY_VIOLATION_INT, IntStatus) )
- {
- IntClear |= NV_DRF_DEF(MC, INTSTATUS, SECURITY_VIOLATION_INT, SET);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_SECURITY_VIOLATION_ADR_0);
- NvOsDebugPrintf("SECURITY_VIOLATION DecErrAddress=0x%x ", RegVal);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_SECURITY_VIOLATION_STATUS_0);
- NvOsDebugPrintf("SECURITY_VIOLATION DecErrStatus=0x%x ", RegVal);
- }
- if ( NV_DRF_VAL(MC, INTSTATUS, DECERR_EMEM_OTHERS_INT, IntStatus) )
- {
- IntClear |= NV_DRF_DEF(MC, INTSTATUS, DECERR_EMEM_OTHERS_INT, SET);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_DECERR_EMEM_OTHERS_ADR_0);
- NvOsDebugPrintf("EMEM DecErrAddress=0x%x ", RegVal);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_DECERR_EMEM_OTHERS_STATUS_0);
- NvOsDebugPrintf("EMEM DecErrStatus=0x%x ", RegVal);
- }
- if ( NV_DRF_VAL(MC, INTSTATUS, INVALID_GART_PAGE_INT, IntStatus) )
- {
- IntClear |= NV_DRF_DEF(MC, INTSTATUS, INVALID_GART_PAGE_INT, SET);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_GART_ERROR_ADDR_0);
- NvOsDebugPrintf("GART DecErrAddress=0x%x ", RegVal);
- RegVal = NV_REGR(hRm, NvRmPrivModuleID_MemoryController, 0,
- MC_GART_ERROR_REQ_0);
- NvOsDebugPrintf("GART DecErrStatus=0x%x ", RegVal);
- }
-
- NV_ASSERT(!"MC Decode Error ");
- // Clear the interrupt.
- NV_REGW(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTSTATUS_0, IntClear);
- NvRmInterruptDone(s_McInterruptHandle);
}
NvError NvRmPrivAp20McErrorMonitorStart(NvRmDeviceHandle hRm)
{
- NvU32 val;
- NvU32 IrqList;
- NvError e = NvSuccess;
- NvOsInterruptHandler handler;
-
- if (s_McInterruptHandle == NULL)
- {
- // Install an interrupt handler.
- handler = McErrorIntHandler;
- IrqList = NvRmGetIrqForLogicalInterrupt(hRm,
- NvRmPrivModuleID_MemoryController, 0);
- NV_CHECK_ERROR( NvRmInterruptRegister(hRm, 1, &IrqList, &handler,
- hRm, &s_McInterruptHandle, NV_TRUE) );
- // Enable Dec Err interrupts in memory Controller.
- val = NV_DRF_DEF(MC, INTMASK, SECURITY_VIOLATION_INTMASK, UNMASKED) |
- NV_DRF_DEF(MC, INTMASK, DECERR_EMEM_OTHERS_INTMASK, UNMASKED) |
- NV_DRF_DEF(MC, INTMASK, INVALID_GART_PAGE_INTMASK, UNMASKED);
- NV_REGW(hRm, NvRmPrivModuleID_MemoryController, 0, MC_INTMASK_0, val);
- }
- return e;
+ return NvSuccess;
}
void NvRmPrivAp20McErrorMonitorStop(NvRmDeviceHandle hRm)
{
- NvRmInterruptUnregister(hRm, s_McInterruptHandle);
- s_McInterruptHandle = NULL;
}
/* This function sets some performance timings for Mc & Emc. Numbers are from