Skip to content

Commit 6e6962f

Browse files
committed
Merge tag 'memory-controller-drv-tegra-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers
Memory controller drivers for v5.19 - Tegra SoC Add support for Tegra234 memory controller and for logging memory controller errors on Tegra186, Tegra194 and Tegra234. * tag 'memory-controller-drv-tegra-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: memory: tegra: Add MC error logging on Tegra186 onward memory: tegra: Add memory controller channels support memory: tegra: Add APE memory clients for Tegra234 memory: tegra: Add Tegra234 support Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 2b6866d + 54a85e0 commit 6e6962f

File tree

8 files changed

+339
-19
lines changed

8 files changed

+339
-19
lines changed

drivers/memory/tegra/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra124.o
99
tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
1010
tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
1111
tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o
12+
tegra-mc-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186.o tegra234.o
1213

1314
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
1415

@@ -19,5 +20,6 @@ obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o
1920
obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o
2021
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o
2122
obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o
23+
obj-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186-emc.o
2224

2325
tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o

drivers/memory/tegra/mc.c

Lines changed: 121 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ static const struct of_device_id tegra_mc_of_match[] = {
4444
#endif
4545
#ifdef CONFIG_ARCH_TEGRA_194_SOC
4646
{ .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
47+
#endif
48+
#ifdef CONFIG_ARCH_TEGRA_234_SOC
49+
{ .compatible = "nvidia,tegra234-mc", .data = &tegra234_mc_soc },
4750
#endif
4851
{ /* sentinel */ }
4952
};
@@ -505,33 +508,125 @@ int tegra30_mc_probe(struct tegra_mc *mc)
505508
return 0;
506509
}
507510

508-
static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
511+
const struct tegra_mc_ops tegra30_mc_ops = {
512+
.probe = tegra30_mc_probe,
513+
.handle_irq = tegra30_mc_handle_irq,
514+
};
515+
#endif
516+
517+
static int mc_global_intstatus_to_channel(const struct tegra_mc *mc, u32 status,
518+
unsigned int *mc_channel)
519+
{
520+
if ((status & mc->soc->ch_intmask) == 0)
521+
return -EINVAL;
522+
523+
*mc_channel = __ffs((status & mc->soc->ch_intmask) >>
524+
mc->soc->global_intstatus_channel_shift);
525+
526+
return 0;
527+
}
528+
529+
static u32 mc_channel_to_global_intstatus(const struct tegra_mc *mc,
530+
unsigned int channel)
531+
{
532+
return BIT(channel) << mc->soc->global_intstatus_channel_shift;
533+
}
534+
535+
irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
509536
{
510537
struct tegra_mc *mc = data;
538+
unsigned int bit, channel;
511539
unsigned long status;
512-
unsigned int bit;
513540

514-
/* mask all interrupts to avoid flooding */
515-
status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
541+
if (mc->soc->num_channels) {
542+
u32 global_status;
543+
int err;
544+
545+
global_status = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, MC_GLOBAL_INTSTATUS);
546+
err = mc_global_intstatus_to_channel(mc, global_status, &channel);
547+
if (err < 0) {
548+
dev_err_ratelimited(mc->dev, "unknown interrupt channel 0x%08x\n",
549+
global_status);
550+
return IRQ_NONE;
551+
}
552+
553+
/* mask all interrupts to avoid flooding */
554+
status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmask;
555+
} else {
556+
status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
557+
}
558+
516559
if (!status)
517560
return IRQ_NONE;
518561

