Merge branch 'master' of git://git.denx.de/u-boot-socfpga
[oweals/u-boot.git] / drivers / hwspinlock / hwspinlock-uclass.c
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 };