summaryrefslogtreecommitdiffstats
path: root/drivers/memory
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2018-04-09 15:28:31 -0400
committerThierry Reding <treding@nvidia.com>2018-04-30 04:10:00 -0400
commita8d502fd33484ed8c4acc6acae73918844ca6811 (patch)
treec25a45b7d295e76825ccf602c41eebf7865cea9f /drivers/memory
parent85dce8918f90f71fc86ae822dd8cf4b738274f7e (diff)
memory: tegra: Squash tegra20-mc into common tegra-mc driver
Tegra30+ has some minor differences in registers / bits layout compared to Tegra20. Let's squash Tegra20 driver into the common tegra-mc driver in a preparation for the upcoming MC hot reset controls implementation, avoiding code duplication. Note that this currently doesn't report the value of MC_GART_ERROR_REQ because it is located within the GART register area and cannot be safely accessed from the MC driver (this happens to work only by accident). The proper solution is to integrate the GART driver with the MC driver, much like is done for the Tegra SMMU, but that is an invasive change and will be part of a separate patch series. Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/memory')
-rw-r--r--drivers/memory/Kconfig10
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/tegra/Makefile1
-rw-r--r--drivers/memory/tegra/mc.c112
-rw-r--r--drivers/memory/tegra/mc.h11
-rw-r--r--drivers/memory/tegra/tegra20.c178
-rw-r--r--drivers/memory/tegra20-mc.c254
7 files changed, 290 insertions, 277 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 19a0e83f260d..8d731d6c3e54 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -104,16 +104,6 @@ config MVEBU_DEVBUS
104 Armada 370 and Armada XP. This controller allows to handle flash 104 Armada 370 and Armada XP. This controller allows to handle flash
105 devices such as NOR, NAND, SRAM, and FPGA. 105 devices such as NOR, NAND, SRAM, and FPGA.
106 106
107config TEGRA20_MC
108 bool "Tegra20 Memory Controller(MC) driver"
109 default y
110 depends on ARCH_TEGRA_2x_SOC
111 help
112 This driver is for the Memory Controller(MC) module available
113 in Tegra20 SoCs, mainly for a address translation fault
114 analysis, especially for IOMMU/GART(Graphics Address
115 Relocation Table) module.
116
117config FSL_CORENET_CF 107config FSL_CORENET_CF
118 tristate "Freescale CoreNet Error Reporting" 108 tristate "Freescale CoreNet Error Reporting"
119 depends on FSL_SOC_BOOKE 109 depends on FSL_SOC_BOOKE
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 66f55240830e..a01ab3e22f94 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
16obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o 16obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
17obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 17obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
18obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 18obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
19obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
20obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o 19obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o
21obj-$(CONFIG_MTK_SMI) += mtk-smi.o 20obj-$(CONFIG_MTK_SMI) += mtk-smi.o
22obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o 21obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
index ce87a9470034..94ab16ba075b 100644
--- a/drivers/memory/tegra/Makefile
+++ b/drivers/memory/tegra/Makefile
@@ -1,6 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2tegra-mc-y := mc.o 2tegra-mc-y := mc.o
3 3
4tegra-mc-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o
4tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o 5tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o
5tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o 6tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
6tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o 7tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 60509f0a386b..b1a060ce8116 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -37,6 +37,9 @@
37 37
38#define MC_ERR_ADR 0x0c 38#define MC_ERR_ADR 0x0c
39 39
40#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
41#define MC_SECURITY_VIOLATION_STATUS 0x74
42
40#define MC_EMEM_ARB_CFG 0x90 43#define MC_EMEM_ARB_CFG 0x90
41#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) 44#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
42#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff 45#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
@@ -46,6 +49,9 @@
46#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) 49#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
47 50
48static const struct of_device_id tegra_mc_of_match[] = { 51static const struct of_device_id tegra_mc_of_match[] = {
52#ifdef CONFIG_ARCH_TEGRA_2x_SOC
53 { .compatible = "nvidia,tegra20-mc", .data = &tegra20_mc_soc },
54#endif
49#ifdef CONFIG_ARCH_TEGRA_3x_SOC 55#ifdef CONFIG_ARCH_TEGRA_3x_SOC
50 { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, 56 { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc },
51#endif 57#endif
@@ -221,6 +227,7 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
221static const char *const status_names[32] = { 227static const char *const status_names[32] = {
222 [ 1] = "External interrupt", 228 [ 1] = "External interrupt",
223 [ 6] = "EMEM address decode error", 229 [ 6] = "EMEM address decode error",
230 [ 7] = "GART page fault",
224 [ 8] = "Security violation", 231 [ 8] = "Security violation",
225 [ 9] = "EMEM arbitration error", 232 [ 9] = "EMEM arbitration error",
226 [10] = "Page fault", 233 [10] = "Page fault",
@@ -334,11 +341,78 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
334 return IRQ_HANDLED; 341 return IRQ_HANDLED;
335} 342}
336 343
344static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data)
345{
346 struct tegra_mc *mc = data;
347 unsigned long status;
348 unsigned int bit;
349
350 /* mask all interrupts to avoid flooding */
351 status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
352 if (!status)
353 return IRQ_NONE;
354
355 for_each_set_bit(bit, &status, 32) {
356 const char *direction = "read", *secure = "";
357 const char *error = status_names[bit];
358 const char *client, *desc;
359 phys_addr_t addr;
360 u32 value, reg;
361 u8 id, type;
362
363 switch (BIT(bit)) {
364 case MC_INT_DECERR_EMEM:
365 reg = MC_DECERR_EMEM_OTHERS_STATUS;
366 value = mc_readl(mc, reg);
367
368 id = value & mc->soc->client_id_mask;
369 desc = error_names[2];
370
371 if (value & BIT(31))
372 direction = "write";
373 break;
374
375 case MC_INT_INVALID_GART_PAGE:
376 dev_err_ratelimited(mc->dev, "%s\n", error);
377 continue;
378
379 case MC_INT_SECURITY_VIOLATION:
380 reg = MC_SECURITY_VIOLATION_STATUS;
381 value = mc_readl(mc, reg);
382
383 id = value & mc->soc->client_id_mask;
384 type = (value & BIT(30)) ? 4 : 3;
385 desc = error_names[type];
386 secure = "secure ";
387
388 if (value & BIT(31))
389 direction = "write";
390 break;
391
392 default:
393 continue;
394 }
395
396 client = mc->soc->clients[id].name;
397 addr = mc_readl(mc, reg + sizeof(u32));
398
399 dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
400 client, secure, direction, &addr, error,
401 desc);
402 }
403
404 /* clear interrupts */
405 mc_writel(mc, status, MC_INTSTATUS);
406
407 return IRQ_HANDLED;
408}
409
337static int tegra_mc_probe(struct platform_device *pdev) 410static int tegra_mc_probe(struct platform_device *pdev)
338{ 411{
339 const struct of_device_id *match; 412 const struct of_device_id *match;
340 struct resource *res; 413 struct resource *res;
341 struct tegra_mc *mc; 414 struct tegra_mc *mc;
415 void *isr;
342 int err; 416 int err;
343 417
344 match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); 418 match = of_match_node(tegra_mc_of_match, pdev->dev.of_node);
@@ -361,18 +435,32 @@ static int tegra_mc_probe(struct platform_device *pdev)
361 if (IS_ERR(mc->regs)) 435 if (IS_ERR(mc->regs))
362 return PTR_ERR(mc->regs); 436 return PTR_ERR(mc->regs);
363 437
364 mc->clk = devm_clk_get(&pdev->dev, "mc"); 438#ifdef CONFIG_ARCH_TEGRA_2x_SOC
365 if (IS_ERR(mc->clk)) { 439 if (mc->soc == &tegra20_mc_soc) {
366 dev_err(&pdev->dev, "failed to get MC clock: %ld\n", 440 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
367 PTR_ERR(mc->clk)); 441 mc->regs2 = devm_ioremap_resource(&pdev->dev, res);
368 return PTR_ERR(mc->clk); 442 if (IS_ERR(mc->regs2))
369 } 443 return PTR_ERR(mc->regs2);
370 444
371 err = tegra_mc_setup_latency_allowance(mc); 445 isr = tegra20_mc_irq;
372 if (err < 0) { 446 } else
373 dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", 447#endif
374 err); 448 {
375 return err; 449 mc->clk = devm_clk_get(&pdev->dev, "mc");
450 if (IS_ERR(mc->clk)) {
451 dev_err(&pdev->dev, "failed to get MC clock: %ld\n",
452 PTR_ERR(mc->clk));
453 return PTR_ERR(mc->clk);
454 }
455
456 err = tegra_mc_setup_latency_allowance(mc);
457 if (err < 0) {
458 dev_err(&pdev->dev, "failed to setup latency allowance: %d\n",
459 err);
460 return err;
461 }
462
463 isr = tegra_mc_irq;
376 } 464 }
377 465
378 err = tegra_mc_setup_timings(mc); 466 err = tegra_mc_setup_timings(mc);
@@ -400,7 +488,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
400 488
401 mc_writel(mc, mc->soc->intmask, MC_INTMASK); 489 mc_writel(mc, mc->soc->intmask, MC_INTMASK);
402 490
403 err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED, 491 err = devm_request_irq(&pdev->dev, mc->irq, isr, IRQF_SHARED,
404 dev_name(&pdev->dev), mc); 492 dev_name(&pdev->dev), mc);
405 if (err < 0) { 493 if (err < 0) {
406 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, 494 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index 24e020b4609b..cdd6911f4079 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -21,19 +21,30 @@
21#define MC_INT_INVALID_SMMU_PAGE (1 << 10) 21#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
22#define MC_INT_ARBITRATION_EMEM (1 << 9) 22#define MC_INT_ARBITRATION_EMEM (1 << 9)
23#define MC_INT_SECURITY_VIOLATION (1 << 8) 23#define MC_INT_SECURITY_VIOLATION (1 << 8)
24#define MC_INT_INVALID_GART_PAGE (1 << 7)
24#define MC_INT_DECERR_EMEM (1 << 6) 25#define MC_INT_DECERR_EMEM (1 << 6)
25 26
26static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) 27static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
27{ 28{
29 if (mc->regs2 && offset >= 0x24)
30 return readl(mc->regs2 + offset - 0x3c);
31
28 return readl(mc->regs + offset); 32 return readl(mc->regs + offset);
29} 33}
30 34
31static inline void mc_writel(struct tegra_mc *mc, u32 value, 35static inline void mc_writel(struct tegra_mc *mc, u32 value,
32 unsigned long offset) 36 unsigned long offset)
33{ 37{
38 if (mc->regs2 && offset >= 0x24)
39 return writel(value, mc->regs2 + offset - 0x3c);
40
34 writel(value, mc->regs + offset); 41 writel(value, mc->regs + offset);
35} 42}
36 43
44#ifdef CONFIG_ARCH_TEGRA_2x_SOC
45extern const struct tegra_mc_soc tegra20_mc_soc;
46#endif
47
37#ifdef CONFIG_ARCH_TEGRA_3x_SOC 48#ifdef CONFIG_ARCH_TEGRA_3x_SOC
38extern const struct tegra_mc_soc tegra30_mc_soc; 49extern const struct tegra_mc_soc tegra30_mc_soc;
39#endif 50#endif
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
new file mode 100644
index 000000000000..512a3418cb80
--- /dev/null
+++ b/drivers/memory/tegra/tegra20.c
@@ -0,0 +1,178 @@
1/*
2 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "mc.h"
10
11static const struct tegra_mc_client tegra20_mc_clients[] = {
12 {
13 .id = 0x00,
14 .name = "display0a",
15 }, {
16 .id = 0x01,
17 .name = "display0ab",
18 }, {
19 .id = 0x02,
20 .name = "display0b",
21 }, {
22 .id = 0x03,
23 .name = "display0bb",
24 }, {
25 .id = 0x04,
26 .name = "display0c",
27 }, {
28 .id = 0x05,
29 .name = "display0cb",
30 }, {
31 .id = 0x06,
32 .name = "display1b",
33 }, {
34 .id = 0x07,
35 .name = "display1bb",
36 }, {
37 .id = 0x08,
38 .name = "eppup",
39 }, {
40 .id = 0x09,
41 .name = "g2pr",
42 }, {
43 .id = 0x0a,
44 .name = "g2sr",
45 }, {
46 .id = 0x0b,
47 .name = "mpeunifbr",
48 }, {
49 .id = 0x0c,
50 .name = "viruv",
51 }, {
52 .id = 0x0d,
53 .name = "avpcarm7r",
54 }, {
55 .id = 0x0e,
56 .name = "displayhc",
57 }, {
58 .id = 0x0f,
59 .name = "displayhcb",
60 }, {
61 .id = 0x10,
62 .name = "fdcdrd",
63 }, {
64 .id = 0x11,
65 .name = "g2dr",
66 }, {
67 .id = 0x12,
68 .name = "host1xdmar",
69 }, {
70 .id = 0x13,
71 .name = "host1xr",
72 }, {
73 .id = 0x14,
74 .name = "idxsrd",
75 }, {
76 .id = 0x15,
77 .name = "mpcorer",
78 }, {
79 .id = 0x16,
80 .name = "mpe_ipred",
81 }, {
82 .id = 0x17,
83 .name = "mpeamemrd",
84 }, {
85 .id = 0x18,
86 .name = "mpecsrd",
87 }, {
88 .id = 0x19,
89 .name = "ppcsahbdmar",
90 }, {
91 .id = 0x1a,
92 .name = "ppcsahbslvr",
93 }, {
94 .id = 0x1b,
95 .name = "texsrd",
96 }, {
97 .id = 0x1c,
98 .name = "vdebsevr",
99 }, {
100 .id = 0x1d,
101 .name = "vdember",
102 }, {
103 .id = 0x1e,
104 .name = "vdemcer",
105 }, {
106 .id = 0x1f,
107 .name = "vdetper",
108 }, {
109 .id = 0x20,
110 .name = "eppu",
111 }, {
112 .id = 0x21,
113 .name = "eppv",
114 }, {
115 .id = 0x22,
116 .name = "eppy",
117 }, {
118 .id = 0x23,
119 .name = "mpeunifbw",
120 }, {
121 .id = 0x24,
122 .name = "viwsb",
123 }, {
124 .id = 0x25,
125 .name = "viwu",
126 }, {
127 .id = 0x26,
128 .name = "viwv",
129 }, {
130 .id = 0x27,
131 .name = "viwy",
132 }, {
133 .id = 0x28,
134 .name = "g2dw",
135 }, {
136 .id = 0x29,
137 .name = "avpcarm7w",
138 }, {
139 .id = 0x2a,
140 .name = "fdcdwr",
141 }, {
142 .id = 0x2b,
143 .name = "host1xw",
144 }, {
145 .id = 0x2c,
146 .name = "ispw",
147 }, {
148 .id = 0x2d,
149 .name = "mpcorew",
150 }, {
151 .id = 0x2e,
152 .name = "mpecswr",
153 }, {
154 .id = 0x2f,
155 .name = "ppcsahbdmaw",
156 }, {
157 .id = 0x30,
158 .name = "ppcsahbslvw",
159 }, {
160 .id = 0x31,
161 .name = "vdebsevw",
162 }, {
163 .id = 0x32,
164 .name = "vdembew",
165 }, {
166 .id = 0x33,
167 .name = "vdetpmw",
168 },
169};
170
171const struct tegra_mc_soc tegra20_mc_soc = {
172 .clients = tegra20_mc_clients,
173 .num_clients = ARRAY_SIZE(tegra20_mc_clients),
174 .num_address_bits = 32,
175 .client_id_mask = 0x3f,
176 .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
177 MC_INT_DECERR_EMEM,
178};
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
deleted file mode 100644
index cc309a05289a..000000000000
--- a/drivers/memory/tegra20-mc.c
+++ /dev/null
@@ -1,254 +0,0 @@
1/*
2 * Tegra20 Memory Controller
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <linux/err.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/ratelimit.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/io.h>
27
28#define DRV_NAME "tegra20-mc"
29
30#define MC_INTSTATUS 0x0
31#define MC_INTMASK 0x4
32
33#define MC_INT_ERR_SHIFT 6
34#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
35#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
36#define MC_INT_INVALID_GART_PAGE BIT(MC_INT_ERR_SHIFT + 1)
37#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
38#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
39
40#define MC_GART_ERROR_REQ 0x30
41#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
42#define MC_SECURITY_VIOLATION_STATUS 0x74
43
44#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
45
46#define MC_CLIENT_ID_MASK 0x3f
47
48#define NUM_MC_REG_BANKS 2
49
50struct tegra20_mc {
51 void __iomem *regs[NUM_MC_REG_BANKS];
52 struct device *dev;
53};
54
55static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs)
56{
57 u32 val = 0;
58
59 if (offs < 0x24)
60 val = readl(mc->regs[0] + offs);
61 else if (offs < 0x400)
62 val = readl(mc->regs[1] + offs - 0x3c);
63
64 return val;
65}
66
67static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs)
68{
69 if (offs < 0x24)
70 writel(val, mc->regs[0] + offs);
71 else if (offs < 0x400)
72 writel(val, mc->regs[1] + offs - 0x3c);
73}
74
75static const char * const tegra20_mc_client[] = {
76 "cbr_display0a",
77 "cbr_display0ab",
78 "cbr_display0b",
79 "cbr_display0bb",
80 "cbr_display0c",
81 "cbr_display0cb",
82 "cbr_display1b",
83 "cbr_display1bb",
84 "cbr_eppup",
85 "cbr_g2pr",
86 "cbr_g2sr",
87 "cbr_mpeunifbr",
88 "cbr_viruv",
89 "csr_avpcarm7r",
90 "csr_displayhc",
91 "csr_displayhcb",
92 "csr_fdcdrd",
93 "csr_g2dr",
94 "csr_host1xdmar",
95 "csr_host1xr",
96 "csr_idxsrd",
97 "csr_mpcorer",
98 "csr_mpe_ipred",
99 "csr_mpeamemrd",
100 "csr_mpecsrd",
101 "csr_ppcsahbdmar",
102 "csr_ppcsahbslvr",
103 "csr_texsrd",
104 "csr_vdebsevr",
105 "csr_vdember",
106 "csr_vdemcer",
107 "csr_vdetper",
108 "cbw_eppu",
109 "cbw_eppv",
110 "cbw_eppy",
111 "cbw_mpeunifbw",
112 "cbw_viwsb",
113 "cbw_viwu",
114 "cbw_viwv",
115 "cbw_viwy",
116 "ccw_g2dw",
117 "csw_avpcarm7w",
118 "csw_fdcdwr",
119 "csw_host1xw",
120 "csw_ispw",
121 "csw_mpcorew",
122 "csw_mpecswr",
123 "csw_ppcsahbdmaw",
124 "csw_ppcsahbslvw",
125 "csw_vdebsevw",
126 "csw_vdembew",
127 "csw_vdetpmw",
128};
129
130static void tegra20_mc_decode(struct tegra20_mc *mc, int n)
131{
132 u32 addr, req;
133 const char *client = "Unknown";
134 int idx, cid;
135 const struct reg_info {
136 u32 offset;
137 u32 write_bit; /* 0=READ, 1=WRITE */
138 int cid_shift;
139 char *message;
140 } reg[] = {
141 {
142 .offset = MC_DECERR_EMEM_OTHERS_STATUS,
143 .write_bit = 31,
144 .message = "MC_DECERR",
145 },
146 {
147 .offset = MC_GART_ERROR_REQ,
148 .cid_shift = 1,
149 .message = "MC_GART_ERR",
150
151 },
152 {
153 .offset = MC_SECURITY_VIOLATION_STATUS,
154 .write_bit = 31,
155 .message = "MC_SECURITY_ERR",
156 },
157 };
158
159 idx = n - MC_INT_ERR_SHIFT;
160 if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) {
161 dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
162 BIT(n));
163 return;
164 }
165
166 req = mc_readl(mc, reg[idx].offset);
167 cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK;
168 if (cid < ARRAY_SIZE(tegra20_mc_client))
169 client = tegra20_mc_client[cid];
170
171 addr = mc_readl(mc, reg[idx].offset + sizeof(u32));
172
173 dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n",
174 reg[idx].message, req, addr, client,
175 (req & BIT(reg[idx].write_bit)) ? "write" : "read",
176 (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ?
177 ((req & SECURITY_VIOLATION_TYPE) ?
178 "carveout" : "trustzone") : "");
179}
180
181static const struct of_device_id tegra20_mc_of_match[] = {
182 { .compatible = "nvidia,tegra20-mc", },
183 {},
184};
185
186static irqreturn_t tegra20_mc_isr(int irq, void *data)
187{
188 u32 stat, mask, bit;
189 struct tegra20_mc *mc = data;
190
191 stat = mc_readl(mc, MC_INTSTATUS);
192 mask = mc_readl(mc, MC_INTMASK);
193 mask &= stat;
194 if (!mask)
195 return IRQ_NONE;
196 while ((bit = ffs(mask)) != 0) {
197 tegra20_mc_decode(mc, bit - 1);
198 mask &= ~BIT(bit - 1);
199 }
200
201 mc_writel(mc, stat, MC_INTSTATUS);
202 return IRQ_HANDLED;
203}
204
205static int tegra20_mc_probe(struct platform_device *pdev)
206{
207 struct resource *irq;
208 struct tegra20_mc *mc;
209 int i, err;
210 u32 intmask;
211
212 mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
213 if (!mc)
214 return -ENOMEM;
215 mc->dev = &pdev->dev;
216
217 for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
218 struct resource *res;
219
220 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
221 mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
222 if (IS_ERR(mc->regs[i]))
223 return PTR_ERR(mc->regs[i]);
224 }
225
226 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
227 if (!irq)
228 return -ENODEV;
229 err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr,
230 IRQF_SHARED, dev_name(&pdev->dev), mc);
231 if (err)
232 return -ENODEV;
233
234 platform_set_drvdata(pdev, mc);
235
236 intmask = MC_INT_INVALID_GART_PAGE |
237 MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
238 mc_writel(mc, intmask, MC_INTMASK);
239 return 0;
240}
241
242static struct platform_driver tegra20_mc_driver = {
243 .probe = tegra20_mc_probe,
244 .driver = {
245 .name = DRV_NAME,
246 .of_match_table = tegra20_mc_of_match,
247 },
248};
249module_platform_driver(tegra20_mc_driver);
250
251MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
252MODULE_DESCRIPTION("Tegra20 MC driver");
253MODULE_LICENSE("GPL v2");
254MODULE_ALIAS("platform:" DRV_NAME);