aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/power/reset/oxnas-restart.c
blob: 13090bec058a04297db94688a26abf3074de3980 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// SPDX-License-Identifier: (GPL-2.0)
/*
 * oxnas SoC reset driver
 * based on:
 * Microsemi MIPS SoC reset driver
 * and ox820_assert_system_reset() written by Ma Hajun <mahaijuns@gmail.com>
 *
 * Copyright (c) 2013 Ma Hajun <mahaijuns@gmail.com>
 * Copyright (c) 2017 Microsemi Corporation
 * Copyright (c) 2020 Daniel Golle <daniel@makrotopia.org>
 */
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/notifier.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>

/* bit numbers of reset control register */
#define OX820_SYS_CTRL_RST_SCU                0
#define OX820_SYS_CTRL_RST_COPRO              1
#define OX820_SYS_CTRL_RST_ARM0               2
#define OX820_SYS_CTRL_RST_ARM1               3
#define OX820_SYS_CTRL_RST_USBHS              4
#define OX820_SYS_CTRL_RST_USBHSPHYA          5
#define OX820_SYS_CTRL_RST_MACA               6
#define OX820_SYS_CTRL_RST_MAC                OX820_SYS_CTRL_RST_MACA
#define OX820_SYS_CTRL_RST_PCIEA              7
#define OX820_SYS_CTRL_RST_SGDMA              8
#define OX820_SYS_CTRL_RST_CIPHER             9
#define OX820_SYS_CTRL_RST_DDR                10
#define OX820_SYS_CTRL_RST_SATA               11
#define OX820_SYS_CTRL_RST_SATA_LINK          12
#define OX820_SYS_CTRL_RST_SATA_PHY           13
#define OX820_SYS_CTRL_RST_PCIEPHY            14
#define OX820_SYS_CTRL_RST_STATIC             15
#define OX820_SYS_CTRL_RST_GPIO               16
#define OX820_SYS_CTRL_RST_UART1              17
#define OX820_SYS_CTRL_RST_UART2              18
#define OX820_SYS_CTRL_RST_MISC               19
#define OX820_SYS_CTRL_RST_I2S                20
#define OX820_SYS_CTRL_RST_SD                 21
#define OX820_SYS_CTRL_RST_MACB               22
#define OX820_SYS_CTRL_RST_PCIEB              23
#define OX820_SYS_CTRL_RST_VIDEO              24
#define OX820_SYS_CTRL_RST_DDR_PHY            25
#define OX820_SYS_CTRL_RST_USBHSPHYB          26
#define OX820_SYS_CTRL_RST_USBDEV             27
#define OX820_SYS_CTRL_RST_ARMDBG             29
#define OX820_SYS_CTRL_RST_PLLA               30
#define OX820_SYS_CTRL_RST_PLLB               31

/* bit numbers of clock control register */
#define OX820_SYS_CTRL_CLK_COPRO              0
#define OX820_SYS_CTRL_CLK_DMA                1
#define OX820_SYS_CTRL_CLK_CIPHER             2
#define OX820_SYS_CTRL_CLK_SD                 3
#define OX820_SYS_CTRL_CLK_SATA               4
#define OX820_SYS_CTRL_CLK_I2S                5
#define OX820_SYS_CTRL_CLK_USBHS              6
#define OX820_SYS_CTRL_CLK_MACA               7
#define OX820_SYS_CTRL_CLK_MAC                OX820_SYS_CTRL_CLK_MACA
#define OX820_SYS_CTRL_CLK_PCIEA              8
#define OX820_SYS_CTRL_CLK_STATIC             9
#define OX820_SYS_CTRL_CLK_MACB               10
#define OX820_SYS_CTRL_CLK_PCIEB              11
#define OX820_SYS_CTRL_CLK_REF600             12
#define OX820_SYS_CTRL_CLK_USBDEV             13
#define OX820_SYS_CTRL_CLK_DDR                14
#define OX820_SYS_CTRL_CLK_DDRPHY             15
#define OX820_SYS_CTRL_CLK_DDRCK              16

