aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/memory
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2018-05-25 08:14:34 -0400
committerOlof Johansson <olof@lixom.net>2018-05-25 08:14:34 -0400
commit6874f9de65314fcea76f7654ba93017616e6c2d9 (patch)
treeee8615063594e37df5b4a6fbbe1006505f3d8270 /drivers/memory
parent67a41cc86f372c418cef9af52993b1f6475b94ad (diff)
parenta1be3cfdfb81cc55c1b2feb73aca6945f61acddb (diff)
Merge tag 'tegra-for-4.18-memory-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers
memory: tegra: Changes for v4.18-rc1 This contains some cleanup of the memory controller driver as well as unification work to share more code between Tegra20 and later SoC generations. Also included are an implementation for the hot resets functionality by the memory controller which is required to properly reset busy hardware. * tag 'tegra-for-4.18-memory-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: dt-bindings: memory: tegra: Remove Tegra114 SATA and AFI reset definitions memory: tegra: Remove Tegra114 SATA and AFI reset definitions memory: tegra: Register SMMU after MC driver became ready memory: tegra: Add Tegra210 memory controller hot resets memory: tegra: Add Tegra124 memory controller hot resets memory: tegra: Add Tegra114 memory controller hot resets memory: tegra: Add Tegra30 memory controller hot resets memory: tegra: Add Tegra20 memory controller hot resets memory: tegra: Introduce memory client hot reset memory: tegra: Squash tegra20-mc into common tegra-mc driver memory: tegra: Remove unused headers inclusions memory: tegra: Apply interrupts mask per SoC memory: tegra: Setup interrupts mask before requesting IRQ memory: tegra: Do not handle spurious interrupts dt-bindings: memory: tegra: Add hot resets definitions Signed-off-by: Olof Johansson <olof@lixom.net>
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.c362
-rw-r--r--drivers/memory/tegra/mc.h22
-rw-r--r--drivers/memory/tegra/tegra114.c33
-rw-r--r--drivers/memory/tegra/tegra124.c48
-rw-r--r--drivers/memory/tegra/tegra20.c296
-rw-r--r--drivers/memory/tegra/tegra210.c53
-rw-r--r--drivers/memory/tegra/tegra30.c35
-rw-r--r--drivers/memory/tegra20-mc.c254
11 files changed, 807 insertions, 308 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 a4803ac192bb..bb93cc53554e 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -7,6 +7,7 @@
7 */ 7 */
8 8
9#include <linux/clk.h> 9#include <linux/clk.h>
10#include <linux/delay.h>
10#include <linux/interrupt.h> 11#include <linux/interrupt.h>
11#include <linux/kernel.h> 12#include <linux/kernel.h>
12#include <linux/module.h> 13#include <linux/module.h>
@@ -20,14 +21,6 @@
20#include "mc.h" 21#include "mc.h"
21 22
22#define MC_INTSTATUS 0x000 23#define MC_INTSTATUS 0x000
23#define MC_INT_DECERR_MTS (1 << 16)
24#define MC_INT_SECERR_SEC (1 << 13)
25#define MC_INT_DECERR_VPR (1 << 12)
26#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
27#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
28#define MC_INT_ARBITRATION_EMEM (1 << 9)
29#define MC_INT_SECURITY_VIOLATION (1 << 8)
30#define MC_INT_DECERR_EMEM (1 << 6)
31 24
32#define MC_INTMASK 0x004 25#define MC_INTMASK 0x004
33 26
@@ -45,6 +38,9 @@
45 38
46#define MC_ERR_ADR 0x0c 39#define MC_ERR_ADR 0x0c
47 40
41#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
42#define MC_SECURITY_VIOLATION_STATUS 0x74
43
48#define MC_EMEM_ARB_CFG 0x90 44#define MC_EMEM_ARB_CFG 0x90
49#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) 45#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
50#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff 46#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
@@ -54,6 +50,9 @@
54#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) 50#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
55 51
56static const struct of_device_id tegra_mc_of_match[] = { 52static const struct of_device_id tegra_mc_of_match[] = {
53#ifdef CONFIG_ARCH_TEGRA_2x_SOC
54 { .compatible = "nvidia,tegra20-mc", .data = &tegra20_mc_soc },
55#endif
57#ifdef CONFIG_ARCH_TEGRA_3x_SOC 56#ifdef CONFIG_ARCH_TEGRA_3x_SOC
58 { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, 57 { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc },
59#endif 58#endif
@@ -73,6 +72,207 @@ static const struct of_device_id tegra_mc_of_match[] = {
73}; 72};
74MODULE_DEVICE_TABLE(of, tegra_mc_of_match); 73MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
75 74
75static int terga_mc_block_dma_common(struct tegra_mc *mc,
76 const struct tegra_mc_reset *rst)
77{
78 unsigned long flags;
79 u32 value;
80
81 spin_lock_irqsave(&mc->lock, flags);
82
83 value = mc_readl(mc, rst->control) | BIT(rst->bit);
84 mc_writel(mc, value, rst->control);
85
86 spin_unlock_irqrestore(&mc->lock, flags);
87
88 return 0;
89}
90
91static bool terga_mc_dma_idling_common(struct tegra_mc *mc,
92 const struct tegra_mc_reset *rst)
93{
94 return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0;
95}
96
97static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
98 const struct tegra_mc_reset *rst)
99{
100 unsigned long flags;
101 u32 value;
102
103 spin_lock_irqsave(&mc->lock, flags);
104
105 value = mc_readl(mc, rst->control) & ~BIT(rst->bit);
106 mc_writel(mc, value, rst->control);
107
108 spin_unlock_irqrestore(&mc->lock, flags);
109
110 return 0;
111}
112
113static int terga_mc_reset_status_common(struct tegra_mc *mc,
114 const struct tegra_mc_reset *rst)
115{
116 return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0;
117}
118
119const struct tegra_mc_reset_ops terga_mc_reset_ops_common = {
120 .block_dma = terga_mc_block_dma_common,
121 .dma_idling = terga_mc_dma_idling_common,
122 .unblock_dma = terga_mc_unblock_dma_common,
123 .reset_status = terga_mc_reset_status_common,
124};
125
126static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev)
127{
128 return container_of(rcdev, struct tegra_mc, reset);
129}
130
131static const struct tegra_mc_reset *tegra_mc_reset_find(struct tegra_mc *mc,
132 unsigned long id)
133{
134 unsigned int i;
135
136 for (i = 0; i < mc->soc->num_resets; i++)
137 if (mc->soc->resets[i].id == id)
138 return &mc->soc->resets[i];
139
140 return NULL;
141}
142
143static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev,
144 unsigned long id)
145{
146 struct tegra_mc *mc = reset_to_mc(rcdev);
147 const struct tegra_mc_reset_ops *rst_ops;
148 const struct tegra_mc_reset *rst;
149 int retries = 500;
150 int err;
151
152 rst = tegra_mc_reset_find(mc, id);
153 if (!rst)
154 return -ENODEV;
155
156 rst_ops = mc->soc->reset_ops;
157 if (!rst_ops)
158 return -ENODEV;
159
160 if (rst_ops->block_dma) {
161 /* block clients DMA requests */
162 err = rst_ops->block_dma(mc, rst);
163 if (err) {
164 dev_err(mc->dev, "Failed to block %s DMA: %d\n",
165 rst->name, err);
166 return err;
167 }
168 }
169
170 if (rst_ops->dma_idling) {
171 /* wait for completion of the outstanding DMA requests */
172 while (!rst_ops->dma_idling(mc, rst)) {
173 if (!retries--) {
174 dev_err(mc->dev, "Failed to flush %s DMA\n",
175 rst->name);
176 return -EBUSY;
177 }
178
179 usleep_range(10, 100);
180 }
181 }
182
183 if (rst_ops->hotreset_assert) {
184 /* clear clients DMA requests sitting before arbitration */
185 err = rst_ops->hotreset_assert(mc, rst);
186 if (err) {
187 dev_err(mc->dev, "Failed to hot reset %s: %d\n",
188 rst->name, err);
189 return err;
190 }
191 }
192
193 return 0;
194}
195
196static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev,
197 unsigned long id)
198{
199 struct tegra_mc *mc = reset_to_mc(rcdev);
200 const struct tegra_mc_reset_ops *rst_ops;
201 const struct tegra_mc_reset *rst;
202 int err;
203
204 rst = tegra_mc_reset_find(mc, id);
205 if (!rst)
206 return -ENODEV;
207
208 rst_ops = mc->soc->reset_ops;
209 if (!rst_ops)
210 return -ENODEV;
211
212 if (rst_ops->hotreset_deassert) {
213 /* take out client from hot reset */
214 err = rst_ops->hotreset_deassert(mc, rst);
215 if (err) {
216 dev_err(mc->dev, "Failed to deassert hot reset %s: %d\n",
217 rst->name, err);
218 return err;
219 }
220 }
221
222 if (rst_ops->unblock_dma) {
223 /* allow new DMA requests to proceed to arbitration */
224 err = rst_ops->unblock_dma(mc, rst);
225 if (err) {
226 dev_err(mc->dev, "Failed to unblock %s DMA : %d\n",
227 rst->name, err);
228 return err;
229 }
230 }
231
232 return 0;
233}
234
235static int tegra_mc_hotreset_status(struct reset_controller_dev *rcdev,
236 unsigned long id)
237{
238 struct tegra_mc *mc = reset_to_mc(rcdev);
239 const struct tegra_mc_reset_ops *rst_ops;
240 const struct tegra_mc_reset *rst;
241
242 rst = tegra_mc_reset_find(mc, id);
243 if (!rst)
244 return -ENODEV;
245
246 rst_ops = mc->soc->reset_ops;
247 if (!rst_ops)
248 return -ENODEV;
249
250 return rst_ops->reset_status(mc, rst);
251}
252
253static const struct reset_control_ops tegra_mc_reset_ops = {
254 .assert = tegra_mc_hotreset_assert,
255 .deassert = tegra_mc_hotreset_deassert,
256 .status = tegra_mc_hotreset_status,
257};
258
259static int tegra_mc_reset_setup(struct tegra_mc *mc)
260{
261 int err;
262
263 mc->reset.ops = &tegra_mc_reset_ops;
264 mc->reset.owner = THIS_MODULE;
265 mc->reset.of_node = mc->dev->of_node;
266 mc->reset.of_reset_n_cells = 1;
267 mc->reset.nr_resets = mc->soc->num_resets;
268
269 err = reset_controller_register(&mc->reset);
270 if (err < 0)
271 return err;
272
273 return 0;
274}
275
76static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) 276static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
77{ 277{
78 unsigned long long tick; 278 unsigned long long tick;
@@ -229,6 +429,7 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc)
229static const char *const status_names[32] = { 429static const char *const status_names[32] = {
230 [ 1] = "External interrupt", 430 [ 1] = "External interrupt",
231 [ 6] = "EMEM address decode error", 431 [ 6] = "EMEM address decode error",
432 [ 7] = "GART page fault",
232 [ 8] = "Security violation", 433 [ 8] = "Security violation",
233 [ 9] = "EMEM arbitration error", 434 [ 9] = "EMEM arbitration error",
234 [10] = "Page fault", 435 [10] = "Page fault",
@@ -248,12 +449,13 @@ static const char *const error_names[8] = {
248static irqreturn_t tegra_mc_irq(int irq, void *data) 449static irqreturn_t tegra_mc_irq(int irq, void *data)
249{ 450{
250 struct tegra_mc *mc = data; 451 struct tegra_mc *mc = data;
251 unsigned long status, mask; 452 unsigned long status;
252 unsigned int bit; 453 unsigned int bit;
253 454
254 /* mask all interrupts to avoid flooding */ 455 /* mask all interrupts to avoid flooding */
255 status = mc_readl(mc, MC_INTSTATUS); 456 status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
256 mask = mc_readl(mc, MC_INTMASK); 457 if (!status)
458 return IRQ_NONE;
257 459
258 for_each_set_bit(bit, &status, 32) { 460 for_each_set_bit(bit, &status, 32) {
259 const char *error = status_names[bit] ?: "unknown"; 461 const char *error = status_names[bit] ?: "unknown";
@@ -341,12 +543,78 @@ static irqreturn_t tegra_mc_irq(int irq, void *data)
341 return IRQ_HANDLED; 543 return IRQ_HANDLED;
342} 544}
343 545
546static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data)
547{
548 struct tegra_mc *mc = data;
549 unsigned long status;
550 unsigned int bit;
551
552 /* mask all interrupts to avoid flooding */
553 status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
554 if (!status)
555 return IRQ_NONE;
556
557 for_each_set_bit(bit, &status, 32) {
558 const char *direction = "read", *secure = "";
559 const char *error = status_names[bit];
560 const char *client, *desc;
561 phys_addr_t addr;
562 u32 value, reg;
563 u8 id, type;
564
565 switch (BIT(bit)) {
566 case MC_INT_DECERR_EMEM:
567 reg = MC_DECERR_EMEM_OTHERS_STATUS;
568 value = mc_readl(mc, reg);
569
570 id = value & mc->soc->client_id_mask;
571 desc = error_names[2];
572
573 if (value & BIT(31))
574 direction = "write";
575 break;
576
577 case MC_INT_INVALID_GART_PAGE:
578 dev_err_ratelimited(mc->dev, "%s\n", error);
579 continue;
580
581 case MC_INT_SECURITY_VIOLATION:
582 reg = MC_SECURITY_VIOLATION_STATUS;
583 value = mc_readl(mc, reg);
584
585 id = value & mc->soc->client_id_mask;
586 type = (value & BIT(30)) ? 4 : 3;
587 desc = error_names[type];
588 secure = "secure ";
589
590 if (value & BIT(31))
591 direction = "write";
592 break;
593
594 default:
595 continue;
596 }
597
598 client = mc->soc->clients[id].name;
599 addr = mc_readl(mc, reg + sizeof(u32));
600
601 dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n",
602 client, secure, direction, &addr, error,
603 desc);
604 }
605
606 /* clear interrupts */
607 mc_writel(mc, status, MC_INTSTATUS);
608
609 return IRQ_HANDLED;
610}
611
344static int tegra_mc_probe(struct platform_device *pdev) 612static int tegra_mc_probe(struct platform_device *pdev)
345{ 613{
346 const struct of_device_id *match; 614 const struct of_device_id *match;
347 struct resource *res; 615 struct resource *res;
348 struct tegra_mc *mc; 616 struct tegra_mc *mc;
349 u32 value; 617 void *isr;
350 int err; 618 int err;
351 619
352 match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); 620 match = of_match_node(tegra_mc_of_match, pdev->dev.of_node);
@@ -358,6 +626,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
358 return -ENOMEM; 626 return -ENOMEM;
359 627
360 platform_set_drvdata(pdev, mc); 628 platform_set_drvdata(pdev, mc);
629 spin_lock_init(&mc->lock);
361 mc->soc = match->data; 630 mc->soc = match->data;
362 mc->dev = &pdev->dev; 631 mc->dev = &pdev->dev;
363 632
@@ -369,18 +638,32 @@ static int tegra_mc_probe(struct platform_device *pdev)
369 if (IS_ERR(mc->regs)) 638 if (IS_ERR(mc->regs))
370 return PTR_ERR(mc->regs); 639 return PTR_ERR(mc->regs);
371 640
372 mc->clk = devm_clk_get(&pdev->dev, "mc"); 641#ifdef CONFIG_ARCH_TEGRA_2x_SOC
373 if (IS_ERR(mc->clk)) { 642 if (mc->soc == &tegra20_mc_soc) {
374 dev_err(&pdev->dev, "failed to get MC clock: %ld\n", 643 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
375 PTR_ERR(mc->clk)); 644 mc->regs2 = devm_ioremap_resource(&pdev->dev, res);
376 return PTR_ERR(mc->clk); 645 if (IS_ERR(mc->regs2))
377 } 646 return PTR_ERR(mc->regs2);
378 647
379 err = tegra_mc_setup_latency_allowance(mc); 648 isr = tegra20_mc_irq;
380 if (err < 0) { 649 } else
381 dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", 650#endif
382 err); 651 {
383 return err; 652 mc->clk = devm_clk_get(&pdev->dev, "mc");
653 if (IS_ERR(mc->clk)) {
654 dev_err(&pdev->dev, "failed to get MC clock: %ld\n",
655 PTR_ERR(mc->clk));
656 return PTR_ERR(mc->clk);
657 }
658
659 err = tegra_mc_setup_latency_allowance(mc);
660 if (err < 0) {
661 dev_err(&pdev->dev, "failed to setup latency allowance: %d\n",
662 err);
663 return err;
664 }
665
666 isr = tegra_mc_irq;
384 } 667 }
385 668
386 err = tegra_mc_setup_timings(mc); 669 err = tegra_mc_setup_timings(mc);
@@ -389,13 +672,11 @@ static int tegra_mc_probe(struct platform_device *pdev)
389 return err; 672 return err;
390 } 673 }
391 674
392 if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { 675 err = tegra_mc_reset_setup(mc);
393 mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); 676 if (err < 0) {
394 if (IS_ERR(mc->smmu)) { 677 dev_err(&pdev->dev, "failed to register reset controller: %d\n",
395 dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", 678 err);
396 PTR_ERR(mc->smmu)); 679 return err;
397 return PTR_ERR(mc->smmu);
398 }
399 } 680 }
400 681
401 mc->irq = platform_get_irq(pdev, 0); 682 mc->irq = platform_get_irq(pdev, 0);
@@ -404,7 +685,11 @@ static int tegra_mc_probe(struct platform_device *pdev)
404 return mc->irq; 685 return mc->irq;
405 } 686 }
406 687
407 err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED, 688 WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n");
689
690 mc_writel(mc, mc->soc->intmask, MC_INTMASK);
691
692 err = devm_request_irq(&pdev->dev, mc->irq, isr, IRQF_SHARED,
408 dev_name(&pdev->dev), mc); 693 dev_name(&pdev->dev), mc);
409 if (err < 0) { 694 if (err < 0) {
410 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, 695 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
@@ -412,13 +697,14 @@ static int tegra_mc_probe(struct platform_device *pdev)
412 return err; 697 return err;
413 } 698 }
414 699
415 WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); 700 if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) {
416 701 mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
417 value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | 702 if (IS_ERR(mc->smmu)) {
418 MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | 703 dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
419 MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; 704 PTR_ERR(mc->smmu));
420 705 return PTR_ERR(mc->smmu);
421 mc_writel(mc, value, MC_INTMASK); 706 }
707 }
422 708
423 return 0; 709 return 0;
424} 710}
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index ddb16676c3af..01065f12ebeb 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -14,17 +14,39 @@
14 14
15#include <soc/tegra/mc.h> 15#include <soc/tegra/mc.h>
16 16
17#define MC_INT_DECERR_MTS (1 << 16)
18#define MC_INT_SECERR_SEC (1 << 13)
19#define MC_INT_DECERR_VPR (1 << 12)
20#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
21#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
22#define MC_INT_ARBITRATION_EMEM (1 << 9)
23#define MC_INT_SECURITY_VIOLATION (1 << 8)
24#define MC_INT_INVALID_GART_PAGE (1 << 7)
25#define MC_INT_DECERR_EMEM (1 << 6)
26
17static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) 27static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
18{ 28{
29 if (mc->regs2 && offset >= 0x24)
30 return readl(mc->regs2 + offset - 0x3c);
31
19 return readl(mc->regs + offset); 32 return readl(mc->regs + offset);
20} 33}
21 34
22static inline void mc_writel(struct tegra_mc *mc, u32 value, 35static inline void mc_writel(struct tegra_mc *mc, u32 value,
23 unsigned long offset) 36 unsigned long offset)
24{ 37{
38 if (mc->regs2 && offset >= 0x24)
39 return writel(value, mc->regs2 + offset - 0x3c);
40
25 writel(value, mc->regs + offset); 41 writel(value, mc->regs + offset);
26} 42}
27 43
44extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common;
45
46#ifdef CONFIG_ARCH_TEGRA_2x_SOC
47extern const struct tegra_mc_soc tegra20_mc_soc;
48#endif
49
28#ifdef CONFIG_ARCH_TEGRA_3x_SOC 50#ifdef CONFIG_ARCH_TEGRA_3x_SOC
29extern const struct tegra_mc_soc tegra30_mc_soc; 51extern const struct tegra_mc_soc tegra30_mc_soc;
30#endif 52#endif
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index b20e6e3e208e..6560a5101322 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -938,6 +938,34 @@ static const struct tegra_smmu_soc tegra114_smmu_soc = {
938 .num_asids = 4, 938 .num_asids = 4,
939}; 939};
940 940
941#define TEGRA114_MC_RESET(_name, _control, _status, _bit) \
942 { \
943 .name = #_name, \
944 .id = TEGRA114_MC_RESET_##_name, \
945 .control = _control, \
946 .status = _status, \
947 .bit = _bit, \
948 }
949
950static const struct tegra_mc_reset tegra114_mc_resets[] = {
951 TEGRA114_MC_RESET(AVPC, 0x200, 0x204, 1),
952 TEGRA114_MC_RESET(DC, 0x200, 0x204, 2),
953 TEGRA114_MC_RESET(DCB, 0x200, 0x204, 3),
954 TEGRA114_MC_RESET(EPP, 0x200, 0x204, 4),
955 TEGRA114_MC_RESET(2D, 0x200, 0x204, 5),
956 TEGRA114_MC_RESET(HC, 0x200, 0x204, 6),
957 TEGRA114_MC_RESET(HDA, 0x200, 0x204, 7),
958 TEGRA114_MC_RESET(ISP, 0x200, 0x204, 8),
959 TEGRA114_MC_RESET(MPCORE, 0x200, 0x204, 9),
960 TEGRA114_MC_RESET(MPCORELP, 0x200, 0x204, 10),
961 TEGRA114_MC_RESET(MPE, 0x200, 0x204, 11),
962 TEGRA114_MC_RESET(3D, 0x200, 0x204, 12),
963 TEGRA114_MC_RESET(3D2, 0x200, 0x204, 13),
964 TEGRA114_MC_RESET(PPCS, 0x200, 0x204, 14),
965 TEGRA114_MC_RESET(VDE, 0x200, 0x204, 16),
966 TEGRA114_MC_RESET(VI, 0x200, 0x204, 17),
967};
968
941const struct tegra_mc_soc tegra114_mc_soc = { 969const struct tegra_mc_soc tegra114_mc_soc = {
942 .clients = tegra114_mc_clients, 970 .clients = tegra114_mc_clients,
943 .num_clients = ARRAY_SIZE(tegra114_mc_clients), 971 .num_clients = ARRAY_SIZE(tegra114_mc_clients),
@@ -945,4 +973,9 @@ const struct tegra_mc_soc tegra114_mc_soc = {
945 .atom_size = 32, 973 .atom_size = 32,
946 .client_id_mask = 0x7f, 974 .client_id_mask = 0x7f,
947 .smmu = &tegra114_smmu_soc, 975 .smmu = &tegra114_smmu_soc,
976 .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
977 MC_INT_DECERR_EMEM,
978 .reset_ops = &terga_mc_reset_ops_common,
979 .resets = tegra114_mc_resets,
980 .num_resets = ARRAY_SIZE(tegra114_mc_resets),
948}; 981};
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 8b6360eabb8a..b561a1fe7f46 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1012,6 +1012,42 @@ static const struct tegra_smmu_group_soc tegra124_groups[] = {
1012 }, 1012 },
1013}; 1013};
1014 1014
1015#define TEGRA124_MC_RESET(_name, _control, _status, _bit) \
1016 { \
1017 .name = #_name, \
1018 .id = TEGRA124_MC_RESET_##_name, \
1019 .control = _control, \
1020 .status = _status, \
1021 .bit = _bit, \
1022 }
1023
1024static const struct tegra_mc_reset tegra124_mc_resets[] = {
1025 TEGRA124_MC_RESET(AFI, 0x200, 0x204, 0),
1026 TEGRA124_MC_RESET(AVPC, 0x200, 0x204, 1),
1027 TEGRA124_MC_RESET(DC, 0x200, 0x204, 2),
1028 TEGRA124_MC_RESET(DCB, 0x200, 0x204, 3),
1029 TEGRA124_MC_RESET(HC, 0x200, 0x204, 6),
1030 TEGRA124_MC_RESET(HDA, 0x200, 0x204, 7),
1031 TEGRA124_MC_RESET(ISP2, 0x200, 0x204, 8),
1032 TEGRA124_MC_RESET(MPCORE, 0x200, 0x204, 9),
1033 TEGRA124_MC_RESET(MPCORELP, 0x200, 0x204, 10),
1034 TEGRA124_MC_RESET(MSENC, 0x200, 0x204, 11),
1035 TEGRA124_MC_RESET(PPCS, 0x200, 0x204, 14),
1036 TEGRA124_MC_RESET(SATA, 0x200, 0x204, 15),
1037 TEGRA124_MC_RESET(VDE, 0x200, 0x204, 16),
1038 TEGRA124_MC_RESET(VI, 0x200, 0x204, 17),
1039 TEGRA124_MC_RESET(VIC, 0x200, 0x204, 18),
1040 TEGRA124_MC_RESET(XUSB_HOST, 0x200, 0x204, 19),
1041 TEGRA124_MC_RESET(XUSB_DEV, 0x200, 0x204, 20),
1042 TEGRA124_MC_RESET(TSEC, 0x200, 0x204, 21),
1043 TEGRA124_MC_RESET(SDMMC1, 0x200, 0x204, 22),
1044 TEGRA124_MC_RESET(SDMMC2, 0x200, 0x204, 23),
1045 TEGRA124_MC_RESET(SDMMC3, 0x200, 0x204, 25),
1046 TEGRA124_MC_RESET(SDMMC4, 0x970, 0x974, 0),
1047 TEGRA124_MC_RESET(ISP2B, 0x970, 0x974, 1),
1048 TEGRA124_MC_RESET(GPU, 0x970, 0x974, 2),
1049};
1050
1015#ifdef CONFIG_ARCH_TEGRA_124_SOC 1051#ifdef CONFIG_ARCH_TEGRA_124_SOC
1016static const struct tegra_smmu_soc tegra124_smmu_soc = { 1052static const struct tegra_smmu_soc tegra124_smmu_soc = {
1017 .clients = tegra124_mc_clients, 1053 .clients = tegra124_mc_clients,
@@ -1035,6 +1071,12 @@ const struct tegra_mc_soc tegra124_mc_soc = {
1035 .smmu = &tegra124_smmu_soc, 1071 .smmu = &tegra124_smmu_soc,
1036 .emem_regs = tegra124_mc_emem_regs, 1072 .emem_regs = tegra124_mc_emem_regs,
1037 .num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs), 1073 .num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
1074 .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
1075 MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
1076 MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
1077 .reset_ops = &terga_mc_reset_ops_common,
1078 .resets = tegra124_mc_resets,
1079 .num_resets = ARRAY_SIZE(tegra124_mc_resets),
1038}; 1080};
1039#endif /* CONFIG_ARCH_TEGRA_124_SOC */ 1081#endif /* CONFIG_ARCH_TEGRA_124_SOC */
1040 1082
@@ -1059,5 +1101,11 @@ const struct tegra_mc_soc tegra132_mc_soc = {
1059 .atom_size = 32, 1101 .atom_size = 32,
1060 .client_id_mask = 0x7f, 1102 .client_id_mask = 0x7f,
1061 .smmu = &tegra132_smmu_soc, 1103 .smmu = &tegra132_smmu_soc,
1104 .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
1105 MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
1106 MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
1107 .reset_ops = &terga_mc_reset_ops_common,
1108 .resets = tegra124_mc_resets,
1109 .num_resets = ARRAY_SIZE(tegra124_mc_resets),
1062}; 1110};
1063#endif /* CONFIG_ARCH_TEGRA_132_SOC */ 1111#endif /* CONFIG_ARCH_TEGRA_132_SOC */
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
new file mode 100644
index 000000000000..7119e532471c
--- /dev/null
+++ b/drivers/memory/tegra/tegra20.c
@@ -0,0 +1,296 @@
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 <dt-bindings/memory/tegra20-mc.h>
10
11#include "mc.h"
12
13static const struct tegra_mc_client tegra20_mc_clients[] = {
14 {
15 .id = 0x00,
16 .name = "display0a",
17 }, {
18 .id = 0x01,
19 .name = "display0ab",
20 }, {
21 .id = 0x02,
22 .name = "display0b",
23 }, {
24 .id = 0x03,
25 .name = "display0bb",
26 }, {
27 .id = 0x04,
28 .name = "display0c",
29 }, {
30 .id = 0x05,
31 .name = "display0cb",
32 }, {
33 .id = 0x06,
34 .name = "display1b",
35 }, {
36 .id = 0x07,
37 .name = "display1bb",
38 }, {
39 .id = 0x08,
40 .name = "eppup",
41 }, {
42 .id = 0x09,
43 .name = "g2pr",
44 }, {
45 .id = 0x0a,
46 .name = "g2sr",
47 }, {
48 .id = 0x0b,
49 .name = "mpeunifbr",
50 }, {
51 .id = 0x0c,
52 .name = "viruv",
53 }, {
54 .id = 0x0d,
55 .name = "avpcarm7r",
56 }, {
57 .id = 0x0e,
58 .name = "displayhc",
59 }, {
60 .id = 0x0f,
61 .name = "displayhcb",
62 }, {
63 .id = 0x10,
64 .name = "fdcdrd",
65 }, {
66 .id = 0x11,
67 .name = "g2dr",
68 }, {
69 .id = 0x12,
70 .name = "host1xdmar",
71 }, {
72 .id = 0x13,
73 .name = "host1xr",
74 }, {
75 .id = 0x14,
76 .name = "idxsrd",
77 }, {
78 .id = 0x15,
79 .name = "mpcorer",
80 }, {
81 .id = 0x16,
82 .name = "mpe_ipred",
83 }, {
84 .id = 0x17,
85 .name = "mpeamemrd",
86 }, {
87 .id = 0x18,
88 .name = "mpecsrd",
89 }, {
90 .id = 0x19,
91 .name = "ppcsahbdmar",
92 }, {
93 .id = 0x1a,
94 .name = "ppcsahbslvr",
95 }, {
96 .id = 0x1b,
97 .name = "texsrd",
98 }, {
99 .id = 0x1c,
100 .name = "vdebsevr",
101 }, {
102 .id = 0x1d,
103 .name = "vdember",
104 }, {
105 .id = 0x1e,
106 .name = "vdemcer",
107 }, {
108 .id = 0x1f,
109 .name = "vdetper",
110 }, {
111 .id = 0x20,
112 .name = "eppu",
113 }, {
114 .id = 0x21,
115 .name = "eppv",
116 }, {
117 .id = 0x22,
118 .name = "eppy",
119 }, {
120 .id = 0x23,
121 .name = "mpeunifbw",
122 }, {
123 .id = 0x24,
124 .name = "viwsb",
125 }, {
126 .id = 0x25,
127 .name = "viwu",
128 }, {
129 .id = 0x26,
130 .name = "viwv",
131 }, {
132 .id = 0x27,
133 .name = "viwy",
134 }, {
135 .id = 0x28,
136 .name = "g2dw",
137 }, {
138 .id = 0x29,
139 .name = "avpcarm7w",
140 }, {
141 .id = 0x2a,
142 .name = "fdcdwr",
143 }, {
144 .id = 0x2b,
145 .name = "host1xw",
146 }, {
147 .id = 0x2c,
148 .name = "ispw",
149 }, {
150 .id = 0x2d,
151 .name = "mpcorew",
152 }, {
153 .id = 0x2e,
154 .name = "mpecswr",
155 }, {
156 .id = 0x2f,
157 .name = "ppcsahbdmaw",
158 }, {
159 .id = 0x30,
160 .name = "ppcsahbslvw",
161 }, {
162 .id = 0x31,
163 .name = "vdebsevw",
164 }, {
165 .id = 0x32,
166 .name = "vdembew",
167 }, {
168 .id = 0x33,
169 .name = "vdetpmw",
170 },
171};
172
173#define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit) \
174 { \
175 .name = #_name, \
176 .id = TEGRA20_MC_RESET_##_name, \
177 .control = _control, \
178 .status = _status, \
179 .reset = _reset, \
180 .bit = _bit, \
181 }
182
183static const struct tegra_mc_reset tegra20_mc_resets[] = {
184 TEGRA20_MC_RESET(AVPC, 0x100, 0x140, 0x104, 0),
185 TEGRA20_MC_RESET(DC, 0x100, 0x144, 0x104, 1),
186 TEGRA20_MC_RESET(DCB, 0x100, 0x148, 0x104, 2),
187 TEGRA20_MC_RESET(EPP, 0x100, 0x14c, 0x104, 3),
188 TEGRA20_MC_RESET(2D, 0x100, 0x150, 0x104, 4),
189 TEGRA20_MC_RESET(HC, 0x100, 0x154, 0x104, 5),
190 TEGRA20_MC_RESET(ISP, 0x100, 0x158, 0x104, 6),
191 TEGRA20_MC_RESET(MPCORE, 0x100, 0x15c, 0x104, 7),
192 TEGRA20_MC_RESET(MPEA, 0x100, 0x160, 0x104, 8),
193 TEGRA20_MC_RESET(MPEB, 0x100, 0x164, 0x104, 9),
194 TEGRA20_MC_RESET(MPEC, 0x100, 0x168, 0x104, 10),
195 TEGRA20_MC_RESET(3D, 0x100, 0x16c, 0x104, 11),
196 TEGRA20_MC_RESET(PPCS, 0x100, 0x170, 0x104, 12),
197 TEGRA20_MC_RESET(VDE, 0x100, 0x174, 0x104, 13),
198 TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14),
199};
200
201static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
202 const struct tegra_mc_reset *rst)
203{
204 unsigned long flags;
205 u32 value;
206
207 spin_lock_irqsave(&mc->lock, flags);
208
209 value = mc_readl(mc, rst->reset);
210 mc_writel(mc, value & ~BIT(rst->bit), rst->reset);
211
212 spin_unlock_irqrestore(&mc->lock, flags);
213
214 return 0;
215}
216
217static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
218 const struct tegra_mc_reset *rst)
219{
220 unsigned long flags;
221 u32 value;
222
223 spin_lock_irqsave(&mc->lock, flags);
224
225 value = mc_readl(mc, rst->reset);
226 mc_writel(mc, value | BIT(rst->bit), rst->reset);
227
228 spin_unlock_irqrestore(&mc->lock, flags);
229
230 return 0;
231}
232
233static int terga20_mc_block_dma(struct tegra_mc *mc,
234 const struct tegra_mc_reset *rst)
235{
236 unsigned long flags;
237 u32 value;
238
239 spin_lock_irqsave(&mc->lock, flags);
240
241 value = mc_readl(mc, rst->control) & ~BIT(rst->bit);
242 mc_writel(mc, value, rst->control);
243
244 spin_unlock_irqrestore(&mc->lock, flags);
245
246 return 0;
247}
248
249static bool terga20_mc_dma_idling(struct tegra_mc *mc,
250 const struct tegra_mc_reset *rst)
251{
252 return mc_readl(mc, rst->status) == 0;
253}
254
255static int terga20_mc_reset_status(struct tegra_mc *mc,
256 const struct tegra_mc_reset *rst)
257{
258 return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0;
259}
260
261static int terga20_mc_unblock_dma(struct tegra_mc *mc,
262 const struct tegra_mc_reset *rst)
263{
264 unsigned long flags;
265 u32 value;
266
267 spin_lock_irqsave(&mc->lock, flags);
268
269 value = mc_readl(mc, rst->control) | BIT(rst->bit);
270 mc_writel(mc, value, rst->control);
271
272 spin_unlock_irqrestore(&mc->lock, flags);
273
274 return 0;
275}
276
277const struct tegra_mc_reset_ops terga20_mc_reset_ops = {
278 .hotreset_assert = terga20_mc_hotreset_assert,
279 .hotreset_deassert = terga20_mc_hotreset_deassert,
280 .block_dma = terga20_mc_block_dma,
281 .dma_idling = terga20_mc_dma_idling,
282 .unblock_dma = terga20_mc_unblock_dma,
283 .reset_status = terga20_mc_reset_status,
284};
285
286const struct tegra_mc_soc tegra20_mc_soc = {
287 .clients = tegra20_mc_clients,
288 .num_clients = ARRAY_SIZE(tegra20_mc_clients),
289 .num_address_bits = 32,
290 .client_id_mask = 0x3f,
291 .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
292 MC_INT_DECERR_EMEM,
293 .reset_ops = &terga20_mc_reset_ops,
294 .resets = tegra20_mc_resets,
295 .num_resets = ARRAY_SIZE(tegra20_mc_resets),
296};
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index d398bcd3fc57..d00a77160407 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -6,11 +6,6 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <linux/of.h>
10#include <linux/mm.h>
11
12#include <asm/cacheflush.h>
13
14#include <dt-bindings/memory/tegra210-mc.h> 9#include <dt-bindings/memory/tegra210-mc.h>
15 10
16#include "mc.h" 11#include "mc.h"
@@ -1085,6 +1080,48 @@ static const struct tegra_smmu_soc tegra210_smmu_soc = {
1085 .num_asids = 128, 1080 .num_asids = 128,
1086}; 1081};
1087 1082
1083#define TEGRA210_MC_RESET(_name, _control, _status, _bit) \
1084 { \
1085 .name = #_name, \
1086 .id = TEGRA210_MC_RESET_##_name, \
1087 .control = _control, \
1088 .status = _status, \
1089 .bit = _bit, \
1090 }
1091
1092static const struct tegra_mc_reset tegra210_mc_resets[] = {
1093 TEGRA210_MC_RESET(AFI, 0x200, 0x204, 0),
1094 TEGRA210_MC_RESET(AVPC, 0x200, 0x204, 1),
1095 TEGRA210_MC_RESET(DC, 0x200, 0x204, 2),
1096 TEGRA210_MC_RESET(DCB, 0x200, 0x204, 3),
1097 TEGRA210_MC_RESET(HC, 0x200, 0x204, 6),
1098 TEGRA210_MC_RESET(HDA, 0x200, 0x204, 7),
1099 TEGRA210_MC_RESET(ISP2, 0x200, 0x204, 8),
1100 TEGRA210_MC_RESET(MPCORE, 0x200, 0x204, 9),
1101 TEGRA210_MC_RESET(NVENC, 0x200, 0x204, 11),
1102 TEGRA210_MC_RESET(PPCS, 0x200, 0x204, 14),
1103 TEGRA210_MC_RESET(SATA, 0x200, 0x204, 15),
1104 TEGRA210_MC_RESET(VI, 0x200, 0x204, 17),
1105 TEGRA210_MC_RESET(VIC, 0x200, 0x204, 18),
1106 TEGRA210_MC_RESET(XUSB_HOST, 0x200, 0x204, 19),
1107 TEGRA210_MC_RESET(XUSB_DEV, 0x200, 0x204, 20),
1108 TEGRA210_MC_RESET(A9AVP, 0x200, 0x204, 21),
1109 TEGRA210_MC_RESET(TSEC, 0x200, 0x204, 22),
1110 TEGRA210_MC_RESET(SDMMC1, 0x200, 0x204, 29),
1111 TEGRA210_MC_RESET(SDMMC2, 0x200, 0x204, 30),
1112 TEGRA210_MC_RESET(SDMMC3, 0x200, 0x204, 31),
1113 TEGRA210_MC_RESET(SDMMC4, 0x970, 0x974, 0),
1114 TEGRA210_MC_RESET(ISP2B, 0x970, 0x974, 1),
1115 TEGRA210_MC_RESET(GPU, 0x970, 0x974, 2),
1116 TEGRA210_MC_RESET(NVDEC, 0x970, 0x974, 5),
1117 TEGRA210_MC_RESET(APE, 0x970, 0x974, 6),
1118 TEGRA210_MC_RESET(SE, 0x970, 0x974, 7),
1119 TEGRA210_MC_RESET(NVJPG, 0x970, 0x974, 8),
1120 TEGRA210_MC_RESET(AXIAP, 0x970, 0x974, 11),
1121 TEGRA210_MC_RESET(ETR, 0x970, 0x974, 12),
1122 TEGRA210_MC_RESET(TSECB, 0x970, 0x974, 13),
1123};
1124
1088const struct tegra_mc_soc tegra210_mc_soc = { 1125const struct tegra_mc_soc tegra210_mc_soc = {
1089 .clients = tegra210_mc_clients, 1126 .clients = tegra210_mc_clients,
1090 .num_clients = ARRAY_SIZE(tegra210_mc_clients), 1127 .num_clients = ARRAY_SIZE(tegra210_mc_clients),
@@ -1092,4 +1129,10 @@ const struct tegra_mc_soc tegra210_mc_soc = {
1092 .atom_size = 64, 1129 .atom_size = 64,
1093 .client_id_mask = 0xff, 1130 .client_id_mask = 0xff,
1094 .smmu = &tegra210_smmu_soc, 1131 .smmu = &tegra210_smmu_soc,
1132 .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
1133 MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
1134 MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
1135 .reset_ops = &terga_mc_reset_ops_common,
1136 .resets = tegra210_mc_resets,
1137 .num_resets = ARRAY_SIZE(tegra210_mc_resets),
1095}; 1138};
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index d756c837f23e..bee5314ed404 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -960,6 +960,36 @@ static const struct tegra_smmu_soc tegra30_smmu_soc = {
960 .num_asids = 4, 960 .num_asids = 4,
961}; 961};
962 962
963#define TEGRA30_MC_RESET(_name, _control, _status, _bit) \
964 { \
965 .name = #_name, \
966 .id = TEGRA30_MC_RESET_##_name, \
967 .control = _control, \
968 .status = _status, \
969 .bit = _bit, \
970 }
971
972static const struct tegra_mc_reset tegra30_mc_resets[] = {
973 TEGRA30_MC_RESET(AFI, 0x200, 0x204, 0),
974 TEGRA30_MC_RESET(AVPC, 0x200, 0x204, 1),
975 TEGRA30_MC_RESET(DC, 0x200, 0x204, 2),
976 TEGRA30_MC_RESET(DCB, 0x200, 0x204, 3),
977 TEGRA30_MC_RESET(EPP, 0x200, 0x204, 4),
978 TEGRA30_MC_RESET(2D, 0x200, 0x204, 5),
979 TEGRA30_MC_RESET(HC, 0x200, 0x204, 6),
980 TEGRA30_MC_RESET(HDA, 0x200, 0x204, 7),
981 TEGRA30_MC_RESET(ISP, 0x200, 0x204, 8),
982 TEGRA30_MC_RESET(MPCORE, 0x200, 0x204, 9),
983 TEGRA30_MC_RESET(MPCORELP, 0x200, 0x204, 10),
984 TEGRA30_MC_RESET(MPE, 0x200, 0x204, 11),
985 TEGRA30_MC_RESET(3D, 0x200, 0x204, 12),
986 TEGRA30_MC_RESET(3D2, 0x200, 0x204, 13),
987 TEGRA30_MC_RESET(PPCS, 0x200, 0x204, 14),
988 TEGRA30_MC_RESET(SATA, 0x200, 0x204, 15),
989 TEGRA30_MC_RESET(VDE, 0x200, 0x204, 16),
990 TEGRA30_MC_RESET(VI, 0x200, 0x204, 17),
991};
992
963const struct tegra_mc_soc tegra30_mc_soc = { 993const struct tegra_mc_soc tegra30_mc_soc = {
964 .clients = tegra30_mc_clients, 994 .clients = tegra30_mc_clients,
965 .num_clients = ARRAY_SIZE(tegra30_mc_clients), 995 .num_clients = ARRAY_SIZE(tegra30_mc_clients),
@@ -967,4 +997,9 @@ const struct tegra_mc_soc tegra30_mc_soc = {
967 .atom_size = 16, 997 .atom_size = 16,
968 .client_id_mask = 0x7f, 998 .client_id_mask = 0x7f,
969 .smmu = &tegra30_smmu_soc, 999 .smmu = &tegra30_smmu_soc,
1000 .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
1001 MC_INT_DECERR_EMEM,
1002 .reset_ops = &terga_mc_reset_ops_common,
1003 .resets = tegra30_mc_resets,
1004 .num_resets = ARRAY_SIZE(tegra30_mc_resets),
970}; 1005};
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);