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