/* Regmap offsets */
#define OX820_CLK_SET_REGOFFSET               0x2c
#define OX820_CLK_CLR_REGOFFSET               0x30
#define OX820_RST_SET_REGOFFSET               0x34
#define OX820_RST_CLR_REGOFFSET               0x38
#define OX820_SECONDARY_SEL_REGOFFSET         0x14
#define OX820_TERTIARY_SEL_REGOFFSET          0x8c
#define OX820_QUATERNARY_SEL_REGOFFSET        0x94
#define OX820_DEBUG_SEL_REGOFFSET             0x9c
#define OX820_ALTERNATIVE_SEL_REGOFFSET       0xa4
#define OX820_PULLUP_SEL_REGOFFSET            0xac
#define OX820_SEC_SECONDARY_SEL_REGOFFSET     0x100014
#define OX820_SEC_TERTIARY_SEL_REGOFFSET      0x10008c
#define OX820_SEC_QUATERNARY_SEL_REGOFFSET    0x100094
#define OX820_SEC_DEBUG_SEL_REGOFFSET         0x10009c
#define OX820_SEC_ALTERNATIVE_SEL_REGOFFSET   0x1000a4
#define OX820_SEC_PULLUP_SEL_REGOFFSET        0x1000ac

struct oxnas_restart_context {
	struct regmap *sys_ctrl;
	struct notifier_block restart_handler;
};

static int ox820_restart_handle(struct notifier_block *this,
				 unsigned long mode, void *cmd)
{
	struct oxnas_restart_context *ctx = container_of(this, struct
							oxnas_restart_context,
							restart_handler);
	u32 value;

	/*
	 * Assert reset to cores as per power on defaults
	 * Don't touch the DDR interface as things will come to an impromptu
	 * stop NB Possibly should be asserting reset for PLLB, but there are
	 * timing concerns here according to the docs
	 */
	value = BIT(OX820_SYS_CTRL_RST_COPRO)		|
		BIT(OX820_SYS_CTRL_RST_USBHS)		|
		BIT(OX820_SYS_CTRL_RST_USBHSPHYA)	|
		BIT(OX820_SYS_CTRL_RST_MACA)		|
		BIT(OX820_SYS_CTRL_RST_PCIEA)		|
		BIT(OX820_SYS_CTRL_RST_SGDMA)		|
		BIT(OX820_SYS_CTRL_RST_CIPHER)		|
		BIT(OX820_SYS_CTRL_RST_SATA)		|
		BIT(OX820_SYS_CTRL_RST_SATA_LINK)	|
		BIT(OX820_SYS_CTRL_RST_SATA_PHY)	|
		BIT(OX820_SYS_CTRL_RST_PCIEPHY)		|
		BIT(OX820_SYS_CTRL_RST_STATIC)		|
		BIT(OX820_SYS_CTRL_RST_UART1)		|
		BIT(OX820_SYS_CTRL_RST_UART2)		|
		BIT(OX820_SYS_CTRL_RST_MISC)		|
		BIT(OX820_SYS_CTRL_RST_I2S)		|
		BIT(OX820_SYS_CTRL_RST_SD)		|
		BIT(OX820_SYS_CTRL_RST_MACB)		|
		BIT(OX820_SYS_CTRL_RST_PCIEB)		|
		BIT(OX820_SYS_CTRL_RST_VIDEO)		|
		BIT(OX820_SYS_CTRL_RST_USBHSPHYB)	|
		BIT(OX820_SYS_CTRL_RST_USBDEV);

	regmap_write(ctx->sys_ctrl, OX820_RST_SET_REGOFFSET, value);

	/* Release reset to cores as per power on defaults */
	regmap_write(ctx->sys_ctrl, OX820_RST_CLR_REGOFFSET,
			BIT(OX820_SYS_CTRL_RST_GPIO));

	/*
	 * Disable clocks to cores as per power-on defaults - must leave DDR
	 * related clocks enabled otherwise we'll stop rather abruptly.
	 */
	value = BIT(OX820_SYS_CTRL_CLK_COPRO)		|
		BIT(OX820_SYS_CTRL_CLK_DMA)		|
		BIT(OX820_SYS_CTRL_CLK_CIPHER)		|
		BIT(OX820_SYS_CTRL_CLK_SD)		|
		BIT(OX820_SYS_CTRL_CLK_SATA)		|
		BIT(OX820_SYS_CTRL_CLK_I2S)		|
		BIT(OX820_SYS_CTRL_CLK_USBHS)		|
		BIT(OX820_SYS_CTRL_CLK_MAC)		|
		BIT(OX820_SYS_CTRL_CLK_PCIEA)		|
		BIT(OX820_SYS_CTRL_CLK_STATIC)		|
		BIT(OX820_SYS_CTRL_CLK_MACB)		|
		BIT(OX820_SYS_CTRL_CLK_PCIEB)		|
		BIT(OX820_SYS_CTRL_CLK_REF600)		|
		BIT(OX820_SYS_CTRL_CLK_USBDEV);

	regmap_write(ctx->sys_ctrl, OX820_CLK_CLR_REGOFFSET, value);

	/* Enable clocks to cores as per power-on defaults */

	/* Set sys-control pin mux'ing as per power-on defaults */
	regmap_write(ctx->sys_ctrl, OX820_SECONDARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_TERTIARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_QUATERNARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_DEBUG_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_ALTERNATIVE_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_PULLUP_SEL_REGOFFSET, 0);

	regmap_write(ctx->sys_ctrl, OX820_SEC_SECONDARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_SEC_TERTIARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_SEC_QUATERNARY_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_SEC_DEBUG_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_SEC_ALTERNATIVE_SEL_REGOFFSET, 0);
	regmap_write(ctx->sys_ctrl, OX820_SEC_PULLUP_SEL_REGOFFSET, 0);

	/*
	 * No need to save any state, as the ROM loader can determine whether
	 * reset is due to power cycling or programatic action, just hit the
	 * (self-clearing) CPU reset bit of the block reset register
	 */
	value =
		BIT(OX820_SYS_CTRL_RST_SCU) |
		BIT(OX820_SYS_CTRL_RST_ARM0) |
		BIT(OX820_SYS_CTRL_RST_ARM1);

	regmap_write(ctx->sys_ctrl, OX820_RST_SET_REGOFFSET, value);

	pr_emerg("Unable to restart system\n");
	return NOTIFY_DONE;
}

static int ox820_restart_probe(struct platform_device *pdev)
{
	struct oxnas_restart_context *ctx;
	struct regmap *sys_ctrl;
	struct device *dev = &pdev->dev;
	int err = 0;

	sys_ctrl = syscon_node_to_regmap(pdev->dev.of_node);
	if (IS_ERR(sys_ctrl))
		return PTR_ERR(sys_ctrl);

	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;

	ctx->sys_ctrl = sys_ctrl;
	ctx->restart_handler.notifier_call = ox820_restart_handle;
	ctx->restart_handler.priority = 192;
	err = register_restart_handler(&ctx->restart_handler);
	if (err)
		dev_err(dev, "can't register restart notifier (err=%d)\n", err);

	return err;
}

static const struct of_device_id ox820_restart_of_match[] = {
	{ .compatible = "oxsemi,ox820-sys-ctrl" },
	{}
};

static struct platform_driver ox820_restart_driver = {
	.probe = ox820_restart_probe,
	.driver = {
		.name = "ox820-chip-reset",
		.of_match_table = ox820_restart_of_match,
	},
};
builtin_platform_driver(ox820_restart_driver);