519562
for_each_set_bit(bit, &status, 32) {
520563
const char *error = tegra_mc_status_names[bit] ?: "unknown";
521564
const char *client = "unknown", *desc;
522565
const char *direction, *secure;
566+
u32 status_reg, addr_reg;
567+
u32 intmask = BIT(bit);
523568
phys_addr_t addr = 0;
569+
#ifdef CONFIG_PHYS_ADDR_T_64BIT
570+
u32 addr_hi_reg = 0;
571+
#endif
524572
unsigned int i;
525573
char perm[7];
526574
u8 id, type;
527575
u32 value;
528576

529-
value = mc_readl(mc, MC_ERR_STATUS);
577+
switch (intmask) {
578+
case MC_INT_DECERR_VPR:
579+
status_reg = MC_ERR_VPR_STATUS;
580+
addr_reg = MC_ERR_VPR_ADR;
581+
break;
582+
583+
case MC_INT_SECERR_SEC:
584+
status_reg = MC_ERR_SEC_STATUS;
585+
addr_reg = MC_ERR_SEC_ADR;
586+
break;
587+
588+
case MC_INT_DECERR_MTS:
589+
status_reg = MC_ERR_MTS_STATUS;
590+
addr_reg = MC_ERR_MTS_ADR;
591+
break;
592+
593+
case MC_INT_DECERR_GENERALIZED_CARVEOUT:
594+
status_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS;
595+
addr_reg = MC_ERR_GENERALIZED_CARVEOUT_ADR;
596+
break;
597+
598+
case MC_INT_DECERR_ROUTE_SANITY:
599+
status_reg = MC_ERR_ROUTE_SANITY_STATUS;
600+
addr_reg = MC_ERR_ROUTE_SANITY_ADR;
601+
break;
602+
603+
default:
604+
status_reg = MC_ERR_STATUS;
605+
addr_reg = MC_ERR_ADR;
606+
607+
#ifdef CONFIG_PHYS_ADDR_T_64BIT
608+
if (mc->soc->has_addr_hi_reg)
609+
addr_hi_reg = MC_ERR_ADR_HI;
610+
#endif
611+
break;
612+
}
613+
614+
if (mc->soc->num_channels)
615+
value = mc_ch_readl(mc, channel, status_reg);
616+
else
617+
value = mc_readl(mc, status_reg);
530618

531619
#ifdef CONFIG_PHYS_ADDR_T_64BIT
532620
if (mc->soc->num_address_bits > 32) {
533-
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
534-
MC_ERR_STATUS_ADR_HI_MASK);
621+
if (addr_hi_reg) {
622+
if (mc->soc->num_channels)
623+
addr = mc_ch_readl(mc, channel, addr_hi_reg);
624+
else
625+
addr = mc_readl(mc, addr_hi_reg);
626+
} else {
627+
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
628+
MC_ERR_STATUS_ADR_HI_MASK);
629+
}
535630
addr <<= 32;
536631
}
537632
#endif
@@ -588,7 +683,10 @@ static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
588683
break;
589684
}
590685

591-
value = mc_readl(mc, MC_ERR_ADR);
686+
if (mc->soc->num_channels)
687+
value = mc_ch_readl(mc, channel, addr_reg);
688+
else
689+
value = mc_readl(mc, addr_reg);
592690
addr |= value;
593691

594692
dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n",
@@ -597,17 +695,18 @@ static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
597695
}
598696

599697
/* clear interrupts */
600-
mc_writel(mc, status, MC_INTSTATUS);
698+
if (mc->soc->num_channels) {
699+
mc_ch_writel(mc, channel, status, MC_INTSTATUS);
700+
mc_ch_writel(mc, MC_BROADCAST_CHANNEL,
701+
mc_channel_to_global_intstatus(mc, channel),
702+
MC_GLOBAL_INTSTATUS);
703+
} else {
704+
mc_writel(mc, status, MC_INTSTATUS);
705+
}
601706

602707
return IRQ_HANDLED;
603708
}
604709

605-
const struct tegra_mc_ops tegra30_mc_ops = {
606-
.probe = tegra30_mc_probe,
607-
.handle_irq = tegra30_mc_handle_irq,
608-
};
609-
#endif
610-
611710
const char *const tegra_mc_status_names[32] = {
612711
[ 1] = "External interrupt",
613712
[ 6] = "EMEM address decode error",
@@ -619,6 +718,8 @@ const char *const tegra_mc_status_names[32] = {
619718
[12] = "VPR violation",
620719
[13] = "Secure carveout violation",
621720
[16] = "MTS carveout violation",
721+
[17] = "Generalized carveout violation",
722+
[20] = "Route Sanity error",
622723
};
623724

624725
const char *const tegra_mc_error_names[8] = {
@@ -759,7 +860,11 @@ static int tegra_mc_probe(struct platform_device *pdev)
759860

760861
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
761862

762-
mc_writel(mc, mc->soc->intmask, MC_INTMASK);
863+
if (mc->soc->num_channels)
864+
mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmask,
865+
MC_INTMASK);
866+
else
867+
mc_writel(mc, mc->soc->intmask, MC_INTMASK);
763868

764869
err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
765870
dev_name(&pdev->dev), mc);

