uboot/drivers/hwspinlock/hwspinlock-uclass.c
<<
>>
Prefs
   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
  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};
 145