blob: ad831c703a9874a918e6d2353afccb001a65e26d [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
Simon Glasseb517312018-10-01 12:22:45 -06007#define LOG_CATEGORY UCLASS_SYSRESET
8
Stephen Warren11636252016-05-12 12:03:35 -06009#include <common.h>
10#include <sysreset.h>
11#include <dm.h>
12#include <errno.h>
13#include <regmap.h>
14#include <dm/device-internal.h>
15#include <dm/lists.h>
16#include <dm/root.h>
17#include <linux/err.h>
18
19int sysreset_request(struct udevice *dev, enum sysreset_t type)
20{
21 struct sysreset_ops *ops = sysreset_get_ops(dev);
22
23 if (!ops->request)
24 return -ENOSYS;
25
26 return ops->request(dev, type);
27}
28
Mario Six245f5cd2018-08-06 10:23:32 +020029int sysreset_get_status(struct udevice *dev, char *buf, int size)
30{
31 struct sysreset_ops *ops = sysreset_get_ops(dev);
32
33 if (!ops->get_status)
34 return -ENOSYS;
35
36 return ops->get_status(dev, buf, size);
37}
38
Simon Glass751fed42018-10-01 12:22:46 -060039int sysreset_get_last(struct udevice *dev)
40{
41 struct sysreset_ops *ops = sysreset_get_ops(dev);
42
43 if (!ops->get_last)
44 return -ENOSYS;
45
46 return ops->get_last(dev);
47}
48
Stephen Warren11636252016-05-12 12:03:35 -060049int sysreset_walk(enum sysreset_t type)
50{
51 struct udevice *dev;
52 int ret = -ENOSYS;
53
54 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
55 for (uclass_first_device(UCLASS_SYSRESET, &dev);
56 dev;
57 uclass_next_device(&dev)) {
58 ret = sysreset_request(dev, type);
59 if (ret == -EINPROGRESS)
60 break;
61 }
62 type++;
63 }
64
65 return ret;
66}
67
Simon Glass751fed42018-10-01 12:22:46 -060068int sysreset_get_last_walk(void)
69{
70 struct udevice *dev;
71 int value = -ENOENT;
72
73 for (uclass_first_device(UCLASS_SYSRESET, &dev);
74 dev;
75 uclass_next_device(&dev)) {
76 int ret;
77
78 ret = sysreset_get_last(dev);
79 if (ret >= 0) {
80 value = ret;
81 break;
82 }
83 }
84
85 return value;
86}
87
Stephen Warren11636252016-05-12 12:03:35 -060088void sysreset_walk_halt(enum sysreset_t type)
89{
90 int ret;
91
92 ret = sysreset_walk(type);
93
94 /* Wait for the reset to take effect */
95 if (ret == -EINPROGRESS)
96 mdelay(100);
97
98 /* Still no reset? Give up */
Simon Glasseb517312018-10-01 12:22:45 -060099 log_err("System reset not supported on this platform\n");
Stephen Warren11636252016-05-12 12:03:35 -0600100 hang();
101}
102
103/**
104 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
105 */
106void reset_cpu(ulong addr)
107{
108 sysreset_walk_halt(SYSRESET_WARM);
109}
110
111
112int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
113{
Bin Meng406be392018-07-19 03:07:31 -0700114 printf("resetting ...\n");
115
Philipp Tomsichb53f69922017-11-24 18:37:58 +0100116 sysreset_walk_halt(SYSRESET_COLD);
Stephen Warren11636252016-05-12 12:03:35 -0600117
118 return 0;
119}
120
Michal Simek758de972018-07-12 10:36:07 +0200121static int sysreset_post_bind(struct udevice *dev)
122{
123#if defined(CONFIG_NEEDS_MANUAL_RELOC)
124 struct sysreset_ops *ops = sysreset_get_ops(dev);
125 static int reloc_done;
126
127 if (!reloc_done) {
128 if (ops->request)
129 ops->request += gd->reloc_off;
130 reloc_done++;
131 }
132#endif
133 return 0;
134}
135
Stephen Warren11636252016-05-12 12:03:35 -0600136UCLASS_DRIVER(sysreset) = {
137 .id = UCLASS_SYSRESET,
138 .name = "sysreset",
Michal Simek758de972018-07-12 10:36:07 +0200139 .post_bind = sysreset_post_bind,
Stephen Warren11636252016-05-12 12:03:35 -0600140};