0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/notifier.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/of_address.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/reboot.h>
0016 #include <linux/regmap.h>
0017
0018 struct reset_props {
0019 const char *syscon;
0020 u32 protect_reg;
0021 u32 vcore_protect;
0022 u32 if_si_owner_bit;
0023 };
0024
0025 struct ocelot_reset_context {
0026 void __iomem *base;
0027 struct regmap *cpu_ctrl;
0028 const struct reset_props *props;
0029 struct notifier_block restart_handler;
0030 };
0031
0032 #define BIT_OFF_INVALID 32
0033
0034 #define SOFT_CHIP_RST BIT(0)
0035
0036 #define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
0037 #define IF_SI_OWNER_MASK GENMASK(1, 0)
0038 #define IF_SI_OWNER_SISL 0
0039 #define IF_SI_OWNER_SIBM 1
0040 #define IF_SI_OWNER_SIMC 2
0041
0042 static int ocelot_restart_handle(struct notifier_block *this,
0043 unsigned long mode, void *cmd)
0044 {
0045 struct ocelot_reset_context *ctx = container_of(this, struct
0046 ocelot_reset_context,
0047 restart_handler);
0048 u32 if_si_owner_bit = ctx->props->if_si_owner_bit;
0049
0050
0051 regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
0052 ctx->props->vcore_protect, 0);
0053
0054
0055 if (if_si_owner_bit != BIT_OFF_INVALID)
0056 regmap_update_bits(ctx->cpu_ctrl,
0057 ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,
0058 IF_SI_OWNER_MASK << if_si_owner_bit,
0059 IF_SI_OWNER_SIBM << if_si_owner_bit);
0060
0061 pr_emerg("Resetting SoC\n");
0062
0063 writel(SOFT_CHIP_RST, ctx->base);
0064
0065 pr_emerg("Unable to restart system\n");
0066 return NOTIFY_DONE;
0067 }
0068
0069 static int ocelot_reset_probe(struct platform_device *pdev)
0070 {
0071 struct ocelot_reset_context *ctx;
0072 struct resource *res;
0073
0074 struct device *dev = &pdev->dev;
0075 int err;
0076
0077 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0078 if (!ctx)
0079 return -ENOMEM;
0080
0081 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0082 ctx->base = devm_ioremap_resource(dev, res);
0083 if (IS_ERR(ctx->base))
0084 return PTR_ERR(ctx->base);
0085
0086 ctx->props = device_get_match_data(dev);
0087
0088 ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(ctx->props->syscon);
0089 if (IS_ERR(ctx->cpu_ctrl)) {
0090 dev_err(dev, "No syscon map: %s\n", ctx->props->syscon);
0091 return PTR_ERR(ctx->cpu_ctrl);
0092 }
0093
0094 ctx->restart_handler.notifier_call = ocelot_restart_handle;
0095 ctx->restart_handler.priority = 192;
0096 err = register_restart_handler(&ctx->restart_handler);
0097 if (err)
0098 dev_err(dev, "can't register restart notifier (err=%d)\n", err);
0099
0100 return err;
0101 }
0102
0103 static const struct reset_props reset_props_jaguar2 = {
0104 .syscon = "mscc,ocelot-cpu-syscon",
0105 .protect_reg = 0x20,
0106 .vcore_protect = BIT(2),
0107 .if_si_owner_bit = 6,
0108 };
0109
0110 static const struct reset_props reset_props_luton = {
0111 .syscon = "mscc,ocelot-cpu-syscon",
0112 .protect_reg = 0x20,
0113 .vcore_protect = BIT(2),
0114 .if_si_owner_bit = BIT_OFF_INVALID,
0115 };
0116
0117 static const struct reset_props reset_props_ocelot = {
0118 .syscon = "mscc,ocelot-cpu-syscon",
0119 .protect_reg = 0x20,
0120 .vcore_protect = BIT(2),
0121 .if_si_owner_bit = 4,
0122 };
0123
0124 static const struct reset_props reset_props_sparx5 = {
0125 .syscon = "microchip,sparx5-cpu-syscon",
0126 .protect_reg = 0x84,
0127 .vcore_protect = BIT(10),
0128 .if_si_owner_bit = 6,
0129 };
0130
0131 static const struct of_device_id ocelot_reset_of_match[] = {
0132 {
0133 .compatible = "mscc,jaguar2-chip-reset",
0134 .data = &reset_props_jaguar2
0135 }, {
0136 .compatible = "mscc,luton-chip-reset",
0137 .data = &reset_props_luton
0138 }, {
0139 .compatible = "mscc,ocelot-chip-reset",
0140 .data = &reset_props_ocelot
0141 }, {
0142 .compatible = "microchip,sparx5-chip-reset",
0143 .data = &reset_props_sparx5
0144 },
0145 { }
0146 };
0147
0148 static struct platform_driver ocelot_reset_driver = {
0149 .probe = ocelot_reset_probe,
0150 .driver = {
0151 .name = "ocelot-chip-reset",
0152 .of_match_table = ocelot_reset_of_match,
0153 },
0154 };
0155 builtin_platform_driver(ocelot_reset_driver);