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_walk(enum sysreset_t type) 28 { 29 struct udevice *dev; 30 int ret = -ENOSYS; 31 32 while (ret != -EINPROGRESS && type < SYSRESET_COUNT) { 33 for (uclass_first_device(UCLASS_SYSRESET, &dev); 34 dev; 35 uclass_next_device(&dev)) { 36 ret = sysreset_request(dev, type); 37 if (ret == -EINPROGRESS) 38 break; 39 } 40 type++; 41 } 42 43 return ret; 44 } 45 46 void sysreset_walk_halt(enum sysreset_t type) 47 { 48 int ret; 49 50 ret = sysreset_walk(type); 51 52 /* Wait for the reset to take effect */ 53 if (ret == -EINPROGRESS) 54 mdelay(100); 55 56 /* Still no reset? Give up */ 57 debug("System reset not supported on this platform\n"); 58 hang(); 59 } 60 61 /** 62 * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) 63 */ 64 void reset_cpu(ulong addr) 65 { 66 sysreset_walk_halt(SYSRESET_WARM); 67 } 68 69 70 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 71 { 72 sysreset_walk_halt(SYSRESET_COLD); 73 74 return 0; 75 } 76 77 static int sysreset_post_bind(struct udevice *dev) 78 { 79 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 80 struct sysreset_ops *ops = sysreset_get_ops(dev); 81 static int reloc_done; 82 83 if (!reloc_done) { 84 if (ops->request) 85 ops->request += gd->reloc_off; 86 reloc_done++; 87 } 88 #endif 89 return 0; 90 } 91 92 UCLASS_DRIVER(sysreset) = { 93 .id = UCLASS_SYSRESET, 94 .name = "sysreset", 95 .post_bind = sysreset_post_bind, 96 }; 97