drivers/memory/tegra/mc.h

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,21 @@
4343
#define MC_EMEM_ARB_OVERRIDE 0xe8
4444
#define MC_TIMING_CONTROL_DBG 0xf8
4545
#define MC_TIMING_CONTROL 0xfc
46-
46+
#define MC_ERR_VPR_STATUS 0x654
47+
#define MC_ERR_VPR_ADR 0x658
48+
#define MC_ERR_SEC_STATUS 0x67c
49+
#define MC_ERR_SEC_ADR 0x680
50+
#define MC_ERR_MTS_STATUS 0x9b0
51+
#define MC_ERR_MTS_ADR 0x9b4
52+
#define MC_ERR_ROUTE_SANITY_STATUS 0x9c0
53+
#define MC_ERR_ROUTE_SANITY_ADR 0x9c4
54+
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
55+
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
56+
#define MC_GLOBAL_INTSTATUS 0xf24
57+
#define MC_ERR_ADR_HI 0x11fc
58+
59+
#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
60+
#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
4761
#define MC_INT_DECERR_MTS BIT(16)
4862
#define MC_INT_SECERR_SEC BIT(13)
4963
#define MC_INT_DECERR_VPR BIT(12)
@@ -78,6 +92,8 @@
7892

7993
#define MC_TIMING_UPDATE BIT(0)
8094

95+
#define MC_BROADCAST_CHANNEL ~0
96+
8197
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
8298
{
8399
val = val * percents;
@@ -92,6 +108,30 @@ icc_provider_to_tegra_mc(struct icc_provider *provider)
92108
return container_of(provider, struct tegra_mc, provider);
93109
}
94110

