summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorAlex Waterman <alexw@nvidia.com>2013-10-23 12:29:52 -0700
committerKrishna Reddy <vdumpa@nvidia.com>2014-02-07 13:20:16 -0800
commit2219ca8ed25b79ce07b20e4af7cf558c8525ae98 (patch)
treebccbe808aadc05b55a61180084defb5fb3471780 /drivers/platform
parent31c364e9c2e0a95dcb39c49396da89316e7c15c8 (diff)
ARM: tegra: mc: move MC code to drivers/platform/tegra/mc
Move the MC driver out of mach-tegra and prepare the driver for using the DT. Change-Id: I544259de9e899b29152d7e2f08bce5745e40fb30 Signed-off-by: Alex Waterman <alexw@nvidia.com> Reviewed-on: http://git-master/r/302984 Reviewed-by: Krishna Reddy <vdumpa@nvidia.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/tegra/Makefile5
-rw-r--r--drivers/platform/tegra/mc-timing-t12x.c2
-rw-r--r--drivers/platform/tegra/mc.c2
-rw-r--r--drivers/platform/tegra/mc/Makefile16
-rw-r--r--drivers/platform/tegra/mc/mc-timing-t12x.c88
-rw-r--r--drivers/platform/tegra/mc/mc.c297
-rw-r--r--drivers/platform/tegra/mc/mcerr-t11.c198
-rw-r--r--drivers/platform/tegra/mc/mcerr-t12.c218
-rw-r--r--drivers/platform/tegra/mc/mcerr-t14.c194
-rw-r--r--drivers/platform/tegra/mc/mcerr-t3.c104
-rw-r--r--drivers/platform/tegra/mc/mcerr.c442
-rw-r--r--drivers/platform/tegra/mcerr-t12.c2
-rw-r--r--drivers/platform/tegra/mcerr.c2
13 files changed, 1559 insertions, 11 deletions
diff --git a/drivers/platform/tegra/Makefile b/drivers/platform/tegra/Makefile
index da3bd255fd0b..07e495620696 100644
--- a/drivers/platform/tegra/Makefile
+++ b/drivers/platform/tegra/Makefile
@@ -12,6 +12,8 @@ obj-y += mipi-cal.o
endif
endif
+obj-y += mc/
+
ifneq ($(CONFIG_ARM64),)
ccflags-y += -I$(srctree)/arch/arm/mach-tegra/include \
@@ -97,9 +99,6 @@ obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += tegra12_edp.o
obj-y += board-common.o
-obj-y += mcerr.o
-obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += mcerr-t12.o
-
obj-y += board-touch-raydium_spi.o
obj-y += board-panel.o
diff --git a/drivers/platform/tegra/mc-timing-t12x.c b/drivers/platform/tegra/mc-timing-t12x.c
deleted file mode 100644
index 9c9e3eebe397..000000000000
--- a/drivers/platform/tegra/mc-timing-t12x.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Automatically generated file; DO NOT EDIT. */
-#include "../../../arch/arm/mach-tegra/mc-timing-t12x.c"
diff --git a/drivers/platform/tegra/mc.c b/drivers/platform/tegra/mc.c
deleted file mode 100644
index 191f3fdd2479..000000000000
--- a/drivers/platform/tegra/mc.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Automatically generated file; DO NOT EDIT. */
-#include "../../../arch/arm/mach-tegra/mc.c"
diff --git a/drivers/platform/tegra/mc/Makefile b/drivers/platform/tegra/mc/Makefile
new file mode 100644
index 000000000000..31d86edca45d
--- /dev/null
+++ b/drivers/platform/tegra/mc/Makefile
@@ -0,0 +1,16 @@
+#
+# Memory controller code.
+#
+
+obj-y += mc.o
+
+# MC error reporting.
+obj-y += mcerr.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += mcerr-t3.o
+obj-$(CONFIG_ARCH_TEGRA_11x_SOC) += mcerr-t11.o
+obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += mcerr-t12.o
+obj-$(CONFIG_ARCH_TEGRA_14x_SOC) += mcerr-t14.o
+
+ifeq ($(CONFIG_PM_SLEEP),y)
+obj-$(CONFIG_ARCH_TEGRA_12x_SOC) += mc-timing-t12x.o
+endif
diff --git a/drivers/platform/tegra/mc/mc-timing-t12x.c b/drivers/platform/tegra/mc/mc-timing-t12x.c
new file mode 100644
index 000000000000..aeb87d908a05
--- /dev/null
+++ b/drivers/platform/tegra/mc/mc-timing-t12x.c
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-tegra/mc-timing-t12x.c
+ *
+ * Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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/io.h>
+
+#include <mach/mcerr.h>
+
+#include "../../../../arch/arm/mach-tegra/iomap.h"
+
+#define MC_LA_REG(mod) MC_LATENCY_ALLOWANCE_ ## mod
+
+static u32 mc_timing_reg_table[] = {
+ MC_LA_REG(AFI_0),
+ MC_LA_REG(AVPC_0),
+ MC_LA_REG(DC_0),
+ MC_LA_REG(DC_1),
+ MC_LA_REG(DC_2),
+ MC_LA_REG(DCB_0),
+ MC_LA_REG(DCB_1),
+ MC_LA_REG(DCB_2),
+ MC_LA_REG(HC_0),
+ MC_LA_REG(HC_1),
+ MC_LA_REG(HDA_0),
+ MC_LA_REG(MPCORE_0),
+ MC_LA_REG(MPCORELP_0),
+ MC_LA_REG(MSENC_0),
+ MC_LA_REG(PPCS_0),
+ MC_LA_REG(PPCS_1),
+ MC_LA_REG(PTC_0),
+ MC_LA_REG(SATA_0),
+ MC_LA_REG(VDE_0),
+ MC_LA_REG(VDE_1),
+ MC_LA_REG(VDE_2),
+ MC_LA_REG(VDE_3),
+ MC_LA_REG(ISP2_0),
+ MC_LA_REG(ISP2_1),
+ MC_LA_REG(XUSB_0),
+ MC_LA_REG(XUSB_1),
+ MC_LA_REG(ISP2B_0),
+ MC_LA_REG(ISP2B_1),
+ MC_LA_REG(TSEC_0),
+ MC_LA_REG(VIC_0),
+ MC_LA_REG(VI2_0),
+ MC_LA_REG(A9AVP_0),
+ MC_LA_REG(GPU_0),
+ MC_LA_REG(SDMMCA_0),
+ MC_LA_REG(SDMMCAA_0),
+ MC_LA_REG(SDMMC_0),
+ MC_LA_REG(SDMMCAB_0),
+ MC_LA_REG(DC_3)
+};
+
+#define NUM_LA_REGS ARRAY_SIZE(mc_timing_reg_table)
+
+void tegra12_mc_latency_allowance_save(u32 **pctx)
+{
+ u32 *ctx = *pctx;
+ u32 i;
+ for (i = 0; i < NUM_LA_REGS; ++i)
+ *ctx++ = readl(IOMEM(mc +
+ mc_timing_reg_table[i]));
+}
+
+void tegra12_mc_latency_allowance_restore(u32 **pctx)
+{
+ u32 *ctx = *pctx;
+ u32 i;
+ for (i = 0; i < NUM_LA_REGS; ++i)
+ __raw_writel(*ctx++, IOMEM(mc +
+ mc_timing_reg_table[i]));
+}
diff --git a/drivers/platform/tegra/mc/mc.c b/drivers/platform/tegra/mc/mc.c
new file mode 100644
index 000000000000..e1cdd7637d3e
--- /dev/null
+++ b/drivers/platform/tegra/mc/mc.c
@@ -0,0 +1,297 @@
+/*
+ * arch/arm/mach-tegra/mc.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * Author:
+ * Erik Gilling <konkers@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/tegra-soc.h>
+
+#include <mach/mc.h>
+#include <mach/mcerr.h>
+
+#include "../../../../arch/arm/mach-tegra/iomap.h"
+
+#define MC_CLIENT_HOTRESET_CTRL 0x200
+#define MC_CLIENT_HOTRESET_STAT 0x204
+#define MC_CLIENT_HOTRESET_CTRL_1 0x970
+#define MC_CLIENT_HOTRESET_STAT_1 0x974
+
+#define MC_TIMING_REG_NUM1 \
+ ((MC_EMEM_ARB_TIMING_W2R - MC_EMEM_ARB_CFG) / 4 + 1)
+#define MC_TIMING_REG_NUM2 \
+ ((MC_EMEM_ARB_MISC1 - MC_EMEM_ARB_DA_TURNS) / 4 + 1)
+#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
+#define MC_TIMING_REG_NUM3 T12X_MC_LATENCY_ALLOWANCE_NUM_REGS
+#else
+#define MC_TIMING_REG_NUM3 \
+ ((MC_LATENCY_ALLOWANCE_VI_2 - MC_LATENCY_ALLOWANCE_BASE) / 4 + 1)
+#endif
+
+static DEFINE_SPINLOCK(tegra_mc_lock);
+void __iomem *mc = (void __iomem *)IO_ADDRESS(TEGRA_MC_BASE);
+#ifdef MC_DUAL_CHANNEL
+void __iomem *mc1 = (void __iomem *)IO_ADDRESS(TEGRA_MC1_BASE);
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2
+ + MC_TIMING_REG_NUM3 + 4];
+
+static void tegra_mc_timing_save(void)
+{
+ u32 off;
+ u32 *ctx = mc_boot_timing;
+
+ for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
+ *ctx++ = mc_readl(off);
+
+ for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
+ *ctx++ = mc_readl(off);
+
+ *ctx++ = mc_readl(MC_EMEM_ARB_RING3_THROTTLE);
+ *ctx++ = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ *ctx++ = mc_readl(MC_RESERVED_RSV);
+
+#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
+ tegra12_mc_latency_allowance_save(&ctx);
+#else
+ for (off = MC_LATENCY_ALLOWANCE_BASE; off <= MC_LATENCY_ALLOWANCE_VI_2;
+ off += 4)
+ *ctx++ = mc_readl(off);
+#endif
+
+ *ctx++ = mc_readl(MC_INT_MASK);
+}
+
+void tegra_mc_timing_restore(void)
+{
+ u32 off;
+ u32 *ctx = mc_boot_timing;
+
+ for (off = MC_EMEM_ARB_CFG; off <= MC_EMEM_ARB_TIMING_W2R; off += 4)
+ __mc_raw_writel(0, *ctx++, off);
+
+ for (off = MC_EMEM_ARB_DA_TURNS; off <= MC_EMEM_ARB_MISC1; off += 4)
+ __mc_raw_writel(0, *ctx++, off);
+
+ __mc_raw_writel(0, *ctx++, MC_EMEM_ARB_RING3_THROTTLE);
+ __mc_raw_writel(0, *ctx++, MC_EMEM_ARB_OVERRIDE);
+ __mc_raw_writel(0, *ctx++, MC_RESERVED_RSV);
+
+#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
+ tegra12_mc_latency_allowance_restore(&ctx);
+#else
+ for (off = MC_LATENCY_ALLOWANCE_BASE; off <= MC_LATENCY_ALLOWANCE_VI_2;
+ off += 4)
+ __mc_raw_writel(0, *ctx++, off);
+#endif
+
+ mc_writel(*ctx++, MC_INT_MASK);
+ off = mc_readl(MC_INT_MASK);
+
+ mc_writel(0x1, MC_TIMING_CONTROL);
+ off = mc_readl(MC_TIMING_CONTROL);
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ /* Bug 1059264
+ * Set extra snap level to avoid VI starving and dropping data.
+ */
+ mc_writel(1, MC_VE_EXTRA_SNAP_LEVELS);
+#endif
+}
+#else
+#define tegra_mc_timing_save()
+#endif
+
+/*
+ * If using T30/DDR3, the 2nd 16 bytes part of DDR3 atom is 2nd line and is
+ * discarded in tiling mode.
+ */
+int tegra_mc_get_tiled_memory_bandwidth_multiplier(void)
+{
+ int type;
+
+ type = tegra_emc_get_dram_type();
+
+ if (type == DRAM_TYPE_DDR3)
+ return 2;
+ else
+ return 1;
+}
+
+/* API to get EMC freq to be requested, for Bandwidth.
+ * bw_kbps: BandWidth passed is in KBps.
+ * returns freq in KHz
+ */
+unsigned int tegra_emc_bw_to_freq_req(unsigned int bw_kbps)
+{
+ unsigned int freq;
+ unsigned int bytes_per_emc_clk;
+
+ bytes_per_emc_clk = tegra_mc_get_effective_bytes_width() * 2;
+ freq = (bw_kbps + bytes_per_emc_clk - 1) / bytes_per_emc_clk *
+ CONFIG_TEGRA_EMC_TO_DDR_CLOCK;
+ return freq;
+}
+EXPORT_SYMBOL_GPL(tegra_emc_bw_to_freq_req);
+
+/* API to get EMC bandwidth, for freq that can be requested.
+ * freq_khz: Frequency passed is in KHz.
+ * returns bandwidth in KBps
+ */
+unsigned int tegra_emc_freq_req_to_bw(unsigned int freq_khz)
+{
+ unsigned int bw;
+ unsigned int bytes_per_emc_clk;
+
+ bytes_per_emc_clk = tegra_mc_get_effective_bytes_width() * 2;
+ bw = freq_khz * bytes_per_emc_clk / CONFIG_TEGRA_EMC_TO_DDR_CLOCK;
+ return bw;
+}
+EXPORT_SYMBOL_GPL(tegra_emc_freq_req_to_bw);
+
+#define HOTRESET_READ_COUNT 5
+static bool tegra_stable_hotreset_check(u32 stat_reg, u32 *stat)
+{
+ int i;
+ u32 cur_stat;
+ u32 prv_stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tegra_mc_lock, flags);
+ prv_stat = mc_readl(stat_reg);
+ for (i = 0; i < HOTRESET_READ_COUNT; i++) {
+ cur_stat = mc_readl(stat_reg);
+ if (cur_stat != prv_stat) {
+ spin_unlock_irqrestore(&tegra_mc_lock, flags);
+ return false;
+ }
+ }
+ *stat = cur_stat;
+ spin_unlock_irqrestore(&tegra_mc_lock, flags);
+ return true;
+}
+
+int tegra_mc_flush(int id)
+{
+ u32 rst_ctrl, rst_stat;
+ u32 rst_ctrl_reg, rst_stat_reg;
+ unsigned long flags;
+ bool ret;
+
+ if (id < 32) {
+ rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
+ rst_stat_reg = MC_CLIENT_HOTRESET_STAT;
+ } else {
+ id %= 32;
+ rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
+ rst_stat_reg = MC_CLIENT_HOTRESET_STAT_1;
+ }
+
+ spin_lock_irqsave(&tegra_mc_lock, flags);
+
+ rst_ctrl = mc_readl(rst_ctrl_reg);
+ rst_ctrl |= (1 << id);
+ mc_writel(rst_ctrl, rst_ctrl_reg);
+
+ spin_unlock_irqrestore(&tegra_mc_lock, flags);
+
+ do {
+ udelay(10);
+ rst_stat = 0;
+ ret = tegra_stable_hotreset_check(rst_stat_reg, &rst_stat);
+ if (!ret)
+ continue;
+ } while (!(rst_stat & (1 << id)));
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_mc_flush);
+
+int tegra_mc_flush_done(int id)
+{
+ u32 rst_ctrl;
+ u32 rst_ctrl_reg, rst_stat_reg;
+ unsigned long flags;
+
+ if (id < 32) {
+ rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
+ rst_stat_reg = MC_CLIENT_HOTRESET_STAT;
+ } else {
+ id %= 32;
+ rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
+ rst_stat_reg = MC_CLIENT_HOTRESET_STAT_1;
+ }
+
+ spin_lock_irqsave(&tegra_mc_lock, flags);
+
+ rst_ctrl = mc_readl(rst_ctrl_reg);
+ rst_ctrl &= ~(1 << id);
+ mc_writel(rst_ctrl, rst_ctrl_reg);
+
+ spin_unlock_irqrestore(&tegra_mc_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_mc_flush_done);
+
+/*
+ * MC driver init.
+ */
+static int __init tegra_mc_init(void)
+{
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
+ defined(CONFIG_TEGRA_MC_EARLY_ACK)
+ u32 reg;
+#endif
+ struct dentry *mc_debugfs_dir;
+
+ tegra_mc_timing_save();
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ reg = 0x0f7f1010;
+ mc_writel(reg, MC_RESERVED_RSV);
+#endif
+
+#if defined(CONFIG_TEGRA_MC_EARLY_ACK)
+ reg = mc_readl(MC_EMEM_ARB_OVERRIDE);
+ reg |= 3;
+#if defined(CONFIG_TEGRA_ERRATA_1157520)
+ if (tegra_revision == TEGRA_REVISION_A01)
+ reg &= ~2;
+#endif
+ mc_writel(reg, MC_EMEM_ARB_OVERRIDE);
+#endif
+
+ mc_debugfs_dir = debugfs_create_dir("mc", NULL);
+ if (mc_debugfs_dir == NULL) {
+ pr_err("Failed to make debugfs node: %ld\n",
+ PTR_ERR(mc_debugfs_dir));
+ return PTR_ERR(mc_debugfs_dir);
+ }
+
+ tegra_mcerr_init(mc_debugfs_dir);
+
+ return 0;
+}
+arch_initcall(tegra_mc_init);
diff --git a/drivers/platform/tegra/mc/mcerr-t11.c b/drivers/platform/tegra/mc/mcerr-t11.c
new file mode 100644
index 000000000000..5cfc1b9b8e22
--- /dev/null
+++ b/drivers/platform/tegra/mc/mcerr-t11.c
@@ -0,0 +1,198 @@
+/*
+ * Tegra 11x SoC-specific mcerr code.
+ *
+ * Copyright (c) 2010-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 <mach/mcerr.h>
+
+/*** Auto generated by `mcp.pl'. Do not modify! ***/
+
+#define dummy_client client("dummy", "dummy")
+
+struct mc_client mc_clients[] = {
+ client("ptc", "csr_ptcr"),
+ client("dc", "csr_display0a"),
+ client("dcb", "csr_display0ab"),
+ client("dc", "csr_display0b"),
+ client("dcb", "csr_display0bb"),
+ client("dc", "csr_display0c"),
+ client("dcb", "csr_display0cb"),
+ dummy_client,
+ dummy_client,
+ client("epp", "cbr_eppup"),
+ client("g2", "cbr_g2pr"),
+ client("g2", "cbr_g2sr"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("avpc", "csr_avpcarm7r"),
+ client("dc", "csr_displayhc"),
+ client("dcb", "csr_displayhcb"),
+ client("nv", "csr_fdcdrd"),
+ client("nv", "csr_fdcdrd2"),
+ client("g2", "csr_g2dr"),
+ client("hda", "csr_hdar"),
+ client("hc", "csr_host1xdmar"),
+ client("hc", "csr_host1xr"),
+ client("nv", "csr_idxsrd"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("msenc", "csr_msencsrd"),
+ client("ppcs", "csr_ppcsahbdmar"),
+ client("ppcs", "csr_ppcsahbslvr"),
+ dummy_client,
+ client("nv", "csr_texl2srd"),
+ dummy_client,
+ client("vde", "csr_vdebsevr"),
+ client("vde", "csr_vdember"),
+ client("vde", "csr_vdemcer"),
+ client("vde", "csr_vdetper"),
+ client("mpcorelp", "csr_mpcorelpr"),
+ client("mpcore", "csr_mpcorer"),
+ client("epp", "cbw_eppu"),
+ client("epp", "cbw_eppv"),
+ client("epp", "cbw_eppy"),
+ client("msenc", "csw_msencswr"),
+ client("vi", "cbw_viwsb"),
+ client("vi", "cbw_viwu"),
+ client("vi", "cbw_viwv"),
+ client("vi", "cbw_viwy"),
+ client("g2", "ccw_g2dw"),
+ dummy_client,
+ client("avpc", "csw_avpcarm7w"),
+ client("nv", "csw_fdcdwr"),
+ client("nv", "csw_fdcdwr2"),
+ client("hda", "csw_hdaw"),
+ client("hc", "csw_host1xw"),
+ client("isp", "csw_ispw"),
+ client("mpcorelp", "csw_mpcorelpw"),
+ client("mpcore", "csw_mpcorew"),
+ dummy_client,
+ client("ppcs", "csw_ppcsahbdmaw"),
+ client("ppcs", "csw_ppcsahbslvw"),
+ dummy_client,
+ client("vde", "csw_vdebsevw"),
+ client("vde", "csw_vdedbgw"),
+ client("vde", "csw_vdembew"),
+ client("vde", "csw_vdetpmw"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("xusb_host", "csr_xusb_hostr"),
+ client("xusb_host", "csw_xusb_hostw"),
+ client("xusb_dev", "csr_xusb_devr"),
+ client("xusb_dev", "csw_xusb_devw"),
+ client("nv", "csw_fdcdwr3"),
+ client("nv", "csr_fdcdrd3"),
+ client("nv", "csw_fdcdwr4"),
+ client("nv", "csr_fdcdrd4"),
+ client("emucif", "csr_emucifr"),
+ client("emucif", "csw_emucifw"),
+ client("tsec", "csr_tsecsrd"),
+ client("tsec", "csw_tsecswr"),
+};
+int mc_client_last = ARRAY_SIZE(mc_clients) - 1;
+/*** Done. ***/
+
+static void mcerr_t11x_info_update(struct mc_client *c, u32 stat)
+{
+ if (stat & MC_INT_DECERR_EMEM)
+ c->intr_counts[0]++;
+ if (stat & MC_INT_SECURITY_VIOLATION)
+ c->intr_counts[1]++;
+ if (stat & MC_INT_INVALID_SMMU_PAGE)
+ c->intr_counts[2]++;
+ if (stat & MC_INT_DECERR_VPR)
+ c->intr_counts[3]++;
+ if (stat & MC_INT_SECERR_SEC)
+ c->intr_counts[4]++;
+
+ if (stat & ~MC_INT_EN_MASK)
+ c->intr_counts[5]++;
+}
+
+/*
+ * T11x reports addresses in a 32 byte range thus we can only give an
+ * approximate location for the invalid memory request, not the exact address.
+ */
+static void mcerr_t11x_print(const struct mc_error *err,
+ const struct mc_client *client,
+ u32 status, phys_addr_t addr,
+ int secure, int rw, const char *smmu_info)
+{
+ pr_err("[mcerr] (%s) %s: %s\n", client->swgid, client->name, err->msg);
+ pr_err("[mcerr] status = 0x%08x; addr = [0x%08lx -> 0x%08lx]",
+ status, (ulong)(addr & ~0x1f), (ulong)(addr | 0x1f));
+ pr_err("[mcerr] secure: %s, access-type: %s, SMMU fault: %s\n",
+ secure ? "yes" : "no", rw ? "write" : "read",
+ smmu_info ? smmu_info : "none");
+}
+
+#define fmt_hdr "%-18s %-18s %-9s %-9s %-9s %-10s %-10s %-9s\n"
+#define fmt_cli "%-18s %-18s %-9u %-9u %-9u %-10u %-10u %-9u\n"
+static int mcerr_t11x_debugfs_show(struct seq_file *s, void *v)
+{
+ int i, j;
+ int do_print;
+
+ seq_printf(s, fmt_hdr,
+ "swgid", "client", "decerr", "secerr", "smmuerr",
+ "decerr-VPR", "secerr-SEC", "unknown");
+ for (i = 0; i < ARRAY_SIZE(mc_clients); i++) {
+ do_print = 0;
+ if (strcmp(mc_clients[i].name, "dummy") == 0)
+ continue;
+ /* Only print clients who actually have errors. */
+ for (j = 0; j < INTR_COUNT; j++) {
+ if (mc_clients[i].intr_counts[j]) {
+ do_print = 1;
+ break;
+ }
+ }
+ if (do_print)
+ seq_printf(s, fmt_cli,
+ mc_clients[i].swgid,
+ mc_clients[i].name,
+ mc_clients[i].intr_counts[0],
+ mc_clients[i].intr_counts[1],
+ mc_clients[i].intr_counts[2],
+ mc_clients[i].intr_counts[3],
+ mc_clients[i].intr_counts[4],
+ mc_clients[i].intr_counts[5]);
+ }
+ return 0;
+}
+
+/*
+ * Set up chip specific functions and data for handling this particular chip's
+ * error decoding and logging.
+ */
+void mcerr_chip_specific_setup(struct mcerr_chip_specific *spec)
+{
+ spec->mcerr_print = mcerr_t11x_print;
+ spec->mcerr_info_update = mcerr_t11x_info_update;
+ spec->mcerr_debugfs_show = mcerr_t11x_debugfs_show;
+ spec->nr_clients = ARRAY_SIZE(mc_clients);
+ return;
+}
diff --git a/drivers/platform/tegra/mc/mcerr-t12.c b/drivers/platform/tegra/mc/mcerr-t12.c
new file mode 100644
index 000000000000..0a2dde60e8aa
--- /dev/null
+++ b/drivers/platform/tegra/mc/mcerr-t12.c
@@ -0,0 +1,218 @@
+/*
+ * Tegra 12x SoC-specific mcerr code.
+ *
+ * Copyright (c) 2012-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 <mach/mcerr.h>
+
+/*** Auto generated by `mcp.pl'. Do not modify! ***/
+
+#define dummy_client client("dummy", "dummy")
+
+struct mc_client mc_clients[] = {
+ client("ptc", "csr_ptcr"),
+ client("dc", "csr_display0a"),
+ client("dcb", "csr_display0ab"),
+ client("dc", "csr_display0b"),
+ client("dcb", "csr_display0bb"),
+ client("dc", "csr_display0c"),
+ client("dcb", "csr_display0cb"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("afi", "csr_afir"),
+ client("avpc", "csr_avpcarm7r"),
+ client("dc", "csr_displayhc"),
+ client("dcb", "csr_displayhcb"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("hda", "csr_hdar"),
+ client("hc", "csr_host1xdmar"),
+ client("hc", "csr_host1xr"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("msenc", "csr_msencsrd"),
+ client("ppcs", "csr_ppcsahbdmar"),
+ client("ppcs", "csr_ppcsahbslvr"),
+ client("sata", "csr_satar"),
+ dummy_client,
+ dummy_client,
+ client("vde", "csr_vdebsevr"),
+ client("vde", "csr_vdember"),
+ client("vde", "csr_vdemcer"),
+ client("vde", "csr_vdetper"),
+ client("mpcorelp", "csr_mpcorelpr"),
+ client("mpcore", "csr_mpcorer"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("msenc", "csw_msencswr"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("afi", "csw_afiw"),
+ client("avpc", "csw_avpcarm7w"),
+ dummy_client,
+ dummy_client,
+ client("hda", "csw_hdaw"),
+ client("hc", "csw_host1xw"),
+ dummy_client,
+ client("mpcorelp", "csw_mpcorelpw"),
+ client("mpcore", "csw_mpcorew"),
+ dummy_client,
+ client("ppcs", "csw_ppcsahbdmaw"),
+ client("ppcs", "csw_ppcsahbslvw"),
+ client("sata", "csw_sataw"),
+ client("vde", "csw_vdebsevw"),
+ client("vde", "csw_vdedbgw"),
+ client("vde", "csw_vdembew"),
+ client("vde", "csw_vdetpmw"),
+ dummy_client,
+ dummy_client,
+ client("isp2", "csr_ispra"),
+ dummy_client,
+ client("isp2", "csw_ispwa"),
+ client("isp2", "csw_ispwb"),
+ dummy_client,
+ dummy_client,
+ client("xusb_host", "csr_xusb_hostr"),
+ client("xusb_host", "csw_xusb_hostw"),
+ client("xusb_dev", "csr_xusb_devr"),
+ client("xusb_dev", "csw_xusb_devw"),
+ client("isp2b", "csr_isprab"),
+ dummy_client,
+ client("isp2b", "csw_ispwab"),
+ client("isp2b", "csw_ispwbb"),
+ dummy_client,
+ dummy_client,
+ client("tsec", "csr_tsecsrd"),
+ client("tsec", "csw_tsecswr"),
+ client("a9avp", "csr_a9avpscr"),
+ client("a9avp", "csw_a9avpscw"),
+ client("gpu", "csr_gpusrd"),
+ client("gpu", "csw_gpuswr"),
+ client("dc", "csr_displayt"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("sdmmc1a", "csr_sdmmcra"),
+ client("sdmmc2a", "csr_sdmmcraa"),
+ client("sdmmc3a", "csr_sdmmcr"),
+ client("sdmmc4a", "csr_sdmmcrab"),
+ client("sdmmc1a", "csw_sdmmcwa"),
+ client("sdmmc2a", "csw_sdmmcwaa"),
+ client("sdmmc3a", "csw_sdmmcw"),
+ client("sdmmc4a", "csw_sdmmcwab"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("vic", "csr_vicsrd"),
+ client("vic", "csw_vicswr"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("vi", "csw_viw"),
+ client("dc", "csr_displayd"),
+};
+int mc_client_last = ARRAY_SIZE(mc_clients) - 1;
+/*** Done. ***/
+
+static void mcerr_t12x_info_update(struct mc_client *c, u32 stat)
+{
+ if (stat & MC_INT_DECERR_EMEM)
+ c->intr_counts[0]++;
+ if (stat & MC_INT_SECURITY_VIOLATION)
+ c->intr_counts[1]++;
+ if (stat & MC_INT_INVALID_SMMU_PAGE)
+ c->intr_counts[2]++;
+ if (stat & MC_INT_INVALID_APB_ASID_UPDATE)
+ c->intr_counts[3]++;
+ if (stat & MC_INT_DECERR_VPR)
+ c->intr_counts[4]++;
+ if (stat & MC_INT_SECERR_SEC)
+ c->intr_counts[5]++;
+ if (stat & MC_INT_DECERR_MTS)
+ c->intr_counts[6]++;
+
+ if (stat & ~MC_INT_EN_MASK)
+ c->intr_counts[7]++;
+}
+
+#define fmt_hdr "%-18s %-18s %-9s %-9s %-9s %-10s %-10s %-10s %-10s %-9s\n"
+#define fmt_cli "%-18s %-18s %-9u %-9u %-9u %-10u %-10u %-10u %-10u %-9u\n"
+static int mcerr_t12x_debugfs_show(struct seq_file *s, void *v)
+{
+ int i, j;
+ int do_print;
+
+ seq_printf(s, fmt_hdr,
+ "swgid", "client", "decerr", "secerr", "smmuerr",
+ "apberr", "decerr-VPR", "secerr-SEC",
+ "decerr_MST", "unknown");
+ for (i = 0; i < ARRAY_SIZE(mc_clients); i++) {
+ do_print = 0;
+ if (strcmp(mc_clients[i].name, "dummy") == 0)
+ continue;
+ /* Only print clients who actually have errors. */
+ for (j = 0; j < INTR_COUNT; j++) {
+ if (mc_clients[i].intr_counts[j]) {
+ do_print = 1;
+ break;
+ }
+ }
+ if (do_print)
+ seq_printf(s, fmt_cli,
+ mc_clients[i].swgid,
+ mc_clients[i].name,
+ mc_clients[i].intr_counts[0],
+ mc_clients[i].intr_counts[1],
+ mc_clients[i].intr_counts[2],
+ mc_clients[i].intr_counts[3],
+ mc_clients[i].intr_counts[4],
+ mc_clients[i].intr_counts[5],
+ mc_clients[i].intr_counts[6],
+ mc_clients[i].intr_counts[7]);
+ }
+ return 0;
+}
+
+/*
+ * Set up chip specific functions and data for handling this particular chip's
+ * error decoding and logging.
+ */
+void mcerr_chip_specific_setup(struct mcerr_chip_specific *spec)
+{
+ spec->mcerr_info_update = mcerr_t12x_info_update;
+ spec->mcerr_debugfs_show = mcerr_t12x_debugfs_show;
+ spec->nr_clients = ARRAY_SIZE(mc_clients);
+ return;
+}
+
diff --git a/drivers/platform/tegra/mc/mcerr-t14.c b/drivers/platform/tegra/mc/mcerr-t14.c
new file mode 100644
index 000000000000..4400f8a4e7af
--- /dev/null
+++ b/drivers/platform/tegra/mc/mcerr-t14.c
@@ -0,0 +1,194 @@
+/*
+ * Tegra 14x SoC-specific mcerr code.
+ *
+ * Copyright (c) 2012-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 <mach/mcerr.h>
+
+/*** Auto generated by `mcp.pl'. Do not modify! ***/
+
+#define dummy_client client("dummy", "dummy")
+
+struct mc_client mc_clients[] = {
+ client("ptc", "csr_ptcr"),
+ client("dc", "csr_display0a"),
+ client("dcb", "cbr_display0ab"),
+ client("dc", "csr_display0b"),
+ client("dcb", "csr_display0bb"),
+ client("dc", "csr_display0c"),
+ client("dcb", "cbr_display0cb"),
+ dummy_client,
+ dummy_client,
+ client("epp", "cbr_eppup"),
+ client("g2", "cbr_g2pr"),
+ client("g2", "cbr_g2sr"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("avpc", "csr_avpcarm7r"),
+ client("dc", "csr_displayhc"),
+ client("dcb", "csr_displayhcb"),
+ client("nv", "csr_fdcdrd"),
+ client("nv", "csr_fdcdrd2"),
+ client("g2", "csr_g2dr"),
+ client("hda", "csr_hdar"),
+ client("hc", "csr_host1xdmar"),
+ client("hc", "csr_host1xr"),
+ client("nv", "csr_idxsrd"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("msenc", "csr_msencsrd"),
+ client("ppcs", "csr_ppcsahbdmar"),
+ client("ppcs", "csr_ppcsahbslvr"),
+ dummy_client,
+ client("nv", "csr_texl2srd"),
+ dummy_client,
+ client("vde", "csr_vdebsevr"),
+ client("vde", "csr_vdember"),
+ client("vde", "csr_vdemcer"),
+ client("vde", "csr_vdetper"),
+ client("mpcorelp", "csr_mpcorelpr"),
+ client("mpcore", "csr_mpcorer"),
+ client("epp", "cbw_eppu"),
+ client("epp", "cbw_eppv"),
+ client("epp", "cbw_eppy"),
+ client("msenc", "csw_msencswr"),
+ client("vi", "cbw_viwsb"),
+ client("vi", "cbw_viwu"),
+ client("vi", "cbw_viwv"),
+ client("vi", "cbw_viwy"),
+ client("g2", "ccw_g2dw"),
+ dummy_client,
+ client("avpc", "csw_avpcarm7w"),
+ client("nv", "csw_fdcdwr"),
+ client("nv", "csw_fdcdwr2"),
+ client("hda", "csw_hdaw"),
+ client("hc", "csw_host1xw"),
+ client("isp", "csw_ispw"),
+ client("mpcorelp", "csw_mpcorelpw"),
+ client("mpcore", "csw_mpcorew"),
+ dummy_client,
+ client("ppcs", "csw_ppcsahbdmaw"),
+ client("ppcs", "csw_ppcsahbslvw"),
+ dummy_client,
+ client("vde", "csw_vdebsevw"),
+ client("vde", "csw_vdedbgw"),
+ client("vde", "csw_vdembew"),
+ client("vde", "csw_vdetpmw"),
+ dummy_client,
+ dummy_client,
+ client("isp", "csr_ispra"),
+ dummy_client,
+ client("isp", "csw_ispwa"),
+ client("isp", "csw_ispwb"),
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ dummy_client,
+ client("emucif", "csr_emucifr"),
+ client("emucif", "csw_emucifw"),
+ client("tsec", "csr_tsecsrd"),
+ client("tsec", "csw_tsecswr"),
+ client("vi", "csw_viw"),
+ client("bbmci", "csr_bbcr"),
+ client("bbmci", "csw_bbcw"),
+ client("bbmcill", "csr_bbcllr"),
+ client("dc", "csr_displayt"),
+ dummy_client,
+ client("dc", "csr_displayd"),
+};
+int mc_client_last = ARRAY_SIZE(mc_clients) - 1;
+/*** Done. ***/
+
+static void mcerr_t14x_info_update(struct mc_client *c, u32 stat)
+{
+ if (stat & MC_INT_DECERR_EMEM)
+ c->intr_counts[0]++;
+ if (stat & MC_INT_SECURITY_VIOLATION)
+ c->intr_counts[1]++;
+ if (stat & MC_INT_INVALID_SMMU_PAGE)
+ c->intr_counts[2]++;
+ if (stat & MC_INT_DECERR_VPR)
+ c->intr_counts[3]++;
+ if (stat & MC_INT_SECERR_SEC)
+ c->intr_counts[4]++;
+ if (stat & MC_INT_BBC_PRIVATE_MEM_VIOLATION)
+ c->intr_counts[5]++;
+ if (stat & MC_INT_DECERR_BBC)
+ c->intr_counts[6]++;
+
+ if (stat & ~MC_INT_EN_MASK)
+ c->intr_counts[7]++;
+}
+
+#define fmt_hdr "%-18s %-18s %-9s %-9s %-9s %-10s %-10s %-9s %-9s %-9s\n"
+#define fmt_cli "%-18s %-18s %-9u %-9u %-9u %-10u %-10u %-9u %-9u %-9u\n";
+static int mcerr_t14x_debugfs_show(struct seq_file *s, void *v)
+{
+ int i, j;
+ int do_print;
+
+ seq_printf(s, fmt_hdr,
+ "swgid", "client", "decerr", "secerr", "smmuerr",
+ "decerr-VPR", "secerr-SEC", "priv-bbc", "decerr-bbc",
+ "unknown");
+ for (i = 0; i < ARRAY_SIZE(mc_clients); i++) {
+ do_print = 0;
+ if (strcmp(mc_clients[i].name, "dummy") == 0)
+ continue;
+ /* Only print clients who actually have errors. */
+ for (j = 0; j < INTR_COUNT; j++) {
+ if (mc_clients[i].intr_counts[j]) {
+ do_print = 1;
+ break;
+ }
+ }
+ if (do_print)
+ seq_printf(s, fmt_cli,
+ mc_clients[i].swgid,
+ mc_clients[i].name,
+ mc_clients[i].intr_counts[0],
+ mc_clients[i].intr_counts[1],
+ mc_clients[i].intr_counts[2],
+ mc_clients[i].intr_counts[3],
+ mc_clients[i].intr_counts[4],
+ mc_clients[i].intr_counts[5],
+ mc_clients[i].intr_counts[6],
+ mc_clients[i].intr_counts[7]);
+ }
+ return 0;
+}
+
+/*
+ * Set up chip specific functions and data for handling this particular chip's
+ * error decoding and logging.
+ */
+void mcerr_chip_specific_setup(struct mcerr_chip_specific *spec)
+{
+ spec->mcerr_info_update = mcerr_t14x_info_update;
+ spec->mcerr_debugfs_show = mcerr_t14x_debugfs_show;
+ spec->nr_clients = ARRAY_SIZE(mc_clients);
+ return;
+}
diff --git a/drivers/platform/tegra/mc/mcerr-t3.c b/drivers/platform/tegra/mc/mcerr-t3.c
new file mode 100644
index 000000000000..50118f726879
--- /dev/null
+++ b/drivers/platform/tegra/mc/mcerr-t3.c
@@ -0,0 +1,104 @@
+/*
+ * Tegra 3 SoC-specific mcerr code.
+ *
+ * Copyright (c) 2010-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 <mach/mcerr.h>
+
+/*** Auto generated by `mcp.pl'. Do not modify! ***/
+
+#define dummy_client client("dummy", "dummy")
+
+struct mc_client mc_clients[] = {
+ client("ptc", "csr_ptcr"),
+ client("dc", "cbr_display0a"),
+ client("dcb", "cbr_display0ab"),
+ client("dc", "cbr_display0b"),
+ client("dcb", "cbr_display0bb"),
+ client("dc", "cbr_display0c"),
+ client("dcb", "cbr_display0cb"),
+ client("dc", "cbr_display1b"),
+ client("dcb", "cbr_display1bb"),
+ client("epp", "cbr_eppup"),
+ client("g2", "cbr_g2pr"),
+ client("g2", "cbr_g2sr"),
+ client("mpe", "cbr_mpeunifbr"),
+ client("vi", "cbr_viruv"),
+ client("afi", "csr_afir"),
+ client("avpc", "csr_avpcarm7r"),
+ client("dc", "csr_displayhc"),
+ client("dcb", "csr_displayhcb"),
+ client("nv", "csr_fdcdrd"),
+ client("nv2", "csr_fdcdrd2"),
+ client("g2", "csr_g2dr"),
+ client("hda", "csr_hdar"),
+ client("hc", "csr_host1xdmar"),
+ client("hc", "csr_host1xr"),
+ client("nv", "csr_idxsrd"),
+ client("nv2", "csr_idxsrd2"),
+ client("mpe", "csr_mpe_ipred"),
+ client("mpe", "csr_mpeamemrd"),
+ client("mpe", "csr_mpecsrd"),
+ client("ppcs", "csr_ppcsahbdmar"),
+ client("ppcs", "csr_ppcsahbslvr"),
+ client("sata", "csr_satar"),
+ client("nv", "csr_texsrd"),
+ client("nv2", "csr_texsrd2"),
+ client("vde", "csr_vdebsevr"),
+ client("vde", "csr_vdember"),
+ client("vde", "csr_vdemcer"),
+ client("vde", "csr_vdetper"),
+ client("mpcorelp", "csr_mpcorelpr"),
+ client("mpcore", "csr_mpcorer"),
+ client("epp", "cbw_eppu"),
+ client("epp", "cbw_eppv"),
+ client("epp", "cbw_eppy"),
+ client("mpe", "cbw_mpeunifbw"),
+ client("vi", "cbw_viwsb"),
+ client("vi", "cbw_viwu"),
+ client("vi", "cbw_viwv"),
+ client("vi", "cbw_viwy"),
+ client("g2", "ccw_g2dw"),
+ client("afi", "csw_afiw"),
+ client("avpc", "csw_avpcarm7w"),
+ client("nv", "csw_fdcdwr"),
+ client("nv2", "csw_fdcdwr2"),
+ client("hda", "csw_hdaw"),
+ client("hc", "csw_host1xw"),
+ client("isp", "csw_ispw"),
+ client("mpcorelp", "csw_mpcorelpw"),
+ client("mpcore", "csw_mpcorew"),
+ client("mpe", "csw_mpecswr"),
+ client("ppcs", "csw_ppcsahbdmaw"),
+ client("ppcs", "csw_ppcsahbslvw"),
+ client("sata", "csw_sataw"),
+ client("vde", "csw_vdebsevw"),
+ client("vde", "csw_vdedbgw"),
+ client("vde", "csw_vdembew"),
+ client("vde", "csw_vdetpmw"),
+};
+int mc_client_last = ARRAY_SIZE(mc_clients) - 1;
+/*** Done. ***/
+
+/*
+ * Defaults work for T30.
+ */
+void mcerr_chip_specific_setup(struct mcerr_chip_specific *spec)
+{
+ return;
+}
diff --git a/drivers/platform/tegra/mc/mcerr.c b/drivers/platform/tegra/mc/mcerr.c
new file mode 100644
index 000000000000..5aa8c4a5da5a
--- /dev/null
+++ b/drivers/platform/tegra/mc/mcerr.c
@@ -0,0 +1,442 @@
+/*
+ * arch/arm/mach-tegra/mcerr.c
+ *
+ * MC error code common to T3x and T11x. T20 has been left alone.
+ *
+ * Copyright (c) 2010-2014, NVIDIA Corporation. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "mc-err: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock_types.h>
+
+#include <mach/mc.h>
+#include <mach/irqs.h>
+#include <mach/mcerr.h>
+
+static bool mcerr_throttle_enabled = true;
+
+static int arb_intr_mma_set(const char *arg, const struct kernel_param *kp);
+static int arb_intr_mma_get(char *buff, const struct kernel_param *kp);
+static void unthrottle_prints(struct work_struct *work);
+
+static int spurious_intrs;
+
+static struct arb_emem_intr_info arb_intr_info = {
+ .lock = __SPIN_LOCK_UNLOCKED(arb_intr_info.lock),
+};
+static int arb_intr_count;
+
+static struct kernel_param_ops arb_intr_mma_ops = {
+ .get = arb_intr_mma_get,
+ .set = arb_intr_mma_set,
+};
+
+module_param_cb(arb_intr_mma_in_ms, &arb_intr_mma_ops,
+ &arb_intr_info.arb_intr_mma, S_IRUGO | S_IWUSR);
+module_param(arb_intr_count, int, S_IRUGO | S_IWUSR);
+module_param(spurious_intrs, int, S_IRUGO | S_IWUSR);
+
+static const char *const smmu_page_attrib[] = {
+ "nr-nw-s",
+ "nr-nw-ns",
+ "nr-wr-s",
+ "nr-wr-ns",
+ "rd-nw-s",
+ "rd-nw-ns",
+ "rd-wr-s",
+ "rd-wr-ns"
+};
+
+/*
+ * Table of known errors and their interrupt signatures.
+ */
+static const struct mc_error mc_errors[] = {
+ MC_ERR(MC_INT_DECERR_EMEM,
+ "EMEM address decode error",
+ 0, MC_ERR_STATUS, MC_ERR_ADR),
+ MC_ERR(MC_INT_DECERR_VPR,
+ "MC request violates VPR requirments",
+ 0, MC_ERR_VPR_STATUS, MC_ERR_VPR_ADR),
+ MC_ERR(MC_INT_SECURITY_VIOLATION,
+ "non secure access to secure region",
+ 0, MC_ERR_STATUS, MC_ERR_ADR),
+ MC_ERR(MC_INT_SECERR_SEC,
+ "MC request violated SEC carveout requirements",
+ 0, MC_ERR_SEC_STATUS, MC_ERR_SEC_ADR),
+
+ /*
+ * SMMU related faults.
+ */
+ MC_ERR(MC_INT_INVALID_SMMU_PAGE,
+ "SMMU address translation fault",
+ E_SMMU, MC_ERR_STATUS, MC_ERR_ADR),
+ MC_ERR(MC_INT_INVALID_SMMU_PAGE | MC_INT_DECERR_EMEM,
+ "EMEM decode error on PDE or PTE entry",
+ E_SMMU, MC_ERR_STATUS, MC_ERR_ADR),
+ MC_ERR(MC_INT_INVALID_SMMU_PAGE | MC_INT_SECERR_SEC,
+ "secure SMMU address translation fault",
+ E_SMMU, MC_ERR_SEC_STATUS, MC_ERR_SEC_ADR),
+ MC_ERR(MC_INT_INVALID_SMMU_PAGE | MC_INT_DECERR_VPR,
+ "VPR SMMU address translation fault",
+ E_SMMU, MC_ERR_VPR_STATUS, MC_ERR_VPR_ADR),
+
+ /*
+ * Baseband controller related faults.
+ */
+ MC_ERR(MC_INT_BBC_PRIVATE_MEM_VIOLATION,
+ "client accessed BBC aperture",
+ 0, MC_ERR_BBC_STATUS, MC_ERR_BBC_ADR),
+ MC_ERR(MC_INT_DECERR_BBC,
+ "BBC accessed memory outside of its aperture",
+ E_NO_STATUS, 0, 0),
+
+ /*
+ * MTS access violation.
+ */
+ MC_ERR(MC_INT_DECERR_MTS,
+ "MTS carveout access violation",
+ 0, MC_ERR_STATUS, MC_ERR_ADR),
+
+ /* NULL terminate. */
+ MC_ERR(0, NULL, 0, 0, 0),
+};
+
+static DEFINE_SPINLOCK(mc_lock);
+static unsigned long error_count;
+
+static DECLARE_DELAYED_WORK(unthrottle_prints_work, unthrottle_prints);
+
+static struct dentry *mcerr_debugfs_dir;
+
+/*
+ * Chip specific functions.
+ */
+static struct mcerr_chip_specific chip_specific;
+
+static int arb_intr_mma_set(const char *arg, const struct kernel_param *kp)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&arb_intr_info.lock, flags);
+ ret = param_set_int(arg, kp);
+ spin_unlock_irqrestore(&arb_intr_info.lock, flags);
+ return ret;
+}
+
+static int arb_intr_mma_get(char *buff, const struct kernel_param *kp)
+{
+ return param_get_int(buff, kp);
+}
+
+static void arb_intr(void)
+{
+ u64 time;
+ u32 time_diff_ms;
+ unsigned long flags;
+
+ spin_lock_irqsave(&arb_intr_info.lock, flags);
+ arb_intr_count++;
+ time = sched_clock();
+ time_diff_ms = (time - arb_intr_info.time) >> 20;
+ arb_intr_info.time = time;
+ arb_intr_info.arb_intr_mma =
+ ((MMA_HISTORY_SAMPLES - 1) * time_diff_ms +
+ arb_intr_info.arb_intr_mma) / MMA_HISTORY_SAMPLES;
+ spin_unlock_irqrestore(&arb_intr_info.lock, flags);
+}
+
+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);
+}
+
+/*
+ * Common MC error handling code.
+ */
+static irqreturn_t tegra_mc_error_isr(int irq, void *data)
+{
+ int err_mc = 0;
+ struct mc_client *client = NULL;
+ const struct mc_error *fault;
+ const char *smmu_info;
+ unsigned long count;
+ phys_addr_t addr;
+ u32 status, intr;
+ u32 write, secure;
+ u32 client_id;
+
+ intr = mc_readl(MC_INT_STATUS);
+
+ cancel_delayed_work(&unthrottle_prints_work);
+
+#ifdef MC_DUAL_CHANNEL
+ /*
+ * Interrupts can come from either MC; handle the case in which the
+ * interrupt is generated by the second MC.
+ */
+ if (intr & MC_INT_EXT_INTR_IN) {
+ err_mc = 1;
+ intr = __mc_readl(err_mc, MC_INT_STATUS);
+ }
+#endif
+
+ /*
+ * Sometimes the MC seems to generate spurious interrupts - that
+ * is interrupts with an interrupt status register equal to 0.
+ * Not much we can do other than keep a count of them.
+ */
+ if (!intr) {
+ spurious_intrs++;
+ goto out;
+ }
+
+ intr &= MC_INT_EN_MASK;
+ if (intr & MC_INT_ARBITRATION_EMEM) {
+ arb_intr();
+ if (intr == MC_INT_ARBITRATION_EMEM)
+ goto out;
+ intr &= ~MC_INT_ARBITRATION_EMEM;
+ }
+
+ spin_lock(&mc_lock);
+ count = ++error_count;
+ spin_unlock(&mc_lock);
+
+ fault = chip_specific.mcerr_info(intr & MC_INT_EN_MASK);
+ if (WARN(!fault, "[mcerr] Unknown error! intr sig: 0x%08x\n",
+ intr & MC_INT_EN_MASK))
+ goto out;
+
+ if (fault->flags & E_NO_STATUS) {
+ pr_err("[mcerr] MC fault - no status: %s\n", fault->msg);
+ goto out;
+ }
+
+ status = __mc_readl(err_mc, fault->stat_reg);
+ addr = __mc_readl(err_mc, fault->addr_reg);
+ secure = !!(status & MC_ERR_STATUS_SECURE);
+ write = !!(status & MC_ERR_STATUS_WRITE);
+ client_id = status & 0x7f;
+ client = &mc_clients[client_id <= mc_client_last
+ ? client_id : mc_client_last];
+
+#ifdef MC_ERR_34BIT_PHYS_ADDR
+ /*
+ * LPAE: make sure we get the extra 2 physical address bits available
+ * and pass them down to the printing function.
+ */
+ addr |= (((phys_addr_t)(status & MC_ERR_STATUS_ADR_HI)) << 12);
+#endif
+
+ if (fault->flags & E_SMMU)
+ smmu_info = smmu_page_attrib[MC_ERR_SMMU_BITS(status)];
+ else
+ smmu_info = NULL;
+
+ chip_specific.mcerr_info_update(client, intr & MC_INT_EN_MASK);
+
+ if (mcerr_throttle_enabled && count >= MAX_PRINTS) {
+ schedule_delayed_work(&unthrottle_prints_work, HZ/2);
+ if (count == MAX_PRINTS)
+ pr_err("Too many MC errors; throttling prints\n");
+ goto out;
+ }
+
+ chip_specific.mcerr_print(fault, client, status, addr, secure, write,
+ smmu_info);
+out:
+ __mc_writel(err_mc, intr, MC_INT_STATUS);
+ if (err_mc != 0) {
+ __mc_readl(err_mc, MC_INT_STATUS);
+ mc_writel(MC_INT_EXT_INTR_IN, MC_INT_STATUS);
+ }
+ return IRQ_HANDLED;
+}
+
+static const struct mc_error *mcerr_default_info(u32 intr)
+{
+ const struct mc_error *err;
+
+ for (err = mc_errors; err->sig && err->msg; err++) {
+ if (intr != err->sig)
+ continue;
+ return err;
+ }
+
+ return NULL;
+}
+
+static void mcerr_default_info_update(struct mc_client *c, u32 stat)
+{
+ if (stat & MC_INT_DECERR_EMEM)
+ c->intr_counts[0]++;
+ if (stat & MC_INT_SECURITY_VIOLATION)
+ c->intr_counts[1]++;
+ if (stat & MC_INT_INVALID_SMMU_PAGE)
+ c->intr_counts[2]++;
+
+ /* Unknown interrupts. */
+ if (stat & ~MC_INT_EN_MASK)
+ c->intr_counts[3]++;
+}
+
+/*
+ * This will print at least 8 hex digits for address. If the address is bigger
+ * then more digits will be printed but the full 16 hex digits for a 64 bit
+ * address will not get printed by the current code.
+ */
+static void mcerr_default_print(const struct mc_error *err,
+ const struct mc_client *client,
+ u32 status, phys_addr_t addr,
+ int secure, int rw, const char *smmu_info)
+{
+ pr_err("[mcerr] (%s) %s: %s\n", client->swgid, client->name, err->msg);
+ pr_err("[mcerr] status = 0x%08x; addr = 0x%08llx", status,
+ (long long unsigned int)addr);
+ pr_err("[mcerr] secure: %s, access-type: %s, SMMU fault: %s\n",
+ secure ? "yes" : "no", rw ? "write" : "read",
+ smmu_info ? smmu_info : "none");
+}
+
+/*
+ * Print the MC err stats for each client.
+ */
+static int mcerr_default_debugfs_show(struct seq_file *s, void *v)
+{
+ int i, j;
+ int do_print;
+
+ seq_printf(s, "%-24s %-24s %-9s %-9s %-9s %-9s\n", "swgid", "client",
+ "decerr", "secerr", "smmuerr", "unknown");
+ for (i = 0; i < chip_specific.nr_clients; i++) {
+ do_print = 0;
+
+ /* Only print clients who actually have errors. */
+ for (j = 0; j < INTR_COUNT; j++) {
+ if (mc_clients[i].intr_counts[j]) {
+ do_print = 1;
+ break;
+ }
+ }
+
+ if (do_print)
+ seq_printf(s, "%-24s %-24s %-9u %-9u %-9u %-9u\n",
+ mc_clients[i].name,
+ mc_clients[i].swgid,
+ mc_clients[i].intr_counts[0],
+ mc_clients[i].intr_counts[1],
+ mc_clients[i].intr_counts[2],
+ mc_clients[i].intr_counts[3]);
+ }
+ return 0;
+}
+
+static int mcerr_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, chip_specific.mcerr_debugfs_show, NULL);
+}
+
+static const struct file_operations mcerr_debugfs_fops = {
+ .open = mcerr_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __get_throttle(void *data, u64 *val)
+{
+ *val = mcerr_throttle_enabled;
+ return 0;
+}
+
+static int __set_throttle(void *data, u64 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mc_lock, flags);
+ error_count = 0;
+ spin_unlock_irqrestore(&mc_lock, flags);
+
+ mcerr_throttle_enabled = (bool) val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(mcerr_throttle_debugfs_fops, __get_throttle,
+ __set_throttle, "%llu\n");
+
+/*
+ * This will always e successful. However, if something goes wrong in the
+ * init a message will be printed to the kernel log. Since this is a
+ * non-essential piece of the kernel no reason to fail the entire MC init
+ * if this fails.
+ */
+int __init tegra_mcerr_init(struct dentry *mc_parent)
+{
+ u32 reg;
+
+ chip_specific.mcerr_info = mcerr_default_info;
+ chip_specific.mcerr_info_update = mcerr_default_info_update;
+ chip_specific.mcerr_print = mcerr_default_print;
+ chip_specific.mcerr_debugfs_show = mcerr_default_debugfs_show;
+ chip_specific.nr_clients = 0;
+
+ /*
+ * mcerr_chip_specific_setup() can override any of the default
+ * functions as it wishes.
+ */
+ mcerr_chip_specific_setup(&chip_specific);
+
+ 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__);
+ goto done;
+ } else {
+ reg = MC_INT_EN_MASK;
+ mc_writel(reg, MC_INT_MASK);
+ }
+
+ mcerr_debugfs_dir = debugfs_create_dir("err", mc_parent);
+ if (mcerr_debugfs_dir == NULL) {
+ pr_err("Failed to make debugfs node: %ld\n",
+ PTR_ERR(mcerr_debugfs_dir));
+ goto done;
+ }
+ debugfs_create_file("mcerr", 0644, mcerr_debugfs_dir, NULL,
+ &mcerr_debugfs_fops);
+ debugfs_create_file("mcerr_throttle", S_IRUGO | S_IWUSR,
+ mcerr_debugfs_dir, NULL,
+ &mcerr_throttle_debugfs_fops);
+
+ pr_info("Started MC error interface!\n");
+
+done:
+ return 0;
+}
diff --git a/drivers/platform/tegra/mcerr-t12.c b/drivers/platform/tegra/mcerr-t12.c
deleted file mode 100644
index 8339e4c9cc39..000000000000
--- a/drivers/platform/tegra/mcerr-t12.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Automatically generated file; DO NOT EDIT. */
-#include "../../../arch/arm/mach-tegra/mcerr-t12.c"
diff --git a/drivers/platform/tegra/mcerr.c b/drivers/platform/tegra/mcerr.c
deleted file mode 100644
index e09cf476ea49..000000000000
--- a/drivers/platform/tegra/mcerr.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Automatically generated file; DO NOT EDIT. */
-#include "../../../arch/arm/mach-tegra/mcerr.c"