diff options
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/soc/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/bcm/brcmstb/biuctrl.c | 30 | ||||
-rw-r--r-- | drivers/soc/renesas/Kconfig | 14 | ||||
-rw-r--r-- | drivers/soc/renesas/rcar-rst.c | 2 | ||||
-rw-r--r-- | drivers/soc/sifive/Kconfig | 10 | ||||
-rw-r--r-- | drivers/soc/sifive/Makefile | 3 | ||||
-rw-r--r-- | drivers/soc/sifive/sifive_l2_cache.c | 178 |
8 files changed, 225 insertions, 14 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 833e04a7835c..1778f8c62861 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -14,6 +14,7 @@ source "drivers/soc/qcom/Kconfig" source "drivers/soc/renesas/Kconfig" source "drivers/soc/rockchip/Kconfig" source "drivers/soc/samsung/Kconfig" +source "drivers/soc/sifive/Kconfig" source "drivers/soc/sunxi/Kconfig" source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 2ec355003524..8b49d782a1ab 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -20,6 +20,7 @@ obj-y += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ +obj-$(CONFIG_SOC_SIFIVE) += sifive/ obj-y += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c index d326915e0f40..61731e01f94b 100644 --- a/drivers/soc/bcm/brcmstb/biuctrl.c +++ b/drivers/soc/bcm/brcmstb/biuctrl.c @@ -63,7 +63,7 @@ static const int b15_cpubiuctrl_regs[] = { [CPU_WRITEBACK_CTRL_REG] = -1, }; -/* Odd cases, e.g: 7260 */ +/* Odd cases, e.g: 7260A0 */ static const int b53_cpubiuctrl_no_wb_regs[] = { [CPU_CREDIT_REG] = 0x0b0, [CPU_MCP_FLOW_REG] = 0x0b4, @@ -76,6 +76,12 @@ static const int b53_cpubiuctrl_regs[] = { [CPU_WRITEBACK_CTRL_REG] = 0x22c, }; +static const int a72_cpubiuctrl_regs[] = { + [CPU_CREDIT_REG] = 0x18, + [CPU_MCP_FLOW_REG] = 0x1c, + [CPU_WRITEBACK_CTRL_REG] = 0x20, +}; + #define NUM_CPU_BIUCTRL_REGS 3 static int __init mcp_write_pairing_set(void) @@ -101,25 +107,29 @@ static int __init mcp_write_pairing_set(void) return 0; } -static const u32 b53_mach_compat[] = { +static const u32 a72_b53_mach_compat[] = { + 0x7211, + 0x7216, + 0x7255, + 0x7260, 0x7268, 0x7271, 0x7278, }; -static void __init mcp_b53_set(void) +static void __init mcp_a72_b53_set(void) { unsigned int i; u32 reg; reg = brcmstb_get_family_id(); - for (i = 0; i < ARRAY_SIZE(b53_mach_compat); i++) { - if (BRCM_ID(reg) == b53_mach_compat[i]) + for (i = 0; i < ARRAY_SIZE(a72_b53_mach_compat); i++) { + if (BRCM_ID(reg) == a72_b53_mach_compat[i]) break; } - if (i == ARRAY_SIZE(b53_mach_compat)) + if (i == ARRAY_SIZE(a72_b53_mach_compat)) return; /* Set all 3 MCP interfaces to 8 credits */ @@ -157,6 +167,7 @@ static void __init mcp_b53_set(void) static int __init setup_hifcpubiuctrl_regs(struct device_node *np) { struct device_node *cpu_dn; + u32 family_id; int ret = 0; cpubiuctrl_base = of_iomap(np, 0); @@ -179,13 +190,16 @@ static int __init setup_hifcpubiuctrl_regs(struct device_node *np) cpubiuctrl_regs = b15_cpubiuctrl_regs; else if (of_device_is_compatible(cpu_dn, "brcm,brahma-b53")) cpubiuctrl_regs = b53_cpubiuctrl_regs; + else if (of_device_is_compatible(cpu_dn, "arm,cortex-a72")) + cpubiuctrl_regs = a72_cpubiuctrl_regs; else { pr_err("unsupported CPU\n"); ret = -EINVAL; } of_node_put(cpu_dn); - if (BRCM_ID(brcmstb_get_family_id()) == 0x7260) + family_id = brcmstb_get_family_id(); + if (BRCM_ID(family_id) == 0x7260 && BRCM_REV(family_id) == 0) cpubiuctrl_regs = b53_cpubiuctrl_no_wb_regs; out: of_node_put(np); @@ -248,7 +262,7 @@ static int __init brcmstb_biuctrl_init(void) return ret; } - mcp_b53_set(); + mcp_a72_b53_set(); #ifdef CONFIG_PM_SLEEP register_syscore_ops(&brcmstb_cpu_credit_syscore_ops); #endif diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index f93492b72c04..ba2b8b51d2d9 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -192,21 +192,25 @@ config ARCH_R8A774C0 help This enables support for the Renesas RZ/G2E SoC. +config ARCH_R8A77950 + bool + +config ARCH_R8A77951 + bool + config ARCH_R8A7795 bool "Renesas R-Car H3 SoC Platform" + select ARCH_R8A77950 + select ARCH_R8A77951 select ARCH_RCAR_GEN3 select SYSC_R8A7795 help This enables support for the Renesas R-Car H3 SoC. config ARCH_R8A77960 - bool + bool "Renesas R-Car M3-W SoC Platform" select ARCH_RCAR_GEN3 select SYSC_R8A77960 - -config ARCH_R8A7796 - bool "Renesas R-Car M3-W SoC Platform" - select ARCH_R8A77960 help This enables support for the Renesas R-Car M3-W SoC. diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index 14d05a070dd3..2af2e0dd83fe 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -21,7 +21,7 @@ static int rcar_rst_enable_wdt_reset(void __iomem *base) struct rst_config { unsigned int modemr; /* Mode Monitoring Register Offset */ - int (*configure)(void *base); /* Platform specific configuration */ + int (*configure)(void __iomem *base); /* Platform specific config */ }; static const struct rst_config rcar_rst_gen1 __initconst = { diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig new file mode 100644 index 000000000000..58cf8c40d08d --- /dev/null +++ b/drivers/soc/sifive/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +if SOC_SIFIVE + +config SIFIVE_L2 + bool "Sifive L2 Cache controller" + help + Support for the L2 cache controller on SiFive platforms. + +endif diff --git a/drivers/soc/sifive/Makefile b/drivers/soc/sifive/Makefile new file mode 100644 index 000000000000..b5caff77938f --- /dev/null +++ b/drivers/soc/sifive/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SIFIVE_L2) += sifive_l2_cache.o diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c new file mode 100644 index 000000000000..a9ffff3277c7 --- /dev/null +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SiFive L2 cache controller Driver + * + * Copyright (C) 2018-2019 SiFive, Inc. + * + */ +#include <linux/debugfs.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <asm/sifive_l2_cache.h> + +#define SIFIVE_L2_DIRECCFIX_LOW 0x100 +#define SIFIVE_L2_DIRECCFIX_HIGH 0x104 +#define SIFIVE_L2_DIRECCFIX_COUNT 0x108 + +#define SIFIVE_L2_DATECCFIX_LOW 0x140 +#define SIFIVE_L2_DATECCFIX_HIGH 0x144 +#define SIFIVE_L2_DATECCFIX_COUNT 0x148 + +#define SIFIVE_L2_DATECCFAIL_LOW 0x160 +#define SIFIVE_L2_DATECCFAIL_HIGH 0x164 +#define SIFIVE_L2_DATECCFAIL_COUNT 0x168 + +#define SIFIVE_L2_CONFIG 0x00 +#define SIFIVE_L2_WAYENABLE 0x08 +#define SIFIVE_L2_ECCINJECTERR 0x40 + +#define SIFIVE_L2_MAX_ECCINTR 3 + +static void __iomem *l2_base; +static int g_irq[SIFIVE_L2_MAX_ECCINTR]; + +enum { + DIR_CORR = 0, + DATA_CORR, + DATA_UNCORR, +}; + +#ifdef CONFIG_DEBUG_FS +static struct dentry *sifive_test; + +static ssize_t l2_write(struct file *file, const char __user *data, + size_t count, loff_t *ppos) +{ + unsigned int val; + + if (kstrtouint_from_user(data, count, 0, &val)) + return -EINVAL; + if ((val >= 0 && val < 0xFF) || (val >= 0x10000 && val < 0x100FF)) + writel(val, l2_base + SIFIVE_L2_ECCINJECTERR); + else + return -EINVAL; + return count; +} + +static const struct file_operations l2_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = l2_write +}; + +static void setup_sifive_debug(void) +{ + sifive_test = debugfs_create_dir("sifive_l2_cache", NULL); + + debugfs_create_file("sifive_debug_inject_error", 0200, + sifive_test, NULL, &l2_fops); +} +#endif + +static void l2_config_read(void) +{ + u32 regval, val; + + regval = readl(l2_base + SIFIVE_L2_CONFIG); + val = regval & 0xFF; + pr_info("L2CACHE: No. of Banks in the cache: %d\n", val); + val = (regval & 0xFF00) >> 8; + pr_info("L2CACHE: No. of ways per bank: %d\n", val); + val = (regval & 0xFF0000) >> 16; + pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val); + val = (regval & 0xFF000000) >> 24; + pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val); + + regval = readl(l2_base + SIFIVE_L2_WAYENABLE); + pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval); +} + +static const struct of_device_id sifive_l2_ids[] = { + { .compatible = "sifive,fu540-c000-ccache" }, + { /* end of table */ }, +}; + +static ATOMIC_NOTIFIER_HEAD(l2_err_chain); + +int register_sifive_l2_error_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&l2_err_chain, nb); +} +EXPORT_SYMBOL_GPL(register_sifive_l2_error_notifier); + +int unregister_sifive_l2_error_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&l2_err_chain, nb); +} +EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier); + +static irqreturn_t l2_int_handler(int irq, void *device) +{ + unsigned int add_h, add_l; + + if (irq == g_irq[DIR_CORR]) { + add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH); + add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW); + pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DirError interrupt sig */ + readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT); + atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE, + "DirECCFix"); + } + if (irq == g_irq[DATA_CORR]) { + add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH); + add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW); + pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DataError interrupt sig */ + readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT); + atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE, + "DatECCFix"); + } + if (irq == g_irq[DATA_UNCORR]) { + add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH); + add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW); + pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DataFail interrupt sig */ + readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT); + atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE, + "DatECCFail"); + } + + return IRQ_HANDLED; +} + +static int __init sifive_l2_init(void) +{ + struct device_node *np; + struct resource res; + int i, rc; + + np = of_find_matching_node(NULL, sifive_l2_ids); + if (!np) + return -ENODEV; + + if (of_address_to_resource(np, 0, &res)) + return -ENODEV; + + l2_base = ioremap(res.start, resource_size(&res)); + if (!l2_base) + return -ENOMEM; + + for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) { + g_irq[i] = irq_of_parse_and_map(np, i); + rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL); + if (rc) { + pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]); + return rc; + } + } + + l2_config_read(); + +#ifdef CONFIG_DEBUG_FS + setup_sifive_debug(); +#endif + return 0; +} +device_initcall(sifive_l2_init); |