1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 2 /* 3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <hwspinlock.h> 10 #include <dm/device-internal.h> 11 12 static inline const struct hwspinlock_ops * 13 hwspinlock_dev_ops(struct udevice *dev) 14 { 15 return (const struct hwspinlock_ops *)dev->driver->ops; 16 } 17 18 static int hwspinlock_of_xlate_default(struct hwspinlock *hws, 19 struct ofnode_phandle_args *args) 20 { 21 if (args->args_count > 1) { 22 debug("Invaild args_count: %d\n", args->args_count); 23 return -EINVAL; 24 } 25 26 if (args->args_count) 27 hws->id = args->args[0]; 28 else 29 hws->id = 0; 30 31 return 0; 32 } 33 34 int hwspinlock_get_by_index(struct udevice *dev, int index, 35 struct hwspinlock *hws) 36 { 37 int ret; 38 struct ofnode_phandle_args args; 39 struct udevice *dev_hws; 40 const struct hwspinlock_ops *ops; 41 42 assert(hws); 43 hws->dev = NULL; 44 45 ret = dev_read_phandle_with_args(dev, "hwlocks", "#hwlock-cells", 1, 46 index, &args); 47 if (ret) { 48 dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", 49 __func__, ret); 50 return ret; 51 } 52 53 ret = uclass_get_device_by_ofnode(UCLASS_HWSPINLOCK, 54 args.node, &dev_hws); 55 if (ret) { 56 dev_dbg(dev, 57 "%s: uclass_get_device_by_of_offset failed: err=%d\n", 58 __func__, ret); 59 return ret; 60 } 61 62 hws->dev = dev_hws; 63 64 ops = hwspinlock_dev_ops(dev_hws); 65 66 if (ops->of_xlate) 67 ret = ops->of_xlate(hws, &args); 68 else 69 ret = hwspinlock_of_xlate_default(hws, &args); 70 if (ret) 71 dev_dbg(dev, "of_xlate() failed: %d\n", ret); 72 73 return ret; 74 } 75 76 int hwspinlock_lock_timeout(struct hwspinlock *hws, unsigned int timeout) 77 { 78 const struct hwspinlock_ops *ops; 79 ulong start; 80 int ret; 81 82 assert(hws); 83 84 if (!hws->dev) 85 return -EINVAL; 86 87 ops = hwspinlock_dev_ops(hws->dev); 88 if (!ops->lock) 89 return -ENOSYS; 90 91 start = get_timer(0); 92 do { 93 ret = ops->lock(hws->dev, hws->id); 94 if (!ret) 95 return ret; 96 97 if (ops->relax) 98 ops->relax(hws->dev); 99 } while (get_timer(start) < timeout); 100 101 return -ETIMEDOUT; 102 } 103 104 int hwspinlock_unlock(struct hwspinlock *hws) 105 { 106 const struct hwspinlock_ops *ops; 107 108 assert(hws); 109 110 if (!hws->dev) 111 return -EINVAL; 112 113 ops = hwspinlock_dev_ops(hws->dev); 114 if (!ops->unlock) 115 return -ENOSYS; 116 117 return ops->unlock(hws->dev, hws->id); 118 } 119 120 static int hwspinlock_post_bind(struct udevice *dev) 121 { 122 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 123 struct hwspinlock_ops *ops = device_get_ops(dev); 124 static int reloc_done; 125 126 if (!reloc_done) { 127 if (ops->lock) 128 ops->lock += gd->reloc_off; 129 if (ops->unlock) 130 ops->unlock += gd->reloc_off; 131 if (ops->relax) 132 ops->relax += gd->reloc_off; 133 134 reloc_done++; 135 } 136 #endif 137 return 0; 138 } 139 140 UCLASS_DRIVER(hwspinlock) = { 141 .id = UCLASS_HWSPINLOCK, 142 .name = "hwspinlock", 143 .post_bind = hwspinlock_post_bind, 144 }; 145