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