blob: 195f079707cd646a7f9707ca8ece3e0f3aa85b66 [file] [log] [blame]
Benjamin Gaignarda550b542018-11-27 13:49:50 +01001// 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
12static inline const struct hwspinlock_ops *
13hwspinlock_dev_ops(struct udevice *dev)
14{
15 return (const struct hwspinlock_ops *)dev->driver->ops;
16}
17
18static 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
34int 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
76int 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
104int 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
120static 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
140UCLASS_DRIVER(hwspinlock) = {
141 .id = UCLASS_HWSPINLOCK,
142 .name = "hwspinlock",
143 .post_bind = hwspinlock_post_bind,
144};