]>
Commit | Line | Data |
---|---|---|
6ab739bc AB |
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 | ||
ec871696 LP |
18 | struct reset_props { |
19 | const char *syscon; | |
20 | u32 protect_reg; | |
21 | u32 vcore_protect; | |
22 | u32 if_si_owner_bit; | |
23 | }; | |
24 | ||
6ab739bc AB |
25 | struct ocelot_reset_context { |
26 | void __iomem *base; | |
27 | struct regmap *cpu_ctrl; | |
ec871696 | 28 | const struct reset_props *props; |
6ab739bc AB |
29 | struct notifier_block restart_handler; |
30 | }; | |
31 | ||
aa4302c4 GC |
32 | #define BIT_OFF_INVALID 32 |
33 | ||
6ab739bc AB |
34 | #define SOFT_CHIP_RST BIT(0) |
35 | ||
9afe6250 AB |
36 | #define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 |
37 | #define IF_SI_OWNER_MASK GENMASK(1, 0) | |
38 | #define IF_SI_OWNER_SISL 0 | |
39 | #define IF_SI_OWNER_SIBM 1 | |
40 | #define IF_SI_OWNER_SIMC 2 | |
9afe6250 | 41 | |
6ab739bc AB |
42 | static int ocelot_restart_handle(struct notifier_block *this, |
43 | unsigned long mode, void *cmd) | |
44 | { | |
45 | struct ocelot_reset_context *ctx = container_of(this, struct | |
46 | ocelot_reset_context, | |
47 | restart_handler); | |
ec871696 | 48 | u32 if_si_owner_bit = ctx->props->if_si_owner_bit; |
6ab739bc AB |
49 | |
50 | /* Make sure the core is not protected from reset */ | |
ec871696 LP |
51 | regmap_update_bits(ctx->cpu_ctrl, ctx->props->protect_reg, |
52 | ctx->props->vcore_protect, 0); | |
6ab739bc | 53 | |
9afe6250 | 54 | /* Make the SI back to boot mode */ |
aa4302c4 GC |
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); | |
ec871696 LP |
60 | |
61 | pr_emerg("Resetting SoC\n"); | |
9afe6250 | 62 | |
6ab739bc AB |
63 | writel(SOFT_CHIP_RST, ctx->base); |
64 | ||
65 | pr_emerg("Unable to restart system\n"); | |
66 | return NOTIFY_DONE; | |
67 | } | |
68 | ||
69 | static int ocelot_reset_probe(struct platform_device *pdev) | |
70 | { | |
71 | struct ocelot_reset_context *ctx; | |
72 | struct resource *res; | |
73 | ||
74 | struct device *dev = &pdev->dev; | |
75 | int err; | |
76 | ||
77 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); | |
78 | if (!ctx) | |
79 | return -ENOMEM; | |
80 | ||
81 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
82 | ctx->base = devm_ioremap_resource(dev, res); | |
83 | if (IS_ERR(ctx->base)) | |
84 | return PTR_ERR(ctx->base); | |
85 | ||
ec871696 LP |
86 | ctx->props = device_get_match_data(dev); |
87 | ||
88 | ctx->cpu_ctrl = syscon_regmap_lookup_by_compatible(ctx->props->syscon); | |
89 | if (IS_ERR(ctx->cpu_ctrl)) { | |
90 | dev_err(dev, "No syscon map: %s\n", ctx->props->syscon); | |
6ab739bc | 91 | return PTR_ERR(ctx->cpu_ctrl); |
ec871696 | 92 | } |
6ab739bc AB |
93 | |
94 | ctx->restart_handler.notifier_call = ocelot_restart_handle; | |
95 | ctx->restart_handler.priority = 192; | |
96 | err = register_restart_handler(&ctx->restart_handler); | |
97 | if (err) | |
98 | dev_err(dev, "can't register restart notifier (err=%d)\n", err); | |
99 | ||
100 | return err; | |
101 | } | |
102 | ||
aa4302c4 GC |
103 | static const struct reset_props reset_props_jaguar2 = { |
104 | .syscon = "mscc,ocelot-cpu-syscon", | |
105 | .protect_reg = 0x20, | |
106 | .vcore_protect = BIT(2), | |
107 | .if_si_owner_bit = 6, | |
108 | }; | |
109 | ||
110 | static const struct reset_props reset_props_luton = { | |
111 | .syscon = "mscc,ocelot-cpu-syscon", | |
112 | .protect_reg = 0x20, | |
113 | .vcore_protect = BIT(2), | |
114 | .if_si_owner_bit = BIT_OFF_INVALID, /* n/a */ | |
115 | }; | |
116 | ||
ec871696 LP |
117 | static const struct reset_props reset_props_ocelot = { |
118 | .syscon = "mscc,ocelot-cpu-syscon", | |
119 | .protect_reg = 0x20, | |
120 | .vcore_protect = BIT(2), | |
121 | .if_si_owner_bit = 4, | |
122 | }; | |
123 | ||
124 | static const struct reset_props reset_props_sparx5 = { | |
125 | .syscon = "microchip,sparx5-cpu-syscon", | |
126 | .protect_reg = 0x84, | |
127 | .vcore_protect = BIT(10), | |
128 | .if_si_owner_bit = 6, | |
129 | }; | |
130 | ||
6ab739bc | 131 | static const struct of_device_id ocelot_reset_of_match[] = { |
ec871696 | 132 | { |
aa4302c4 GC |
133 | .compatible = "mscc,jaguar2-chip-reset", |
134 | .data = &reset_props_jaguar2 | |
135 | }, { | |
136 | .compatible = "mscc,luton-chip-reset", | |
137 | .data = &reset_props_luton | |
138 | }, { | |
ec871696 LP |
139 | .compatible = "mscc,ocelot-chip-reset", |
140 | .data = &reset_props_ocelot | |
141 | }, { | |
142 | .compatible = "microchip,sparx5-chip-reset", | |
143 | .data = &reset_props_sparx5 | |
144 | }, | |
145 | { /*sentinel*/ } | |
6ab739bc AB |
146 | }; |
147 | ||
148 | static struct platform_driver ocelot_reset_driver = { | |
149 | .probe = ocelot_reset_probe, | |
150 | .driver = { | |
151 | .name = "ocelot-chip-reset", | |
152 | .of_match_table = ocelot_reset_of_match, | |
153 | }, | |
154 | }; | |
155 | builtin_platform_driver(ocelot_reset_driver); |