blob: 51fdb1055e3b36c17933c45d1716222adfe98a0e [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>
Simon Glass9a3b4ce2019-12-28 10:45:01 -070010#include <cpu_func.h>
Simon Glassdb41d652019-12-28 10:45:07 -070011#include <hang.h>
Stephen Warren11636252016-05-12 12:03:35 -060012#include <sysreset.h>
13#include <dm.h>
14#include <errno.h>
15#include <regmap.h>
16#include <dm/device-internal.h>
17#include <dm/lists.h>
18#include <dm/root.h>
19#include <linux/err.h>
20
21int sysreset_request(struct udevice *dev, enum sysreset_t type)
22{
23 struct sysreset_ops *ops = sysreset_get_ops(dev);
24
25 if (!ops->request)
26 return -ENOSYS;
27
28 return ops->request(dev, type);
29}
30
Mario Six245f5cd2018-08-06 10:23:32 +020031int sysreset_get_status(struct udevice *dev, char *buf, int size)
32{
33 struct sysreset_ops *ops = sysreset_get_ops(dev);
34
35 if (!ops->get_status)
36 return -ENOSYS;
37
38 return ops->get_status(dev, buf, size);
39}
40
Simon Glass751fed42018-10-01 12:22:46 -060041int sysreset_get_last(struct udevice *dev)
42{
43 struct sysreset_ops *ops = sysreset_get_ops(dev);
44
45 if (!ops->get_last)
46 return -ENOSYS;
47
48 return ops->get_last(dev);
49}
50
Stephen Warren11636252016-05-12 12:03:35 -060051int sysreset_walk(enum sysreset_t type)
52{
53 struct udevice *dev;
54 int ret = -ENOSYS;
55
56 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
57 for (uclass_first_device(UCLASS_SYSRESET, &dev);
58 dev;
59 uclass_next_device(&dev)) {
60 ret = sysreset_request(dev, type);
61 if (ret == -EINPROGRESS)
62 break;
63 }
64 type++;
65 }
66
67 return ret;
68}
69
Simon Glass751fed42018-10-01 12:22:46 -060070int sysreset_get_last_walk(void)
71{
72 struct udevice *dev;
73 int value = -ENOENT;
74
75 for (uclass_first_device(UCLASS_SYSRESET, &dev);
76 dev;
77 uclass_next_device(&dev)) {
78 int ret;
79
80 ret = sysreset_get_last(dev);
81 if (ret >= 0) {
82 value = ret;
83 break;
84 }
85 }
86
87 return value;
88}
89
Stephen Warren11636252016-05-12 12:03:35 -060090void sysreset_walk_halt(enum sysreset_t type)
91{
92 int ret;
93
94 ret = sysreset_walk(type);
95
96 /* Wait for the reset to take effect */
97 if (ret == -EINPROGRESS)
98 mdelay(100);
99
100 /* Still no reset? Give up */
Simon Glasseb517312018-10-01 12:22:45 -0600101 log_err("System reset not supported on this platform\n");
Stephen Warren11636252016-05-12 12:03:35 -0600102 hang();
103}
104
105/**
106 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
107 */
108void reset_cpu(ulong addr)
109{
110 sysreset_walk_halt(SYSRESET_WARM);
111}
112
113
114int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
115{
Bin Meng406be392018-07-19 03:07:31 -0700116 printf("resetting ...\n");
117
Philipp Tomsichb53f69922017-11-24 18:37:58 +0100118 sysreset_walk_halt(SYSRESET_COLD);
Stephen Warren11636252016-05-12 12:03:35 -0600119
120 return 0;
121}
122
Urja Rannikkob8050512019-05-16 21:48:42 +0000123#if IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
124int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
125{
126 int ret;
127
128 puts("poweroff ...\n");
129 mdelay(100);
130
131 ret = sysreset_walk(SYSRESET_POWER_OFF);
132
133 if (ret == -EINPROGRESS)
134 mdelay(1000);
135
136 /*NOTREACHED when power off*/
137 return CMD_RET_FAILURE;
138}
139#endif
140
Michal Simek758de972018-07-12 10:36:07 +0200141static int sysreset_post_bind(struct udevice *dev)
142{
143#if defined(CONFIG_NEEDS_MANUAL_RELOC)
144 struct sysreset_ops *ops = sysreset_get_ops(dev);
145 static int reloc_done;
146
147 if (!reloc_done) {
148 if (ops->request)
149 ops->request += gd->reloc_off;
150 reloc_done++;
151 }
152#endif
153 return 0;
154}
155
Stephen Warren11636252016-05-12 12:03:35 -0600156UCLASS_DRIVER(sysreset) = {
157 .id = UCLASS_SYSRESET,
158 .name = "sysreset",
Michal Simek758de972018-07-12 10:36:07 +0200159 .post_bind = sysreset_post_bind,
Stephen Warren11636252016-05-12 12:03:35 -0600160};