111+
static inline u32 mc_ch_readl(const struct tegra_mc *mc, int ch,
112+
unsigned long offset)
113+
{
114+
if (!mc->bcast_ch_regs)
115+
return 0;
116+
117+
if (ch == MC_BROADCAST_CHANNEL)
118+
return readl_relaxed(mc->bcast_ch_regs + offset);
119+
120+
return readl_relaxed(mc->ch_regs[ch] + offset);
121+
}
122+
123+
static inline void mc_ch_writel(const struct tegra_mc *mc, int ch,
124+
u32 value, unsigned long offset)
125+
{
126+
if (!mc->bcast_ch_regs)
127+
return;
128+
129+
if (ch == MC_BROADCAST_CHANNEL)
130+
writel_relaxed(value, mc->bcast_ch_regs + offset);
131+
else
132+
writel_relaxed(value, mc->ch_regs[ch] + offset);
133+
}
134+
95135
static inline u32 mc_readl(const struct tegra_mc *mc, unsigned long offset)
96136
{
97137
return readl_relaxed(mc->regs + offset);
@@ -137,6 +177,10 @@ extern const struct tegra_mc_soc tegra186_mc_soc;
137177
extern const struct tegra_mc_soc tegra194_mc_soc;
138178
#endif
139179

180+
#ifdef CONFIG_ARCH_TEGRA_234_SOC
181+
extern const struct tegra_mc_soc tegra234_mc_soc;
182+
#endif
183+
140184
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
141185
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
142186
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
@@ -147,10 +191,12 @@ extern const struct tegra_mc_ops tegra30_mc_ops;
147191
#endif
148192

149193
#if defined(CONFIG_ARCH_TEGRA_186_SOC) || \
150-
defined(CONFIG_ARCH_TEGRA_194_SOC)
194+
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
195+
defined(CONFIG_ARCH_TEGRA_234_SOC)
151196
extern const struct tegra_mc_ops tegra186_mc_ops;
152197
#endif
153198

199+
irqreturn_t tegra30_mc_handle_irq(int irq, void *data);
154200
extern const char * const tegra_mc_status_names[32];
155201
extern const char * const tegra_mc_error_names[8];
156202

drivers/memory/tegra/tegra186-emc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ static const struct of_device_id tegra186_emc_of_match[] = {
272272
#endif
273273
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
274274
{ .compatible = "nvidia,tegra194-emc" },
275+
#endif
276+
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
277+
{ .compatible = "nvidia,tegra234-emc" },
275278
#endif
276279
{ /* sentinel */ }
277280
};

drivers/memory/tegra/tegra186.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <dt-bindings/memory/tegra186-mc.h>
1717
#endif
1818

19+
#include "mc.h"
20+
1921
#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0)
2022
#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
2123
#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
@@ -48,8 +50,37 @@ static void tegra186_mc_program_sid(struct tegra_mc *mc)
4850

4951
static int tegra186_mc_probe(struct tegra_mc *mc)
5052
{
53+
struct platform_device *pdev = to_platform_device(mc->dev);
54+
unsigned int i;
55+
char name[8];
5156
int err;
5257

58+
mc->bcast_ch_regs = devm_platform_ioremap_resource_byname(pdev, "broadcast");
59+
if (IS_ERR(mc->bcast_ch_regs)) {
60+
if (PTR_ERR(mc->bcast_ch_regs) == -EINVAL) {
61+
dev_warn(&pdev->dev,
62+
"Broadcast channel is missing, please update your device-tree\n");
63+
mc->bcast_ch_regs = NULL;
64+
goto populate;
65+
}
66+
67+
return PTR_ERR(mc->bcast_ch_regs);
68+
}
69+
70+
mc->ch_regs = devm_kcalloc(mc->dev, mc->soc->num_channels, sizeof(*mc->ch_regs),
71+
GFP_KERNEL);
72+
if (!mc->ch_regs)
73+
return -ENOMEM;
74+
75+
for (i = 0; i < mc->soc->num_channels; i++) {
76+
snprintf(name, sizeof(name), "ch%u", i);
77+
78+
mc->ch_regs[i] = devm_platform_ioremap_resource_byname(pdev, name);
79+
if (IS_ERR(mc->ch_regs[i]))
80+
return PTR_ERR(mc->ch_regs[i]);
81+
}
82+
83+
populate:
5384
err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev);
5485
if (err < 0)
5586
return err;
@@ -144,6 +175,7 @@ const struct tegra_mc_ops tegra186_mc_ops = {
144175
.remove = tegra186_mc_remove,
145176
.resume = tegra186_mc_resume,
146177
.probe_device = tegra186_mc_probe_device,
178+
.handle_irq = tegra30_mc_handle_irq,
147179
};
148180

149181
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
@@ -875,6 +907,13 @@ const struct tegra_mc_soc tegra186_mc_soc = {
875907
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
876908
.clients = tegra186_mc_clients,
877909
.num_address_bits = 40,
910+
.num_channels = 4,
911+
.client_id_mask = 0xff,
912+
.intmask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
913+
MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
914+
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
878915
.ops = &tegra186_mc_ops,
916+
.ch_intmask = 0x0000000f,
917+
.global_intstatus_channel_shift = 0,
879918
};
880919
#endif

drivers/memory/tegra/tegra194.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,5 +1347,14 @@ const struct tegra_mc_soc tegra194_mc_soc = {
13471347
.num_clients = ARRAY_SIZE(tegra194_mc_clients),
13481348
.clients = tegra194_mc_clients,
13491349
.num_address_bits = 40,
1350+
.num_channels = 16,
1351+
.client_id_mask = 0xff,
1352+
.intmask = MC_INT_DECERR_ROUTE_SANITY |
1353+
MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
1354+
MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
1355+
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
1356+
.has_addr_hi_reg = true,
13501357
.ops = &tegra186_mc_ops,
1358+
.ch_intmask = 0x00000f00,
1359+
.global_intstatus_channel_shift = 8,
13511360
};

0 commit comments

Comments
 (0)