common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / sysreset / sysreset-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #define LOG_CATEGORY UCLASS_SYSRESET
8
9 #include <common.h>
10 #include <command.h>
11 #include <cpu_func.h>
12 #include <hang.h>
13 #include <log.h>
14 #include <sysreset.h>
15 #include <dm.h>
16 #include <errno.h>
17 #include <regmap.h>
18 #include <dm/device-internal.h>
19 #include <dm/lists.h>
20 #include <dm/root.h>
21 #include <linux/delay.h>
22 #include <linux/err.h>
23
24 int sysreset_request(struct udevice *dev, enum sysreset_t type)
25 {
26         struct sysreset_ops *ops = sysreset_get_ops(dev);
27
28         if (!ops->request)
29                 return -ENOSYS;
30
31         return ops->request(dev, type);
32 }
33
34 int sysreset_get_status(struct udevice *dev, char *buf, int size)
35 {
36         struct sysreset_ops *ops = sysreset_get_ops(dev);
37
38         if (!ops->get_status)
39                 return -ENOSYS;
40
41         return ops->get_status(dev, buf, size);
42 }
43
44 int sysreset_get_last(struct udevice *dev)
45 {
46         struct sysreset_ops *ops = sysreset_get_ops(dev);
47
48         if (!ops->get_last)
49                 return -ENOSYS;
50
51         return ops->get_last(dev);
52 }
53
54 int sysreset_walk(enum sysreset_t type)
55 {
56         struct udevice *dev;
57         int ret = -ENOSYS;
58
59         while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
60                 for (uclass_first_device(UCLASS_SYSRESET, &dev);
61                      dev;
62                      uclass_next_device(&dev)) {
63                         ret = sysreset_request(dev, type);
64                         if (ret == -EINPROGRESS)
65                                 break;
66                 }
67                 type++;
68         }
69
70         return ret;
71 }
72
73 int sysreset_get_last_walk(void)
74 {
75         struct udevice *dev;
76         int value = -ENOENT;
77
78         for (uclass_first_device(UCLASS_SYSRESET, &dev);
79              dev;
80              uclass_next_device(&dev)) {
81                 int ret;
82
83                 ret = sysreset_get_last(dev);
84                 if (ret >= 0) {
85                         value = ret;
86                         break;
87                 }
88         }
89
90         return value;
91 }
92
93 void sysreset_walk_halt(enum sysreset_t type)
94 {
95         int ret;
96
97         ret = sysreset_walk(type);
98
99         /* Wait for the reset to take effect */
100         if (ret == -EINPROGRESS)
101                 mdelay(100);
102
103         /* Still no reset? Give up */
104         log_err("System reset not supported on this platform\n");
105         hang();
106 }
107
108 /**
109  * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
110  */
111 void reset_cpu(ulong addr)
112 {
113         sysreset_walk_halt(SYSRESET_WARM);
114 }
115
116
117 int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
118 {
119         printf("resetting ...\n");
120
121         sysreset_walk_halt(SYSRESET_COLD);
122
123         return 0;
124 }
125
126 #if IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
127 int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
128 {
129         int ret;
130
131         puts("poweroff ...\n");
132         mdelay(100);
133
134         ret = sysreset_walk(SYSRESET_POWER_OFF);
135
136         if (ret == -EINPROGRESS)
137                 mdelay(1000);
138
139         /*NOTREACHED when power off*/
140         return CMD_RET_FAILURE;
141 }
142 #endif
143
144 static int sysreset_post_bind(struct udevice *dev)
145 {
146 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
147         struct sysreset_ops *ops = sysreset_get_ops(dev);
148         static int reloc_done;
149
150         if (!reloc_done) {
151                 if (ops->request)
152                         ops->request += gd->reloc_off;
153                 reloc_done++;
154         }
155 #endif
156         return 0;
157 }
158
159 UCLASS_DRIVER(sysreset) = {
160         .id             = UCLASS_SYSRESET,
161         .name           = "sysreset",
162         .post_bind      = sysreset_post_bind,
163 };