1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 /* 3 * Microsemi MIPS SoC reset driver 4 * 5 * License: Dual MIT/GPL 6 * Copyright (c) 2017 Microsemi Corporation 7 */ 8 #include <linux/delay.h> 9 #include <linux/io.h> 10 #include <linux/notifier.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/of_address.h> 13 #include <linux/of_device.h> 14 #include <linux/platform_device.h> 15 #include <linux/reboot.h> 16 #include <linux/regmap.h> 17 18 struct reset_props { 19 const char *syscon; 20 u32 protect_reg; 21 u32 vcore_protect; 22 u32 if_si_owner_bit; 23 }; 24 25 struct ocelot_reset_context { 26 void __iomem *base; 27 struct regmap *cpu_ctrl; 28 const struct reset_props *props; 29 struct notifier_block restart_handler; 30 }; 31 32 #define SOFT_CHIP_RST BIT(0) 33 34 #define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 35 #define IF_SI_OWNER_MASK GENMASK(1, 0) 36 #define IF_SI_OWNER_SISL 0 37 #define IF_SI_OWNER_SIBM 1 38 #define IF_SI_OWNER_SIMC 2 39 40 static int ocelot_restart_handle(struct notifier_block *this, 41 unsigned long mode, void *cmd) 42 { 43 struct ocelot_reset_context *ctx = container_of(this, struct 44 ocelot_reset_context, 45 restart_handler); 46 u32 if_si_owner_bit = ctx->props->if_si_owner_bit; 47 48 /* Make sure the core is not protected from reset */ 49 regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg, 50 ctx->props->vcore_protect, 0); 51 52 /* Make the SI back to boot mode */ 53 regmap_update_bits(ctx->cpu_ctrl, ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL, 54 IF_SI_OWNER_MASK << if_si_owner_bit, 55 IF_SI_OWNER_SIBM << if_si_owner_bit); 56 57 pr_emerg("Resetting SoC\n"); 58 59 writel(SOFT_CHIP_RST, ctx->base); 60 61 pr_emerg("Unable to restart system\n"); 62 return NOTIFY_DONE; 63 } 64 65 static int ocelot_reset_probe(struct platform_device *pdev) 66 { 67 struct ocelot_reset_context *ctx; 68 struct resource *res; 69 70 struct device *dev = &pdev->dev; 71 int err; 72 73 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 74 if (!ctx) 75 return -ENOMEM; 76 77 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 78 ctx->base = devm_ioremap_resource(dev, res); 79 if (IS_ERR(ctx->base)) 80 return PTR_ERR(ctx->base); 81 82 ctx->props = device_get_match_data(dev); 83 84 ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(ctx->props->syscon); 85 if (IS_ERR(ctx->cpu_ctrl)) { 86 dev_err(dev, "No syscon map: %s\n", ctx->props->syscon); 87 return PTR_ERR(ctx->cpu_ctrl); 88 } 89 90 ctx->restart_handler.notifier_call = ocelot_restart_handle; 91 ctx->restart_handler.priority = 192; 92 err = register_restart_handler(&ctx->restart_handler); 93 if (err) 94 dev_err(dev, "can't register restart notifier (err=%d)\n", err); 95 96 return err; 97 } 98 99 static const struct reset_props reset_props_ocelot = { 100 .syscon = "mscc,ocelot-cpu-syscon", 101 .protect_reg = 0x20, 102 .vcore_protect = BIT(2), 103 .if_si_owner_bit = 4, 104 }; 105 106 static const struct reset_props reset_props_sparx5 = { 107 .syscon = "microchip,sparx5-cpu-syscon", 108 .protect_reg = 0x84, 109 .vcore_protect = BIT(10), 110 .if_si_owner_bit = 6, 111 }; 112 113 static const struct of_device_id ocelot_reset_of_match[] = { 114 { 115 .compatible = "mscc,ocelot-chip-reset", 116 .data = &reset_props_ocelot 117 }, { 118 .compatible = "microchip,sparx5-chip-reset", 119 .data = &reset_props_sparx5 120 }, 121 { /*sentinel*/ } 122 }; 123 124 static struct platform_driver ocelot_reset_driver = { 125 .probe = ocelot_reset_probe, 126 .driver = { 127 .name = "ocelot-chip-reset", 128 .of_match_table = ocelot_reset_of_match, 129 }, 130 }; 131 builtin_platform_driver(ocelot_reset_driver); 132