Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 /*
0003  * Microsemi MIPS SoC reset driver
0004  *
0005  * License: Dual MIT/GPL
0006  * Copyright (c) 2017 Microsemi Corporation
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     /* Make sure the core is not protected from reset */
0051     regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg,
0052                ctx->props->vcore_protect, 0);
0053 
0054     /* Make the SI back to boot mode */
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, /* n/a */
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     { /*sentinel*/ }
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);