153 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Microsemi MIPS SoC reset driver4 *5 * License: Dual MIT/GPL6 * Copyright (c) 2017 Microsemi Corporation7 */8#include <linux/delay.h>9#include <linux/io.h>10#include <linux/notifier.h>11#include <linux/mod_devicetable.h>12#include <linux/mfd/syscon.h>13#include <linux/platform_device.h>14#include <linux/property.h>15#include <linux/reboot.h>16#include <linux/regmap.h>17 18struct reset_props {19 const char *syscon;20 u32 protect_reg;21 u32 vcore_protect;22 u32 if_si_owner_bit;23};24 25struct 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 BIT_OFF_INVALID 3233 34#define SOFT_CHIP_RST BIT(0)35 36#define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x2437#define IF_SI_OWNER_MASK GENMASK(1, 0)38#define IF_SI_OWNER_SISL 039#define IF_SI_OWNER_SIBM 140#define IF_SI_OWNER_SIMC 241 42static int ocelot_restart_handle(struct notifier_block *this,43 unsigned long mode, void *cmd)44{45 struct ocelot_reset_context *ctx = container_of(this, struct46 ocelot_reset_context,47 restart_handler);48 u32 if_si_owner_bit = ctx->props->if_si_owner_bit;49 50 /* Make sure the core is not protected from reset */51 regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,52 ctx->props->vcore_protect, 0);53 54 /* Make the SI back to boot mode */55 if (if_si_owner_bit != BIT_OFF_INVALID)56 regmap_update_bits(ctx->cpu_ctrl,57 ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL,58 IF_SI_OWNER_MASK << if_si_owner_bit,59 IF_SI_OWNER_SIBM << if_si_owner_bit);60 61 pr_emerg("Resetting SoC\n");62 63 writel(SOFT_CHIP_RST, ctx->base);64 65 pr_emerg("Unable to restart system\n");66 return NOTIFY_DONE;67}68 69static int ocelot_reset_probe(struct platform_device *pdev)70{71 struct ocelot_reset_context *ctx;72 struct device *dev = &pdev->dev;73 int err;74 75 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);76 if (!ctx)77 return -ENOMEM;78 79 ctx->base = devm_platform_ioremap_resource(pdev, 0);80 if (IS_ERR(ctx->base))81 return PTR_ERR(ctx->base);82 83 ctx->props = device_get_match_data(dev);84 85 ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(ctx->props->syscon);86 if (IS_ERR(ctx->cpu_ctrl)) {87 dev_err(dev, "No syscon map: %s\n", ctx->props->syscon);88 return PTR_ERR(ctx->cpu_ctrl);89 }90 91 ctx->restart_handler.notifier_call = ocelot_restart_handle;92 ctx->restart_handler.priority = 192;93 err = register_restart_handler(&ctx->restart_handler);94 if (err)95 dev_err(dev, "can't register restart notifier (err=%d)\n", err);96 97 return err;98}99 100static const struct reset_props reset_props_jaguar2 = {101 .syscon = "mscc,ocelot-cpu-syscon",102 .protect_reg = 0x20,103 .vcore_protect = BIT(2),104 .if_si_owner_bit = 6,105};106 107static const struct reset_props reset_props_luton = {108 .syscon = "mscc,ocelot-cpu-syscon",109 .protect_reg = 0x20,110 .vcore_protect = BIT(2),111 .if_si_owner_bit = BIT_OFF_INVALID, /* n/a */112};113 114static const struct reset_props reset_props_ocelot = {115 .syscon = "mscc,ocelot-cpu-syscon",116 .protect_reg = 0x20,117 .vcore_protect = BIT(2),118 .if_si_owner_bit = 4,119};120 121static const struct reset_props reset_props_sparx5 = {122 .syscon = "microchip,sparx5-cpu-syscon",123 .protect_reg = 0x84,124 .vcore_protect = BIT(10),125 .if_si_owner_bit = 6,126};127 128static const struct of_device_id ocelot_reset_of_match[] = {129 {130 .compatible = "mscc,jaguar2-chip-reset",131 .data = &reset_props_jaguar2132 }, {133 .compatible = "mscc,luton-chip-reset",134 .data = &reset_props_luton135 }, {136 .compatible = "mscc,ocelot-chip-reset",137 .data = &reset_props_ocelot138 }, {139 .compatible = "microchip,sparx5-chip-reset",140 .data = &reset_props_sparx5141 },142 { /*sentinel*/ }143};144 145static struct platform_driver ocelot_reset_driver = {146 .probe = ocelot_reset_probe,147 .driver = {148 .name = "ocelot-chip-reset",149 .of_match_table = ocelot_reset_of_match,150 },151};152builtin_platform_driver(ocelot_reset_driver);153