blob: e38814b3ed1218f539b41dfccb22c9643072feaa [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
Stephen Warren11636252016-05-12 12:03:35 -060039int sysreset_walk(enum sysreset_t type)
40{
41 struct udevice *dev;
42 int ret = -ENOSYS;
43
44 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
45 for (uclass_first_device(UCLASS_SYSRESET, &dev);
46 dev;
47 uclass_next_device(&dev)) {
48 ret = sysreset_request(dev, type);
49 if (ret == -EINPROGRESS)
50 break;
51 }
52 type++;
53 }
54
55 return ret;
56}
57
58void sysreset_walk_halt(enum sysreset_t type)
59{
60 int ret;
61
62 ret = sysreset_walk(type);
63
64 /* Wait for the reset to take effect */
65 if (ret == -EINPROGRESS)
66 mdelay(100);
67
68 /* Still no reset? Give up */
Simon Glasseb517312018-10-01 12:22:45 -060069 log_err("System reset not supported on this platform\n");
Stephen Warren11636252016-05-12 12:03:35 -060070 hang();
71}
72
73/**
74 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
75 */
76void reset_cpu(ulong addr)
77{
78 sysreset_walk_halt(SYSRESET_WARM);
79}
80
81
82int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
83{
Bin Meng406be392018-07-19 03:07:31 -070084 printf("resetting ...\n");
85
Philipp Tomsichb53f69922017-11-24 18:37:58 +010086 sysreset_walk_halt(SYSRESET_COLD);
Stephen Warren11636252016-05-12 12:03:35 -060087
88 return 0;
89}
90
Michal Simek758de972018-07-12 10:36:07 +020091static int sysreset_post_bind(struct udevice *dev)
92{
93#if defined(CONFIG_NEEDS_MANUAL_RELOC)
94 struct sysreset_ops *ops = sysreset_get_ops(dev);
95 static int reloc_done;
96
97 if (!reloc_done) {
98 if (ops->request)
99 ops->request += gd->reloc_off;
100 reloc_done++;
101 }
102#endif
103 return 0;
104}
105
Stephen Warren11636252016-05-12 12:03:35 -0600106UCLASS_DRIVER(sysreset) = {
107 .id = UCLASS_SYSRESET,
108 .name = "sysreset",
Michal Simek758de972018-07-12 10:36:07 +0200109 .post_bind = sysreset_post_bind,
Stephen Warren11636252016-05-12 12:03:35 -0600110};