uboot/drivers/timer/timer-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
   4 */
   5
   6#define LOG_CATEGORY UCLASS_TIMER
   7
   8#include <common.h>
   9#include <clk.h>
  10#include <cpu.h>
  11#include <dm.h>
  12#include <asm/global_data.h>
  13#include <dm/lists.h>
  14#include <dm/device_compat.h>
  15#include <dm/device-internal.h>
  16#include <dm/root.h>
  17#include <errno.h>
  18#include <init.h>
  19#include <timer.h>
  20#include <linux/err.h>
  21
  22DECLARE_GLOBAL_DATA_PTR;
  23
  24/*
  25 * Implement a timer uclass to work with lib/time.c. The timer is usually
  26 * a 32/64 bits free-running up counter. The get_rate() method is used to get
  27 * the input clock frequency of the timer. The get_count() method is used
  28 * to get the current 64 bits count value. If the hardware is counting down,
  29 * the value should be inversed inside the method. There may be no real
  30 * tick, and no timer interrupt.
  31 */
  32
  33int notrace timer_get_count(struct udevice *dev, u64 *count)
  34{
  35        const struct timer_ops *ops = device_get_ops(dev);
  36
  37        if (!ops->get_count)
  38                return -ENOSYS;
  39
  40        *count = ops->get_count(dev);
  41        return 0;
  42}
  43
  44unsigned long notrace timer_get_rate(struct udevice *dev)
  45{
  46        struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  47
  48        return uc_priv->clock_rate;
  49}
  50
  51static int timer_pre_probe(struct udevice *dev)
  52{
  53        if (CONFIG_IS_ENABLED(OF_REAL)) {
  54                struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  55                struct clk timer_clk;
  56                int err;
  57                ulong ret;
  58
  59                /*
  60                 * It is possible that a timer device has a null ofnode
  61                 */
  62                if (!dev_has_ofnode(dev))
  63                        return 0;
  64
  65                err = clk_get_by_index(dev, 0, &timer_clk);
  66                if (!err) {
  67                        ret = clk_get_rate(&timer_clk);
  68                        if (IS_ERR_VALUE(ret))
  69                                return ret;
  70                        uc_priv->clock_rate = ret;
  71                } else {
  72                        uc_priv->clock_rate =
  73                                dev_read_u32_default(dev, "clock-frequency", 0);
  74                }
  75        }
  76
  77        return 0;
  78}
  79
  80static int timer_post_probe(struct udevice *dev)
  81{
  82        struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  83
  84        if (!uc_priv->clock_rate)
  85                return -EINVAL;
  86
  87        return 0;
  88}
  89
  90#if CONFIG_IS_ENABLED(CPU)
  91int timer_timebase_fallback(struct udevice *dev)
  92{
  93        struct udevice *cpu;
  94        struct cpu_plat *cpu_plat;
  95        struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  96
  97        /* Did we get our clock rate from the device tree? */
  98        if (uc_priv->clock_rate)
  99                return 0;
 100
 101        /* Fall back to timebase-frequency */
 102        dev_dbg(dev, "missing clocks or clock-frequency property; falling back on timebase-frequency\n");
 103        cpu = cpu_get_current_dev();
 104        if (!cpu)
 105                return -ENODEV;
 106
 107        cpu_plat = dev_get_parent_plat(cpu);
 108        if (!cpu_plat)
 109                return -ENODEV;
 110
 111        uc_priv->clock_rate = cpu_plat->timebase_freq;
 112        return 0;
 113}
 114#endif
 115
 116u64 timer_conv_64(u32 count)
 117{
 118        /* increment tbh if tbl has rolled over */
 119        if (count < gd->timebase_l)
 120                gd->timebase_h++;
 121        gd->timebase_l = count;
 122        return ((u64)gd->timebase_h << 32) | gd->timebase_l;
 123}
 124
 125int notrace dm_timer_init(void)
 126{
 127        struct udevice *dev = NULL;
 128        __maybe_unused ofnode node;
 129        int ret;
 130
 131        if (gd->timer)
 132                return 0;
 133
 134        /*
 135         * Directly access gd->dm_root to suppress error messages, if the
 136         * virtual root driver does not yet exist.
 137         */
 138        if (gd->dm_root == NULL)
 139                return -EAGAIN;
 140
 141        if (CONFIG_IS_ENABLED(OF_REAL)) {
 142                /* Check for a chosen timer to be used for tick */
 143                node = ofnode_get_chosen_node("tick-timer");
 144
 145                if (ofnode_valid(node) &&
 146                    uclass_get_device_by_ofnode(UCLASS_TIMER, node, &dev)) {
 147                        /*
 148                         * If the timer is not marked to be bound before
 149                         * relocation, bind it anyway.
 150                         */
 151                        if (!lists_bind_fdt(dm_root(), node, &dev, NULL, false)) {
 152                                ret = device_probe(dev);
 153                                if (ret)
 154                                        return ret;
 155                        }
 156                }
 157        }
 158
 159        if (!dev) {
 160                /* Fall back to the first available timer */
 161                ret = uclass_first_device_err(UCLASS_TIMER, &dev);
 162                if (ret)
 163                        return ret;
 164        }
 165
 166        if (dev) {
 167                gd->timer = dev;
 168                return 0;
 169        }
 170
 171        return -ENODEV;
 172}
 173
 174UCLASS_DRIVER(timer) = {
 175        .id             = UCLASS_TIMER,
 176        .name           = "timer",
 177        .pre_probe      = timer_pre_probe,
 178        .flags          = DM_UC_FLAG_SEQ_ALIAS,
 179        .post_probe     = timer_post_probe,
 180        .per_device_auto        = sizeof(struct timer_dev_priv),
 181};
 182