xref: /rk3399_rockchip-uboot/drivers/sysreset/sysreset-uclass.c (revision 5a58a088a7d0601443c59b778bbe6ec828e74214)
1 /*
2  * Copyright (C) 2015 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <sysreset.h>
10 #include <dm.h>
11 #include <errno.h>
12 #include <regmap.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15 #include <dm/root.h>
16 #include <linux/err.h>
17 
18 #ifdef CONFIG_ARCH_ROCKCHIP
reset_misc(void)19 __weak void reset_misc(void)
20 {
21 }
22 #endif
23 
sysreset_request(struct udevice * dev,enum sysreset_t type)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 
sysreset_walk(enum sysreset_t type)34 int sysreset_walk(enum sysreset_t type)
35 {
36 	struct udevice *dev;
37 	int ret = -ENOSYS;
38 
39 	while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
40 		for (uclass_first_device(UCLASS_SYSRESET, &dev);
41 		     dev;
42 		     uclass_next_device(&dev)) {
43 			ret = sysreset_request(dev, type);
44 			if (ret == -EINPROGRESS)
45 				break;
46 		}
47 		type++;
48 	}
49 
50 	return ret;
51 }
52 
sysreset_walk_reboot_mode(const char * mode)53 static void sysreset_walk_reboot_mode(const char *mode)
54 {
55 	struct sysreset_ops *ops;
56 	struct udevice *dev;
57 
58 	if (!mode)
59 		return;
60 
61 	for (uclass_first_device(UCLASS_SYSRESET, &dev);
62 	     dev;
63 	     uclass_next_device(&dev)) {
64 		ops = sysreset_get_ops(dev);
65 		if (ops && ops->request_by_mode) {
66 			ops->request_by_mode(dev, mode);
67 			break;
68 		}
69 	}
70 }
71 
sysreset_walk_halt(enum sysreset_t type)72 void sysreset_walk_halt(enum sysreset_t type)
73 {
74 	int ret;
75 
76 	ret = sysreset_walk(type);
77 
78 	/* Wait for the reset to take effect */
79 	if (ret == -EINPROGRESS)
80 		mdelay(100);
81 
82 	/* Still no reset? Give up */
83 	debug("System reset not supported on this platform\n");
84 	hang();
85 }
86 
87 /**
88  * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
89  */
reset_cpu(ulong addr)90 void reset_cpu(ulong addr)
91 {
92 	sysreset_walk_halt(SYSRESET_WARM);
93 }
94 
reboot(const char * mode)95 void reboot(const char *mode)
96 {
97 	sysreset_walk_reboot_mode(mode);
98 	flushc();
99 	sysreset_walk_halt(SYSRESET_COLD);
100 }
101 
do_reset(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])102 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
103 {
104 #ifdef CONFIG_ARCH_ROCKCHIP
105 	reset_misc();
106 #endif
107 
108 	if (argc > 1)
109 		reboot(argv[1]);
110 	else
111 		reboot(NULL);
112 
113 	return 0;
114 }
115 
116 UCLASS_DRIVER(sysreset) = {
117 	.id		= UCLASS_SYSRESET,
118 	.name		= "sysreset",
119 };
120