xref: /rk3399_rockchip-uboot/drivers/sysreset/sysreset-uclass.c (revision 763ecaa3060272ce614e171d1955ecfc73db92ee)
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 int sysreset_request(struct udevice *dev, enum sysreset_t type)
19 {
20 	struct sysreset_ops *ops = sysreset_get_ops(dev);
21 
22 	if (!ops->request)
23 		return -ENOSYS;
24 
25 	return ops->request(dev, type);
26 }
27 
28 int sysreset_walk(enum sysreset_t type)
29 {
30 	struct udevice *dev;
31 	int ret = -ENOSYS;
32 
33 	/*
34 	 * Use psci sysreset as primary for rockchip platforms,
35 	 * "rockchip_reset" is applied if PSCI is disabled.
36 	 */
37 #if !defined(CONFIG_TPL_BUILD) && \
38      defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_SYSRESET_PSCI)
39 	ret = uclass_get_device_by_driver(UCLASS_SYSRESET,
40 					  DM_GET_DRIVER(psci_sysreset), &dev);
41 	if (!ret)
42 		sysreset_request(dev, type);
43 	else
44 		printf("WARN: PSCI sysreset is disabled\n");
45 #endif
46 
47 	while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
48 		for (uclass_first_device(UCLASS_SYSRESET, &dev);
49 		     dev;
50 		     uclass_next_device(&dev)) {
51 			ret = sysreset_request(dev, type);
52 			if (ret == -EINPROGRESS)
53 				break;
54 		}
55 		type++;
56 	}
57 
58 	return ret;
59 }
60 
61 void sysreset_walk_halt(enum sysreset_t type)
62 {
63 	int ret;
64 
65 	ret = sysreset_walk(type);
66 
67 	/* Wait for the reset to take effect */
68 	if (ret == -EINPROGRESS)
69 		mdelay(100);
70 
71 	/* Still no reset? Give up */
72 	debug("System reset not supported on this platform\n");
73 	hang();
74 }
75 
76 /**
77  * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
78  */
79 void reset_cpu(ulong addr)
80 {
81 	sysreset_walk_halt(SYSRESET_WARM);
82 }
83 
84 void reboot(const char *mode)
85 {
86 #ifndef CONFIG_SPL_BUILD
87 	struct sysreset_ops *ops;
88 	struct udevice *dev;
89 	int ret;
90 
91 	if (!mode)
92 		goto finish;
93 
94 	ret = uclass_get_device_by_driver(UCLASS_SYSRESET,
95 					  DM_GET_DRIVER(sysreset_syscon_reboot),
96 					  &dev);
97 	if (!ret) {
98 		ops = sysreset_get_ops(dev);
99 		if (ops && ops->request_by_mode)
100 			ops->request_by_mode(dev, mode);
101 	}
102 finish:
103 #endif
104 	flushc();
105 	sysreset_walk_halt(SYSRESET_COLD);
106 }
107 
108 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
109 {
110 	if (argc > 1)
111 		reboot(argv[1]);
112 	else
113 		reboot(NULL);
114 
115 	return 0;
116 }
117 
118 UCLASS_DRIVER(sysreset) = {
119 	.id		= UCLASS_SYSRESET,
120 	.name		= "sysreset",
121 };
122