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 <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 19 int 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 29 int 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 39 int sysreset_get_last(struct udevice *dev) 40 { 41 struct sysreset_ops *ops = sysreset_get_ops(dev); 42 43 if (!ops->get_last) 44 return -ENOSYS; 45 46 return ops->get_last(dev); 47 } 48 49 int sysreset_walk(enum sysreset_t type) 50 { 51 struct udevice *dev; 52 int ret = -ENOSYS; 53 54 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) { 55 for (uclass_first_device(UCLASS_SYSRESET, &dev); 56 dev; 57 uclass_next_device(&dev)) { 58 ret = sysreset_request(dev, type); 59 if (ret == -EINPROGRESS) 60 break; 61 } 62 type++; 63 } 64 65 return ret; 66 } 67 68 int sysreset_get_last_walk(void) 69 { 70 struct udevice *dev; 71 int value = -ENOENT; 72 73 for (uclass_first_device(UCLASS_SYSRESET, &dev); 74 dev; 75 uclass_next_device(&dev)) { 76 int ret; 77 78 ret = sysreset_get_last(dev); 79 if (ret >= 0) { 80 value = ret; 81 break; 82 } 83 } 84 85 return value; 86 } 87 88 void sysreset_walk_halt(enum sysreset_t type) 89 { 90 int ret; 91 92 ret = sysreset_walk(type); 93 94 /* Wait for the reset to take effect */ 95 if (ret == -EINPROGRESS) 96 mdelay(100); 97 98 /* Still no reset? Give up */ 99 log_err("System reset not supported on this platform\n"); 100 hang(); 101 } 102 103 /** 104 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) 105 */ 106 void reset_cpu(ulong addr) 107 { 108 sysreset_walk_halt(SYSRESET_WARM); 109 } 110 111 112 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 113 { 114 printf("resetting ...\n"); 115 116 sysreset_walk_halt(SYSRESET_COLD); 117 118 return 0; 119 } 120 121 static int sysreset_post_bind(struct udevice *dev) 122 { 123 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 124 struct sysreset_ops *ops = sysreset_get_ops(dev); 125 static int reloc_done; 126 127 if (!reloc_done) { 128 if (ops->request) 129 ops->request += gd->reloc_off; 130 reloc_done++; 131 } 132 #endif 133 return 0; 134 } 135 136 UCLASS_DRIVER(sysreset) = { 137 .id = UCLASS_SYSRESET, 138 .name = "sysreset", 139 .post_bind = sysreset_post_bind, 140 }; 141