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 #include <common.h> 8 #include <sysreset.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <regmap.h> 12 #include <dm/device-internal.h> 13 #include <dm/lists.h> 14 #include <dm/root.h> 15 #include <linux/err.h> 16 17 int sysreset_request(struct udevice *dev, enum sysreset_t type) 18 { 19 struct sysreset_ops *ops = sysreset_get_ops(dev); 20 21 if (!ops->request) 22 return -ENOSYS; 23 24 return ops->request(dev, type); 25 } 26 27 int sysreset_get_status(struct udevice *dev, char *buf, int size) 28 { 29 struct sysreset_ops *ops = sysreset_get_ops(dev); 30 31 if (!ops->get_status) 32 return -ENOSYS; 33 34 return ops->get_status(dev, buf, size); 35 } 36 37 int sysreset_walk(enum sysreset_t type) 38 { 39 struct udevice *dev; 40 int ret = -ENOSYS; 41 42 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) { 43 for (uclass_first_device(UCLASS_SYSRESET, &dev); 44 dev; 45 uclass_next_device(&dev)) { 46 ret = sysreset_request(dev, type); 47 if (ret == -EINPROGRESS) 48 break; 49 } 50 type++; 51 } 52 53 return ret; 54 } 55 56 void sysreset_walk_halt(enum sysreset_t type) 57 { 58 int ret; 59 60 ret = sysreset_walk(type); 61 62 /* Wait for the reset to take effect */ 63 if (ret == -EINPROGRESS) 64 mdelay(100); 65 66 /* Still no reset? Give up */ 67 debug("System reset not supported on this platform\n"); 68 hang(); 69 } 70 71 /** 72 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) 73 */ 74 void reset_cpu(ulong addr) 75 { 76 sysreset_walk_halt(SYSRESET_WARM); 77 } 78 79 80 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 81 { 82 printf("resetting ...\n"); 83 84 sysreset_walk_halt(SYSRESET_COLD); 85 86 return 0; 87 } 88 89 static int sysreset_post_bind(struct udevice *dev) 90 { 91 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 92 struct sysreset_ops *ops = sysreset_get_ops(dev); 93 static int reloc_done; 94 95 if (!reloc_done) { 96 if (ops->request) 97 ops->request += gd->reloc_off; 98 reloc_done++; 99 } 100 #endif 101 return 0; 102 } 103 104 UCLASS_DRIVER(sysreset) = { 105 .id = UCLASS_SYSRESET, 106 .name = "sysreset", 107 .post_bind = sysreset_post_bind, 108 }; 109