blob: 0abb4042e0f2ec7df7232eaca25e28df49679b3f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stephen Warren859f2562016-05-12 12:03:35 -06002/*
3 * Copyright (C) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Stephen Warren859f2562016-05-12 12:03:35 -06005 */
6
Simon Glassb8b4d2a2018-10-01 12:22:45 -06007#define LOG_CATEGORY UCLASS_SYSRESET
8
Simon Glassed38aef2020-05-10 11:40:03 -06009#include <command.h>
Simon Glassafb02152019-12-28 10:45:01 -070010#include <cpu_func.h>
Stephen Warren859f2562016-05-12 12:03:35 -060011#include <dm.h>
12#include <errno.h>
Simon Glass12905d62020-12-23 08:11:14 -070013#include <hang.h>
14#include <log.h>
Stephen Warren859f2562016-05-12 12:03:35 -060015#include <regmap.h>
Simon Glass12905d62020-12-23 08:11:14 -070016#include <spl.h>
17#include <sysreset.h>
Stephen Warren859f2562016-05-12 12:03:35 -060018#include <dm/device-internal.h>
19#include <dm/lists.h>
20#include <dm/root.h>
Simon Glassdbd79542020-05-10 11:40:11 -060021#include <linux/delay.h>
Stephen Warren859f2562016-05-12 12:03:35 -060022#include <linux/err.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060023#include <asm/global_data.h>
Stephen Warren859f2562016-05-12 12:03:35 -060024
25int sysreset_request(struct udevice *dev, enum sysreset_t type)
26{
27 struct sysreset_ops *ops = sysreset_get_ops(dev);
28
29 if (!ops->request)
30 return -ENOSYS;
31
32 return ops->request(dev, type);
33}
34
Mario Six265f82a2018-08-06 10:23:32 +020035int sysreset_get_status(struct udevice *dev, char *buf, int size)
36{
37 struct sysreset_ops *ops = sysreset_get_ops(dev);
38
39 if (!ops->get_status)
40 return -ENOSYS;
41
42 return ops->get_status(dev, buf, size);
43}
44
Simon Glass07fbba52018-10-01 12:22:46 -060045int sysreset_get_last(struct udevice *dev)
46{
47 struct sysreset_ops *ops = sysreset_get_ops(dev);
48
49 if (!ops->get_last)
50 return -ENOSYS;
51
52 return ops->get_last(dev);
53}
54
Stephen Warren859f2562016-05-12 12:03:35 -060055int sysreset_walk(enum sysreset_t type)
56{
57 struct udevice *dev;
58 int ret = -ENOSYS;
59
60 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
61 for (uclass_first_device(UCLASS_SYSRESET, &dev);
62 dev;
63 uclass_next_device(&dev)) {
64 ret = sysreset_request(dev, type);
65 if (ret == -EINPROGRESS)
66 break;
67 }
68 type++;
69 }
70
71 return ret;
72}
73
Simon Glass07fbba52018-10-01 12:22:46 -060074int sysreset_get_last_walk(void)
75{
76 struct udevice *dev;
77 int value = -ENOENT;
78
79 for (uclass_first_device(UCLASS_SYSRESET, &dev);
80 dev;
81 uclass_next_device(&dev)) {
82 int ret;
83
84 ret = sysreset_get_last(dev);
85 if (ret >= 0) {
86 value = ret;
87 break;
88 }
89 }
90
91 return value;
92}
93
Stephen Warren859f2562016-05-12 12:03:35 -060094void sysreset_walk_halt(enum sysreset_t type)
95{
96 int ret;
97
98 ret = sysreset_walk(type);
99
100 /* Wait for the reset to take effect */
101 if (ret == -EINPROGRESS)
102 mdelay(100);
103
104 /* Still no reset? Give up */
Simon Glass12905d62020-12-23 08:11:14 -0700105 if (spl_phase() <= PHASE_SPL)
106 log_err("no sysreset\n");
107 else
108 log_err("System reset not supported on this platform\n");
Stephen Warren859f2562016-05-12 12:03:35 -0600109 hang();
110}
111
112/**
113 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
114 */
Harald Seiler6f14d5f2020-12-15 16:47:52 +0100115void reset_cpu(void)
Stephen Warren859f2562016-05-12 12:03:35 -0600116{
117 sysreset_walk_halt(SYSRESET_WARM);
118}
119
120
Bin Menga0aba782021-02-25 17:22:52 +0800121#if IS_ENABLED(CONFIG_SYSRESET_CMD_RESET)
Simon Glassed38aef2020-05-10 11:40:03 -0600122int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Stephen Warren859f2562016-05-12 12:03:35 -0600123{
Igor Opaniuk814f3032021-04-01 02:01:55 +0300124 enum sysreset_t reset_type = SYSRESET_COLD;
125
126 if (argc > 2)
127 return CMD_RET_USAGE;
128
129 if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'w') {
130 reset_type = SYSRESET_WARM;
131 }
132
Bin Meng5588e8c2018-07-19 03:07:31 -0700133 printf("resetting ...\n");
Heinrich Schuchardt22242602020-07-29 12:13:41 +0200134 mdelay(100);
Bin Meng5588e8c2018-07-19 03:07:31 -0700135
Igor Opaniuk814f3032021-04-01 02:01:55 +0300136 sysreset_walk_halt(reset_type);
Stephen Warren859f2562016-05-12 12:03:35 -0600137
138 return 0;
139}
Bin Menga0aba782021-02-25 17:22:52 +0800140#endif
Stephen Warren859f2562016-05-12 12:03:35 -0600141
Urja Rannikkoe008ebf2019-05-16 21:48:42 +0000142#if IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
Simon Glassed38aef2020-05-10 11:40:03 -0600143int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Urja Rannikkoe008ebf2019-05-16 21:48:42 +0000144{
145 int ret;
146
147 puts("poweroff ...\n");
148 mdelay(100);
149
150 ret = sysreset_walk(SYSRESET_POWER_OFF);
151
152 if (ret == -EINPROGRESS)
153 mdelay(1000);
154
155 /*NOTREACHED when power off*/
156 return CMD_RET_FAILURE;
157}
158#endif
159
Stephen Warren859f2562016-05-12 12:03:35 -0600160UCLASS_DRIVER(sysreset) = {
161 .id = UCLASS_SYSRESET,
162 .name = "sysreset",
Stephen Warren859f2562016-05-12 12:03:35 -0600163};