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. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmJ45n8QHGtyemtAa2Vy bmVsLm9yZwAKCRDBN2bmhouD1yuAD/4x9TrrxwuaB7JRASgZeMRgnvm79XJ0ovOM JqVqGTMemsabjQ/5Rb+ej7A4tY5rgE9bxdbWCIallcDdrJLin6RIW5Iz0/iOdWkz APodtJlz2GTndSh8KUqbKUZxNdZ1b8cNHO5AYZLPfWBrRerWaNAEgB9phe23TbB0 5IKrpu83QU5tMPmrS1Kk5hyXUMO1qhYkxizA3IbQk4bv9T+ydNvLRkawjzaUFLwF Jx14pJodAm1HQi6l2c708O/jDQqHu+lXg4kGTIYQl5jdRwDelUlYwdqy/PIkSFAC EKE9gPc0DfT2NP5ETbBe/YBfe/d9GKmTsgenS8yiazZpdaZ7seg4Gzj25jqf9Zdv DKxiQSs/uqWzcpQNbEMKlr3kFUzflI0+t8Vxz0VlNrhkPAKtCfJ9EMpk3Xp08v4Y Is9uim7VOGZGUUBY3+iDVbTB3Tm8RUbyFRl7ueYRajrgeDNizYBOShU7JaDp/KPw ed9pwrlpahKnmMncBpZhatItz1tLswcRpB8uYyKr9HiUbnsQLXcptUR+Wr5xl5zB Qi61aReiRFYh6TsGJrFFiIzCsY4fZcL5e2nWhjSO0dINkdnYpzT+tLMfcWEVgb6u nmGBOE/2CEuKAqp37jCgQsmYeRWqI+qjMKnd1sZZMXJ3mIePGvOalVIQZae0mMia hTMQB+VdnQ== =4R1U -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmJ5g9IACgkQmmx57+YA GNltsRAAsUblZURz4KScRt08Sv0S6ZD/kUknn5twhAI3yH1+6+DGaVV8Yd30Yhxh jVBBA32Gm/YY+TY6LUMmV7q272CgvwvI1A+meCMAYhweNcRznELekAz2RnwIqqgM aF+scOlnauTrPAEQ3M+4rprnNEU6PkiaBhV36j0jbr9XA+wXwXRZvRMiPBcH/cLn hBcLnURiKuj3Q05LFK2wbGM4YR6QqJ4O6gjFYHetNA3x0YIqjnmTDNwoHbbLkKg6 gawAowAegyHw7u1kkZppH19M3iGOczBWzyO1IWmYlk3YzO67wunk78A5g1QUq6ew ICiQliXtU1TueTDzMxxabCbiCsuvU/fyIe+TQNrrq+Y4OGCoyZBVx222noPrAIln 6jiynxTPjkXvcLg2IMYGTOY0UJuPXK7nO/mCVkod8YGa6KV7VgIq5fLDvxiIJ0up beUBcTszdagS+VpsebrpmHNvIx8TjZX7I8Y551qszvwf5UBdc4JJv1Q8TkBSdmnZ XhXvfqEOwbErwpQ0y+U5a27brJtV5oVAQWkbhXvMVd4KNxry9YTzxAWeGYygTdXB 7dcG665P8FBk1x78dRsX9hT/FKpyvbdrUx+SJuWKhd3VPNfe4tHF2LbjfNabndSI CSeeicFsJ+6sJV3mkYiEWRxvbPlxaFt7G/F1q3T+rwvaqsXkGCw= =7LsQ -----END PGP SIGNATURE----- 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/20220509160807.154187-1-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
6e6962ffe2
|
@ -9,6 +9,7 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra124.o
|
||||||
tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
||||||
tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
||||||
tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o
|
tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o
|
||||||
|
tegra-mc-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186.o tegra234.o
|
||||||
|
|
||||||
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
||||||
|
|
||||||
|
@ -19,5 +20,6 @@ obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o
|
||||||
obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o
|
obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o
|
||||||
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o
|
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o
|
||||||
obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o
|
obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o
|
||||||
|
obj-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186-emc.o
|
||||||
|
|
||||||
tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o
|
tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o
|
||||||
|
|
|
@ -44,6 +44,9 @@ static const struct of_device_id tegra_mc_of_match[] = {
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
#ifdef CONFIG_ARCH_TEGRA_194_SOC
|
||||||
{ .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
|
{ .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_ARCH_TEGRA_234_SOC
|
||||||
|
{ .compatible = "nvidia,tegra234-mc", .data = &tegra234_mc_soc },
|
||||||
#endif
|
#endif
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
@ -505,14 +508,54 @@ int tegra30_mc_probe(struct tegra_mc *mc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
|
const struct tegra_mc_ops tegra30_mc_ops = {
|
||||||
|
.probe = tegra30_mc_probe,
|
||||||
|
.handle_irq = tegra30_mc_handle_irq,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mc_global_intstatus_to_channel(const struct tegra_mc *mc, u32 status,
|
||||||
|
unsigned int *mc_channel)
|
||||||
|
{
|
||||||
|
if ((status & mc->soc->ch_intmask) == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*mc_channel = __ffs((status & mc->soc->ch_intmask) >>
|
||||||
|
mc->soc->global_intstatus_channel_shift);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 mc_channel_to_global_intstatus(const struct tegra_mc *mc,
|
||||||
|
unsigned int channel)
|
||||||
|
{
|
||||||
|
return BIT(channel) << mc->soc->global_intstatus_channel_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct tegra_mc *mc = data;
|
struct tegra_mc *mc = data;
|
||||||
|
unsigned int bit, channel;
|
||||||
unsigned long status;
|
unsigned long status;
|
||||||
unsigned int bit;
|
|
||||||
|
|
||||||
/* mask all interrupts to avoid flooding */
|
if (mc->soc->num_channels) {
|
||||||
status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
|
u32 global_status;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
global_status = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, MC_GLOBAL_INTSTATUS);
|
||||||
|
err = mc_global_intstatus_to_channel(mc, global_status, &channel);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err_ratelimited(mc->dev, "unknown interrupt channel 0x%08x\n",
|
||||||
|
global_status);
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mask all interrupts to avoid flooding */
|
||||||
|
status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmask;
|
||||||
|
} else {
|
||||||
|
status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
|
||||||
|
}
|
||||||
|
|
||||||
if (!status)
|
if (!status)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
@ -520,18 +563,70 @@ static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
|
||||||
const char *error = tegra_mc_status_names[bit] ?: "unknown";
|
const char *error = tegra_mc_status_names[bit] ?: "unknown";
|
||||||
const char *client = "unknown", *desc;
|
const char *client = "unknown", *desc;
|
||||||
const char *direction, *secure;
|
const char *direction, *secure;
|
||||||
|
u32 status_reg, addr_reg;
|
||||||
|
u32 intmask = BIT(bit);
|
||||||
phys_addr_t addr = 0;
|
phys_addr_t addr = 0;
|
||||||
|
#ifdef CONFIG_PHYS_ADDR_T_64BIT
|
||||||
|
u32 addr_hi_reg = 0;
|
||||||
|
#endif
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char perm[7];
|
char perm[7];
|
||||||
u8 id, type;
|
u8 id, type;
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
value = mc_readl(mc, MC_ERR_STATUS);
|
switch (intmask) {
|
||||||
|
case MC_INT_DECERR_VPR:
|
||||||
|
status_reg = MC_ERR_VPR_STATUS;
|
||||||
|
addr_reg = MC_ERR_VPR_ADR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MC_INT_SECERR_SEC:
|
||||||
|
status_reg = MC_ERR_SEC_STATUS;
|
||||||
|
addr_reg = MC_ERR_SEC_ADR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MC_INT_DECERR_MTS:
|
||||||
|
status_reg = MC_ERR_MTS_STATUS;
|
||||||
|
addr_reg = MC_ERR_MTS_ADR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MC_INT_DECERR_GENERALIZED_CARVEOUT:
|
||||||
|
status_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS;
|
||||||
|
addr_reg = MC_ERR_GENERALIZED_CARVEOUT_ADR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MC_INT_DECERR_ROUTE_SANITY:
|
||||||
|
status_reg = MC_ERR_ROUTE_SANITY_STATUS;
|
||||||
|
addr_reg = MC_ERR_ROUTE_SANITY_ADR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
status_reg = MC_ERR_STATUS;
|
||||||
|
addr_reg = MC_ERR_ADR;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PHYS_ADDR_T_64BIT
|
||||||
|
if (mc->soc->has_addr_hi_reg)
|
||||||
|
addr_hi_reg = MC_ERR_ADR_HI;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc->soc->num_channels)
|
||||||
|
value = mc_ch_readl(mc, channel, status_reg);
|
||||||
|
else
|
||||||
|
value = mc_readl(mc, status_reg);
|
||||||
|
|
||||||
#ifdef CONFIG_PHYS_ADDR_T_64BIT
|
#ifdef CONFIG_PHYS_ADDR_T_64BIT
|
||||||
if (mc->soc->num_address_bits > 32) {
|
if (mc->soc->num_address_bits > 32) {
|
||||||
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
|
if (addr_hi_reg) {
|
||||||
MC_ERR_STATUS_ADR_HI_MASK);
|
if (mc->soc->num_channels)
|
||||||
|
addr = mc_ch_readl(mc, channel, addr_hi_reg);
|
||||||
|
else
|
||||||
|
addr = mc_readl(mc, addr_hi_reg);
|
||||||
|
} else {
|
||||||
|
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
|
||||||
|
MC_ERR_STATUS_ADR_HI_MASK);
|
||||||
|
}
|
||||||
addr <<= 32;
|
addr <<= 32;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -588,7 +683,10 @@ static irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = mc_readl(mc, MC_ERR_ADR);
|
if (mc->soc->num_channels)
|
||||||
|
value = mc_ch_readl(mc, channel, addr_reg);
|
||||||
|
else
|
||||||
|
value = mc_readl(mc, addr_reg);
|
||||||
addr |= value;
|
addr |= value;
|
||||||
|
|
||||||
dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n",
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear interrupts */
|
/* clear interrupts */
|
||||||
mc_writel(mc, status, MC_INTSTATUS);
|
if (mc->soc->num_channels) {
|
||||||
|
mc_ch_writel(mc, channel, status, MC_INTSTATUS);
|
||||||
|
mc_ch_writel(mc, MC_BROADCAST_CHANNEL,
|
||||||
|
mc_channel_to_global_intstatus(mc, channel),
|
||||||
|
MC_GLOBAL_INTSTATUS);
|
||||||
|
} else {
|
||||||
|
mc_writel(mc, status, MC_INTSTATUS);
|
||||||
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct tegra_mc_ops tegra30_mc_ops = {
|
|
||||||
.probe = tegra30_mc_probe,
|
|
||||||
.handle_irq = tegra30_mc_handle_irq,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *const tegra_mc_status_names[32] = {
|
const char *const tegra_mc_status_names[32] = {
|
||||||
[ 1] = "External interrupt",
|
[ 1] = "External interrupt",
|
||||||
[ 6] = "EMEM address decode error",
|
[ 6] = "EMEM address decode error",
|
||||||
|
@ -619,6 +718,8 @@ const char *const tegra_mc_status_names[32] = {
|
||||||
[12] = "VPR violation",
|
[12] = "VPR violation",
|
||||||
[13] = "Secure carveout violation",
|
[13] = "Secure carveout violation",
|
||||||
[16] = "MTS carveout violation",
|
[16] = "MTS carveout violation",
|
||||||
|
[17] = "Generalized carveout violation",
|
||||||
|
[20] = "Route Sanity error",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *const tegra_mc_error_names[8] = {
|
const char *const tegra_mc_error_names[8] = {
|
||||||
|
@ -759,7 +860,11 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
|
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
|
||||||
|
|
||||||
mc_writel(mc, mc->soc->intmask, MC_INTMASK);
|
if (mc->soc->num_channels)
|
||||||
|
mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmask,
|
||||||
|
MC_INTMASK);
|
||||||
|
else
|
||||||
|
mc_writel(mc, mc->soc->intmask, MC_INTMASK);
|
||||||
|
|
||||||
err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
|
err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
|
||||||
dev_name(&pdev->dev), mc);
|
dev_name(&pdev->dev), mc);
|
||||||
|
|
|
@ -43,7 +43,21 @@
|
||||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
||||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
#define MC_TIMING_CONTROL_DBG 0xf8
|
||||||
#define MC_TIMING_CONTROL 0xfc
|
#define MC_TIMING_CONTROL 0xfc
|
||||||
|
#define MC_ERR_VPR_STATUS 0x654
|
||||||
|
#define MC_ERR_VPR_ADR 0x658
|
||||||
|
#define MC_ERR_SEC_STATUS 0x67c
|
||||||
|
#define MC_ERR_SEC_ADR 0x680
|
||||||
|
#define MC_ERR_MTS_STATUS 0x9b0
|
||||||
|
#define MC_ERR_MTS_ADR 0x9b4
|
||||||
|
#define MC_ERR_ROUTE_SANITY_STATUS 0x9c0
|
||||||
|
#define MC_ERR_ROUTE_SANITY_ADR 0x9c4
|
||||||
|
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
|
||||||
|
#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
|
||||||
|
#define MC_GLOBAL_INTSTATUS 0xf24
|
||||||
|
#define MC_ERR_ADR_HI 0x11fc
|
||||||
|
|
||||||
|
#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
|
||||||
|
#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
|
||||||
#define MC_INT_DECERR_MTS BIT(16)
|
#define MC_INT_DECERR_MTS BIT(16)
|
||||||
#define MC_INT_SECERR_SEC BIT(13)
|
#define MC_INT_SECERR_SEC BIT(13)
|
||||||
#define MC_INT_DECERR_VPR BIT(12)
|
#define MC_INT_DECERR_VPR BIT(12)
|
||||||
|
@ -78,6 +92,8 @@
|
||||||
|
|
||||||
#define MC_TIMING_UPDATE BIT(0)
|
#define MC_TIMING_UPDATE BIT(0)
|
||||||
|
|
||||||
|
#define MC_BROADCAST_CHANNEL ~0
|
||||||
|
|
||||||
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
|
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
|
||||||
{
|
{
|
||||||
val = val * percents;
|
val = val * percents;
|
||||||
|
@ -92,6 +108,30 @@ icc_provider_to_tegra_mc(struct icc_provider *provider)
|
||||||
return container_of(provider, struct tegra_mc, provider);
|
return container_of(provider, struct tegra_mc, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 mc_ch_readl(const struct tegra_mc *mc, int ch,
|
||||||
|
unsigned long offset)
|
||||||
|
{
|
||||||
|
if (!mc->bcast_ch_regs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ch == MC_BROADCAST_CHANNEL)
|
||||||
|
return readl_relaxed(mc->bcast_ch_regs + offset);
|
||||||
|
|
||||||
|
return readl_relaxed(mc->ch_regs[ch] + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mc_ch_writel(const struct tegra_mc *mc, int ch,
|
||||||
|
u32 value, unsigned long offset)
|
||||||
|
{
|
||||||
|
if (!mc->bcast_ch_regs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ch == MC_BROADCAST_CHANNEL)
|
||||||
|
writel_relaxed(value, mc->bcast_ch_regs + offset);
|
||||||
|
else
|
||||||
|
writel_relaxed(value, mc->ch_regs[ch] + offset);
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 mc_readl(const struct tegra_mc *mc, unsigned long offset)
|
static inline u32 mc_readl(const struct tegra_mc *mc, unsigned long offset)
|
||||||
{
|
{
|
||||||
return readl_relaxed(mc->regs + offset);
|
return readl_relaxed(mc->regs + offset);
|
||||||
|
@ -137,6 +177,10 @@ extern const struct tegra_mc_soc tegra186_mc_soc;
|
||||||
extern const struct tegra_mc_soc tegra194_mc_soc;
|
extern const struct tegra_mc_soc tegra194_mc_soc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_TEGRA_234_SOC
|
||||||
|
extern const struct tegra_mc_soc tegra234_mc_soc;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
|
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
|
||||||
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
|
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
|
||||||
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
|
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
|
||||||
|
@ -147,10 +191,12 @@ extern const struct tegra_mc_ops tegra30_mc_ops;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_TEGRA_186_SOC) || \
|
#if defined(CONFIG_ARCH_TEGRA_186_SOC) || \
|
||||||
defined(CONFIG_ARCH_TEGRA_194_SOC)
|
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
|
||||||
|
defined(CONFIG_ARCH_TEGRA_234_SOC)
|
||||||
extern const struct tegra_mc_ops tegra186_mc_ops;
|
extern const struct tegra_mc_ops tegra186_mc_ops;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
irqreturn_t tegra30_mc_handle_irq(int irq, void *data);
|
||||||
extern const char * const tegra_mc_status_names[32];
|
extern const char * const tegra_mc_status_names[32];
|
||||||
extern const char * const tegra_mc_error_names[8];
|
extern const char * const tegra_mc_error_names[8];
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,9 @@ static const struct of_device_id tegra186_emc_of_match[] = {
|
||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
|
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
|
||||||
{ .compatible = "nvidia,tegra194-emc" },
|
{ .compatible = "nvidia,tegra194-emc" },
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_ARCH_TEGRA_234_SOC)
|
||||||
|
{ .compatible = "nvidia,tegra234-emc" },
|
||||||
#endif
|
#endif
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include <dt-bindings/memory/tegra186-mc.h>
|
#include <dt-bindings/memory/tegra186-mc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "mc.h"
|
||||||
|
|
||||||
#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0)
|
#define MC_SID_STREAMID_OVERRIDE_MASK GENMASK(7, 0)
|
||||||
#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
|
#define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
|
||||||
#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
|
#define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
|
||||||
|
@ -48,8 +50,37 @@ static void tegra186_mc_program_sid(struct tegra_mc *mc)
|
||||||
|
|
||||||
static int tegra186_mc_probe(struct tegra_mc *mc)
|
static int tegra186_mc_probe(struct tegra_mc *mc)
|
||||||
{
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(mc->dev);
|
||||||
|
unsigned int i;
|
||||||
|
char name[8];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
mc->bcast_ch_regs = devm_platform_ioremap_resource_byname(pdev, "broadcast");
|
||||||
|
if (IS_ERR(mc->bcast_ch_regs)) {
|
||||||
|
if (PTR_ERR(mc->bcast_ch_regs) == -EINVAL) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"Broadcast channel is missing, please update your device-tree\n");
|
||||||
|
mc->bcast_ch_regs = NULL;
|
||||||
|
goto populate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PTR_ERR(mc->bcast_ch_regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->ch_regs = devm_kcalloc(mc->dev, mc->soc->num_channels, sizeof(*mc->ch_regs),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!mc->ch_regs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < mc->soc->num_channels; i++) {
|
||||||
|
snprintf(name, sizeof(name), "ch%u", i);
|
||||||
|
|
||||||
|
mc->ch_regs[i] = devm_platform_ioremap_resource_byname(pdev, name);
|
||||||
|
if (IS_ERR(mc->ch_regs[i]))
|
||||||
|
return PTR_ERR(mc->ch_regs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
populate:
|
||||||
err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev);
|
err = of_platform_populate(mc->dev->of_node, NULL, NULL, mc->dev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -144,6 +175,7 @@ const struct tegra_mc_ops tegra186_mc_ops = {
|
||||||
.remove = tegra186_mc_remove,
|
.remove = tegra186_mc_remove,
|
||||||
.resume = tegra186_mc_resume,
|
.resume = tegra186_mc_resume,
|
||||||
.probe_device = tegra186_mc_probe_device,
|
.probe_device = tegra186_mc_probe_device,
|
||||||
|
.handle_irq = tegra30_mc_handle_irq,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
|
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
|
||||||
|
@ -875,6 +907,13 @@ const struct tegra_mc_soc tegra186_mc_soc = {
|
||||||
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
|
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
|
||||||
.clients = tegra186_mc_clients,
|
.clients = tegra186_mc_clients,
|
||||||
.num_address_bits = 40,
|
.num_address_bits = 40,
|
||||||
|
.num_channels = 4,
|
||||||
|
.client_id_mask = 0xff,
|
||||||
|
.intmask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
|
||||||
|
MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||||
|
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||||
.ops = &tegra186_mc_ops,
|
.ops = &tegra186_mc_ops,
|
||||||
|
.ch_intmask = 0x0000000f,
|
||||||
|
.global_intstatus_channel_shift = 0,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1347,5 +1347,14 @@ const struct tegra_mc_soc tegra194_mc_soc = {
|
||||||
.num_clients = ARRAY_SIZE(tegra194_mc_clients),
|
.num_clients = ARRAY_SIZE(tegra194_mc_clients),
|
||||||
.clients = tegra194_mc_clients,
|
.clients = tegra194_mc_clients,
|
||||||
.num_address_bits = 40,
|
.num_address_bits = 40,
|
||||||
|
.num_channels = 16,
|
||||||
|
.client_id_mask = 0xff,
|
||||||
|
.intmask = MC_INT_DECERR_ROUTE_SANITY |
|
||||||
|
MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
|
||||||
|
MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||||
|
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||||
|
.has_addr_hi_reg = true,
|
||||||
.ops = &tegra186_mc_ops,
|
.ops = &tegra186_mc_ops,
|
||||||
|
.ch_intmask = 0x00000f00,
|
||||||
|
.global_intstatus_channel_shift = 8,
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021-2022, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <soc/tegra/mc.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/memory/tegra234-mc.h>
|
||||||
|
|
||||||
|
#include "mc.h"
|
||||||
|
|
||||||
|
static const struct tegra_mc_client tegra234_mc_clients[] = {
|
||||||
|
{
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_SDMMCRAB,
|
||||||
|
.name = "sdmmcrab",
|
||||||
|
.sid = TEGRA234_SID_SDMMC4,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x318,
|
||||||
|
.security = 0x31c,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_SDMMCWAB,
|
||||||
|
.name = "sdmmcwab",
|
||||||
|
.sid = TEGRA234_SID_SDMMC4,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x338,
|
||||||
|
.security = 0x33c,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_BPMPR,
|
||||||
|
.name = "bpmpr",
|
||||||
|
.sid = TEGRA234_SID_BPMP,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x498,
|
||||||
|
.security = 0x49c,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_BPMPW,
|
||||||
|
.name = "bpmpw",
|
||||||
|
.sid = TEGRA234_SID_BPMP,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x4a0,
|
||||||
|
.security = 0x4a4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_BPMPDMAR,
|
||||||
|
.name = "bpmpdmar",
|
||||||
|
.sid = TEGRA234_SID_BPMP,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x4a8,
|
||||||
|
.security = 0x4ac,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_BPMPDMAW,
|
||||||
|
.name = "bpmpdmaw",
|
||||||
|
.sid = TEGRA234_SID_BPMP,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x4b0,
|
||||||
|
.security = 0x4b4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_APEDMAR,
|
||||||
|
.name = "apedmar",
|
||||||
|
.sid = TEGRA234_SID_APE,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x4f8,
|
||||||
|
.security = 0x4fc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.id = TEGRA234_MEMORY_CLIENT_APEDMAW,
|
||||||
|
.name = "apedmaw",
|
||||||
|
.sid = TEGRA234_SID_APE,
|
||||||
|
.regs = {
|
||||||
|
.sid = {
|
||||||
|
.override = 0x500,
|
||||||
|
.security = 0x504,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct tegra_mc_soc tegra234_mc_soc = {
|
||||||
|
.num_clients = ARRAY_SIZE(tegra234_mc_clients),
|
||||||
|
.clients = tegra234_mc_clients,
|
||||||
|
.num_address_bits = 40,
|
||||||
|
.num_channels = 16,
|
||||||
|
.client_id_mask = 0x1ff,
|
||||||
|
.intmask = MC_INT_DECERR_ROUTE_SANITY |
|
||||||
|
MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
|
||||||
|
MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
|
||||||
|
MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
|
||||||
|
.has_addr_hi_reg = true,
|
||||||
|
.ops = &tegra186_mc_ops,
|
||||||
|
.ch_intmask = 0x0000ff00,
|
||||||
|
.global_intstatus_channel_shift = 8,
|
||||||
|
};
|
|
@ -193,11 +193,15 @@ struct tegra_mc_soc {
|
||||||
unsigned int num_address_bits;
|
unsigned int num_address_bits;
|
||||||
unsigned int atom_size;
|
unsigned int atom_size;
|
||||||
|
|
||||||
u8 client_id_mask;
|
u16 client_id_mask;
|
||||||
|
u8 num_channels;
|
||||||
|
|
||||||
const struct tegra_smmu_soc *smmu;
|
const struct tegra_smmu_soc *smmu;
|
||||||
|
|
||||||
u32 intmask;
|
u32 intmask;
|
||||||
|
u32 ch_intmask;
|
||||||
|
u32 global_intstatus_channel_shift;
|
||||||
|
bool has_addr_hi_reg;
|
||||||
|
|
||||||
const struct tegra_mc_reset_ops *reset_ops;
|
const struct tegra_mc_reset_ops *reset_ops;
|
||||||
const struct tegra_mc_reset *resets;
|
const struct tegra_mc_reset *resets;
|
||||||
|
@ -212,6 +216,8 @@ struct tegra_mc {
|
||||||
struct tegra_smmu *smmu;
|
struct tegra_smmu *smmu;
|
||||||
struct gart_device *gart;
|
struct gart_device *gart;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
|
void __iomem *bcast_ch_regs;
|
||||||
|
void __iomem **ch_regs;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue