1 | /* |
2 | * Atmel AT91 SAM9 & SAMA5 SoCs reset code |
3 | * |
4 | * Copyright (C) 2007 Atmel Corporation. |
5 | * Copyright (C) BitBox Ltd 2010 |
6 | * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com> |
7 | * Copyright (C) 2014 Free Electrons |
8 | * |
9 | * This file is licensed under the terms of the GNU General Public |
10 | * License version 2. This program is licensed "as is" without any |
11 | * warranty of any kind, whether express or implied. |
12 | */ |
13 | |
14 | #include <linux/clk.h> |
15 | #include <linux/io.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of_address.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/reboot.h> |
20 | #include <linux/reset-controller.h> |
21 | #include <linux/power/power_on_reason.h> |
22 | |
23 | #include <soc/at91/at91sam9_ddrsdr.h> |
24 | #include <soc/at91/at91sam9_sdramc.h> |
25 | |
26 | #include <dt-bindings/reset/sama7g5-reset.h> |
27 | |
28 | #define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */ |
29 | #define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */ |
30 | #define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */ |
31 | #define AT91_RSTC_EXTRST BIT(3) /* External Reset */ |
32 | #define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ |
33 | |
34 | #define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */ |
35 | #define AT91_RSTC_URSTS BIT(0) /* User Reset Status */ |
36 | #define AT91_RSTC_RSTTYP GENMASK(10, 8) /* Reset Type */ |
37 | #define AT91_RSTC_NRSTL BIT(16) /* NRST Pin Level */ |
38 | #define AT91_RSTC_SRCMP BIT(17) /* Software Reset Command in Progress */ |
39 | |
40 | #define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ |
41 | #define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ |
42 | #define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */ |
43 | #define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ |
44 | #define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ |
45 | |
46 | /** |
47 | * enum reset_type - reset types |
48 | * @RESET_TYPE_GENERAL: first power-up reset |
49 | * @RESET_TYPE_WAKEUP: return from backup mode |
50 | * @RESET_TYPE_WATCHDOG: watchdog fault |
51 | * @RESET_TYPE_SOFTWARE: processor reset required by software |
52 | * @RESET_TYPE_USER: NRST pin detected low |
53 | * @RESET_TYPE_CPU_FAIL: CPU clock failure detection |
54 | * @RESET_TYPE_XTAL_FAIL: 32KHz crystal failure dectection fault |
55 | * @RESET_TYPE_ULP2: ULP2 reset |
56 | */ |
57 | enum reset_type { |
58 | RESET_TYPE_GENERAL = 0, |
59 | RESET_TYPE_WAKEUP = 1, |
60 | RESET_TYPE_WATCHDOG = 2, |
61 | RESET_TYPE_SOFTWARE = 3, |
62 | RESET_TYPE_USER = 4, |
63 | RESET_TYPE_CPU_FAIL = 6, |
64 | RESET_TYPE_XTAL_FAIL = 7, |
65 | RESET_TYPE_ULP2 = 8, |
66 | }; |
67 | |
68 | /** |
69 | * struct at91_reset - AT91 reset specific data structure |
70 | * @rstc_base: base address for system reset |
71 | * @ramc_base: array with base addresses of RAM controllers |
72 | * @dev_base: base address for devices reset |
73 | * @sclk: slow clock |
74 | * @data: platform specific reset data |
75 | * @rcdev: reset controller device |
76 | * @lock: lock for devices reset register access |
77 | * @nb: reset notifier block |
78 | * @args: SoC specific system reset arguments |
79 | * @ramc_lpr: SDRAM Controller Low Power Register |
80 | */ |
81 | struct at91_reset { |
82 | void __iomem *rstc_base; |
83 | void __iomem *ramc_base[2]; |
84 | void __iomem *dev_base; |
85 | struct clk *sclk; |
86 | const struct at91_reset_data *data; |
87 | struct reset_controller_dev rcdev; |
88 | spinlock_t lock; |
89 | struct notifier_block nb; |
90 | u32 args; |
91 | u32 ramc_lpr; |
92 | }; |
93 | |
94 | #define to_at91_reset(r) container_of(r, struct at91_reset, rcdev) |
95 | |
96 | /** |
97 | * struct at91_reset_data - AT91 reset data |
98 | * @reset_args: SoC specific system reset arguments |
99 | * @n_device_reset: number of device resets |
100 | * @device_reset_min_id: min id for device reset |
101 | * @device_reset_max_id: max id for device reset |
102 | */ |
103 | struct at91_reset_data { |
104 | u32 reset_args; |
105 | u32 n_device_reset; |
106 | u8 device_reset_min_id; |
107 | u8 device_reset_max_id; |
108 | }; |
109 | |
110 | /* |
111 | * unless the SDRAM is cleanly shutdown before we hit the |
112 | * reset register it can be left driving the data bus and |
113 | * killing the chance of a subsequent boot from NAND |
114 | */ |
115 | static int at91_reset(struct notifier_block *this, unsigned long mode, |
116 | void *cmd) |
117 | { |
118 | struct at91_reset *reset = container_of(this, struct at91_reset, nb); |
119 | |
120 | asm volatile( |
121 | /* Align to cache lines */ |
122 | ".balign 32\n\t" |
123 | |
124 | /* Disable SDRAM0 accesses */ |
125 | " tst %0, #0\n\t" |
126 | " beq 1f\n\t" |
127 | " str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" |
128 | /* Power down SDRAM0 */ |
129 | " str %4, [%0, %6]\n\t" |
130 | /* Disable SDRAM1 accesses */ |
131 | "1: tst %1, #0\n\t" |
132 | " beq 2f\n\t" |
133 | " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" |
134 | /* Power down SDRAM1 */ |
135 | " strne %4, [%1, %6]\n\t" |
136 | /* Reset CPU */ |
137 | "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" |
138 | |
139 | " b .\n\t" |
140 | : |
141 | : "r" (reset->ramc_base[0]), |
142 | "r" (reset->ramc_base[1]), |
143 | "r" (reset->rstc_base), |
144 | "r" (1), |
145 | "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), |
146 | "r" (reset->data->reset_args), |
147 | "r" (reset->ramc_lpr) |
148 | : "r4" ); |
149 | |
150 | return NOTIFY_DONE; |
151 | } |
152 | |
153 | static const char *at91_reset_reason(struct at91_reset *reset) |
154 | { |
155 | u32 reg = readl(addr: reset->rstc_base + AT91_RSTC_SR); |
156 | const char *reason; |
157 | |
158 | switch ((reg & AT91_RSTC_RSTTYP) >> 8) { |
159 | case RESET_TYPE_GENERAL: |
160 | reason = POWER_ON_REASON_REGULAR; |
161 | break; |
162 | case RESET_TYPE_WAKEUP: |
163 | reason = POWER_ON_REASON_RTC; |
164 | break; |
165 | case RESET_TYPE_WATCHDOG: |
166 | reason = POWER_ON_REASON_WATCHDOG; |
167 | break; |
168 | case RESET_TYPE_SOFTWARE: |
169 | reason = POWER_ON_REASON_SOFTWARE; |
170 | break; |
171 | case RESET_TYPE_USER: |
172 | reason = POWER_ON_REASON_RST_BTN; |
173 | break; |
174 | case RESET_TYPE_CPU_FAIL: |
175 | reason = POWER_ON_REASON_CPU_CLK_FAIL; |
176 | break; |
177 | case RESET_TYPE_XTAL_FAIL: |
178 | reason = POWER_ON_REASON_XTAL_FAIL; |
179 | break; |
180 | case RESET_TYPE_ULP2: |
181 | reason = POWER_ON_REASON_BROWN_OUT; |
182 | break; |
183 | default: |
184 | reason = POWER_ON_REASON_UNKNOWN; |
185 | break; |
186 | } |
187 | |
188 | return reason; |
189 | } |
190 | |
191 | static ssize_t power_on_reason_show(struct device *dev, |
192 | struct device_attribute *attr, char *buf) |
193 | { |
194 | struct platform_device *pdev = to_platform_device(dev); |
195 | struct at91_reset *reset = platform_get_drvdata(pdev); |
196 | |
197 | return sprintf(buf, fmt: "%s\n" , at91_reset_reason(reset)); |
198 | } |
199 | static DEVICE_ATTR_RO(power_on_reason); |
200 | |
201 | static const struct of_device_id at91_ramc_of_match[] = { |
202 | { |
203 | .compatible = "atmel,at91sam9260-sdramc" , |
204 | .data = (void *)AT91_SDRAMC_LPR, |
205 | }, |
206 | { |
207 | .compatible = "atmel,at91sam9g45-ddramc" , |
208 | .data = (void *)AT91_DDRSDRC_LPR, |
209 | }, |
210 | { /* sentinel */ } |
211 | }; |
212 | |
213 | static const struct at91_reset_data sam9260 = { |
214 | .reset_args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, |
215 | }; |
216 | |
217 | static const struct at91_reset_data samx7 = { |
218 | .reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, |
219 | }; |
220 | |
221 | static const struct at91_reset_data sama7g5 = { |
222 | .reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, |
223 | .n_device_reset = 3, |
224 | .device_reset_min_id = SAMA7G5_RESET_USB_PHY1, |
225 | .device_reset_max_id = SAMA7G5_RESET_USB_PHY3, |
226 | }; |
227 | |
228 | static const struct of_device_id at91_reset_of_match[] = { |
229 | { |
230 | .compatible = "atmel,at91sam9260-rstc" , |
231 | .data = &sam9260, |
232 | }, |
233 | { |
234 | .compatible = "atmel,at91sam9g45-rstc" , |
235 | .data = &sam9260, |
236 | }, |
237 | { |
238 | .compatible = "atmel,sama5d3-rstc" , |
239 | .data = &sam9260, |
240 | }, |
241 | { |
242 | .compatible = "atmel,samx7-rstc" , |
243 | .data = &samx7, |
244 | }, |
245 | { |
246 | .compatible = "microchip,sam9x60-rstc" , |
247 | .data = &samx7, |
248 | }, |
249 | { |
250 | .compatible = "microchip,sama7g5-rstc" , |
251 | .data = &sama7g5, |
252 | }, |
253 | { /* sentinel */ } |
254 | }; |
255 | MODULE_DEVICE_TABLE(of, at91_reset_of_match); |
256 | |
257 | static int at91_reset_update(struct reset_controller_dev *rcdev, |
258 | unsigned long id, bool assert) |
259 | { |
260 | struct at91_reset *reset = to_at91_reset(rcdev); |
261 | unsigned long flags; |
262 | u32 val; |
263 | |
264 | spin_lock_irqsave(&reset->lock, flags); |
265 | val = readl_relaxed(reset->dev_base); |
266 | if (assert) |
267 | val |= BIT(id); |
268 | else |
269 | val &= ~BIT(id); |
270 | writel_relaxed(val, reset->dev_base); |
271 | spin_unlock_irqrestore(lock: &reset->lock, flags); |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | static int at91_reset_assert(struct reset_controller_dev *rcdev, |
277 | unsigned long id) |
278 | { |
279 | return at91_reset_update(rcdev, id, assert: true); |
280 | } |
281 | |
282 | static int at91_reset_deassert(struct reset_controller_dev *rcdev, |
283 | unsigned long id) |
284 | { |
285 | return at91_reset_update(rcdev, id, assert: false); |
286 | } |
287 | |
288 | static int at91_reset_dev_status(struct reset_controller_dev *rcdev, |
289 | unsigned long id) |
290 | { |
291 | struct at91_reset *reset = to_at91_reset(rcdev); |
292 | u32 val; |
293 | |
294 | val = readl_relaxed(reset->dev_base); |
295 | |
296 | return !!(val & BIT(id)); |
297 | } |
298 | |
299 | static const struct reset_control_ops at91_reset_ops = { |
300 | .assert = at91_reset_assert, |
301 | .deassert = at91_reset_deassert, |
302 | .status = at91_reset_dev_status, |
303 | }; |
304 | |
305 | static int at91_reset_of_xlate(struct reset_controller_dev *rcdev, |
306 | const struct of_phandle_args *reset_spec) |
307 | { |
308 | struct at91_reset *reset = to_at91_reset(rcdev); |
309 | |
310 | if (!reset->data->n_device_reset || |
311 | (reset_spec->args[0] < reset->data->device_reset_min_id || |
312 | reset_spec->args[0] > reset->data->device_reset_max_id)) |
313 | return -EINVAL; |
314 | |
315 | return reset_spec->args[0]; |
316 | } |
317 | |
318 | static int at91_rcdev_init(struct at91_reset *reset, |
319 | struct platform_device *pdev) |
320 | { |
321 | if (!reset->data->n_device_reset) |
322 | return 0; |
323 | |
324 | reset->dev_base = devm_of_iomap(dev: &pdev->dev, node: pdev->dev.of_node, index: 1, |
325 | NULL); |
326 | if (IS_ERR(ptr: reset->dev_base)) |
327 | return -ENODEV; |
328 | |
329 | spin_lock_init(&reset->lock); |
330 | reset->rcdev.ops = &at91_reset_ops; |
331 | reset->rcdev.owner = THIS_MODULE; |
332 | reset->rcdev.of_node = pdev->dev.of_node; |
333 | reset->rcdev.nr_resets = reset->data->n_device_reset; |
334 | reset->rcdev.of_reset_n_cells = 1; |
335 | reset->rcdev.of_xlate = at91_reset_of_xlate; |
336 | |
337 | return devm_reset_controller_register(dev: &pdev->dev, rcdev: &reset->rcdev); |
338 | } |
339 | |
340 | static int __init at91_reset_probe(struct platform_device *pdev) |
341 | { |
342 | const struct of_device_id *match; |
343 | struct at91_reset *reset; |
344 | struct device_node *np; |
345 | int ret, idx = 0; |
346 | |
347 | reset = devm_kzalloc(dev: &pdev->dev, size: sizeof(*reset), GFP_KERNEL); |
348 | if (!reset) |
349 | return -ENOMEM; |
350 | |
351 | reset->rstc_base = devm_of_iomap(dev: &pdev->dev, node: pdev->dev.of_node, index: 0, NULL); |
352 | if (IS_ERR(ptr: reset->rstc_base)) { |
353 | dev_err(&pdev->dev, "Could not map reset controller address\n" ); |
354 | return -ENODEV; |
355 | } |
356 | |
357 | if (!of_device_is_compatible(device: pdev->dev.of_node, "atmel,sama5d3-rstc" )) { |
358 | /* we need to shutdown the ddr controller, so get ramc base */ |
359 | for_each_matching_node_and_match(np, at91_ramc_of_match, &match) { |
360 | reset->ramc_lpr = (u32)match->data; |
361 | reset->ramc_base[idx] = devm_of_iomap(dev: &pdev->dev, node: np, index: 0, NULL); |
362 | if (IS_ERR(ptr: reset->ramc_base[idx])) { |
363 | dev_err(&pdev->dev, "Could not map ram controller address\n" ); |
364 | of_node_put(node: np); |
365 | return -ENODEV; |
366 | } |
367 | idx++; |
368 | } |
369 | } |
370 | |
371 | reset->data = device_get_match_data(dev: &pdev->dev); |
372 | if (!reset->data) |
373 | return -ENODEV; |
374 | |
375 | reset->nb.notifier_call = at91_reset; |
376 | reset->nb.priority = 192; |
377 | |
378 | reset->sclk = devm_clk_get(dev: &pdev->dev, NULL); |
379 | if (IS_ERR(ptr: reset->sclk)) |
380 | return PTR_ERR(ptr: reset->sclk); |
381 | |
382 | ret = clk_prepare_enable(clk: reset->sclk); |
383 | if (ret) { |
384 | dev_err(&pdev->dev, "Could not enable slow clock\n" ); |
385 | return ret; |
386 | } |
387 | |
388 | platform_set_drvdata(pdev, data: reset); |
389 | |
390 | ret = at91_rcdev_init(reset, pdev); |
391 | if (ret) |
392 | goto disable_clk; |
393 | |
394 | if (of_device_is_compatible(device: pdev->dev.of_node, "microchip,sam9x60-rstc" )) { |
395 | u32 val = readl(addr: reset->rstc_base + AT91_RSTC_MR); |
396 | |
397 | writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val, |
398 | addr: reset->rstc_base + AT91_RSTC_MR); |
399 | } |
400 | |
401 | ret = register_restart_handler(&reset->nb); |
402 | if (ret) |
403 | goto disable_clk; |
404 | |
405 | ret = device_create_file(device: &pdev->dev, entry: &dev_attr_power_on_reason); |
406 | if (ret) { |
407 | dev_err(&pdev->dev, "Could not create sysfs entry\n" ); |
408 | return ret; |
409 | } |
410 | |
411 | dev_info(&pdev->dev, "Starting after %s\n" , at91_reset_reason(reset)); |
412 | |
413 | return 0; |
414 | |
415 | disable_clk: |
416 | clk_disable_unprepare(clk: reset->sclk); |
417 | return ret; |
418 | } |
419 | |
420 | static int __exit at91_reset_remove(struct platform_device *pdev) |
421 | { |
422 | struct at91_reset *reset = platform_get_drvdata(pdev); |
423 | |
424 | unregister_restart_handler(&reset->nb); |
425 | clk_disable_unprepare(clk: reset->sclk); |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static struct platform_driver at91_reset_driver = { |
431 | .remove = __exit_p(at91_reset_remove), |
432 | .driver = { |
433 | .name = "at91-reset" , |
434 | .of_match_table = at91_reset_of_match, |
435 | }, |
436 | }; |
437 | module_platform_driver_probe(at91_reset_driver, at91_reset_probe); |
438 | |
439 | MODULE_AUTHOR("Atmel Corporation" ); |
440 | MODULE_DESCRIPTION("Reset driver for Atmel SoCs" ); |
441 | MODULE_LICENSE("GPL v2" ); |
442 | |