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_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 58 void 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 */ 69 log_err("System reset not supported on this platform\n"); 70 hang(); 71 } 72 73 /** 74 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) 75 */ 76 void reset_cpu(ulong addr) 77 { 78 sysreset_walk_halt(SYSRESET_WARM); 79 } 80 81 82 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 83 { 84 printf("resetting ...\n"); 85 86 sysreset_walk_halt(SYSRESET_COLD); 87 88 return 0; 89 } 90 91 static 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 106 UCLASS_DRIVER(sysreset) = { 107 .id = UCLASS_SYSRESET, 108 .name = "sysreset", 109 .post_bind = sysreset_post_bind, 110 }; 111