blob: 06ef0ed96c77605d1b853d6a9722ff953da4066b [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stephen Warren11636252016-05-12 12:03:35 -06002/*
3 * Copyright (C) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Stephen Warren11636252016-05-12 12:03:35 -06005 */
6
7#include <common.h>
8#include <sysreset.h>
9#include <dm.h>
10#include <errno.h>
11#include <regmap.h>
12#include <dm/device-internal.h>
13#include <dm/lists.h>
14#include <dm/root.h>
15#include <linux/err.h>
16
17int sysreset_request(struct udevice *dev, enum sysreset_t type)
18{
19 struct sysreset_ops *ops = sysreset_get_ops(dev);
20
21 if (!ops->request)
22 return -ENOSYS;
23
24 return ops->request(dev, type);
25}
26
Mario Six245f5cd2018-08-06 10:23:32 +020027int sysreset_get_status(struct udevice *dev, char *buf, int size)
28{
29 struct sysreset_ops *ops = sysreset_get_ops(dev);
30
31 if (!ops->get_status)
32 return -ENOSYS;
33
34 return ops->get_status(dev, buf, size);
35}
36
Stephen Warren11636252016-05-12 12:03:35 -060037int sysreset_walk(enum sysreset_t type)
38{
39 struct udevice *dev;
40 int ret = -ENOSYS;
41
42 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
43 for (uclass_first_device(UCLASS_SYSRESET, &dev);
44 dev;
45 uclass_next_device(&dev)) {
46 ret = sysreset_request(dev, type);
47 if (ret == -EINPROGRESS)
48 break;
49 }
50 type++;
51 }
52
53 return ret;
54}
55
56void sysreset_walk_halt(enum sysreset_t type)
57{
58 int ret;
59
60 ret = sysreset_walk(type);
61
62 /* Wait for the reset to take effect */
63 if (ret == -EINPROGRESS)
64 mdelay(100);
65
66 /* Still no reset? Give up */
Simon Glass5c086212016-05-14 14:02:54 -060067 debug("System reset not supported on this platform\n");
Stephen Warren11636252016-05-12 12:03:35 -060068 hang();
69}
70
71/**
72 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
73 */
74void reset_cpu(ulong addr)
75{
76 sysreset_walk_halt(SYSRESET_WARM);
77}
78
79
80int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
81{
Bin Meng406be392018-07-19 03:07:31 -070082 printf("resetting ...\n");
83
Philipp Tomsichb53f69922017-11-24 18:37:58 +010084 sysreset_walk_halt(SYSRESET_COLD);
Stephen Warren11636252016-05-12 12:03:35 -060085
86 return 0;
87}
88
Michal Simek758de972018-07-12 10:36:07 +020089static int sysreset_post_bind(struct udevice *dev)
90{
91#if defined(CONFIG_NEEDS_MANUAL_RELOC)
92 struct sysreset_ops *ops = sysreset_get_ops(dev);
93 static int reloc_done;
94
95 if (!reloc_done) {
96 if (ops->request)
97 ops->request += gd->reloc_off;
98 reloc_done++;
99 }
100#endif
101 return 0;
102}
103
Stephen Warren11636252016-05-12 12:03:35 -0600104UCLASS_DRIVER(sysreset) = {
105 .id = UCLASS_SYSRESET,
106 .name = "sysreset",
Michal Simek758de972018-07-12 10:36:07 +0200107 .post_bind = sysreset_post_bind,
Stephen Warren11636252016-05-12 12:03:35 -0600108};