Commit 057b613990d1665d1d2936655a1aca1962126800

Authored by Stephan Gerhold
Committed by Tom Rini
1 parent c82216803d

timer: Add driver for Nomadik Multi Timer Unit (MTU)

The Nomadik Multi Timer Unit (MTU) provides 4 decrementing
free-running timers. It is used in ST-Ericsson Ux500 SoCs.

The driver uses the first timer to implement UCLASS_TIMER.

Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Showing 3 changed files with 124 additions and 0 deletions Side-by-side Diff

drivers/timer/Kconfig
... ... @@ -127,6 +127,15 @@
127 127 hardware ways, nor got from device tree at the time when device
128 128 tree is not available yet.
129 129  
  130 +config NOMADIK_MTU_TIMER
  131 + bool "Nomadik MTU Timer"
  132 + depends on TIMER
  133 + help
  134 + Enables support for the Nomadik Multi Timer Unit (MTU),
  135 + used in ST-Ericsson Ux500 SoCs.
  136 + The MTU provides 4 decrementing free-running timers.
  137 + At the moment, only the first timer is used by the driver.
  138 +
130 139 config OMAP_TIMER
131 140 bool "Omap timer support"
132 141 depends on TIMER
drivers/timer/Makefile
... ... @@ -12,6 +12,7 @@
12 12 obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o
13 13 obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o
14 14 obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
  15 +obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o
15 16 obj-$(CONFIG_OMAP_TIMER) += omap-timer.o
16 17 obj-$(CONFIG_RENESAS_OSTM_TIMER) += ostm_timer.o
17 18 obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
drivers/timer/nomadik-mtu-timer.c
  1 +// SPDX-License-Identifier: GPL-2.0-or-later
  2 +/*
  3 + * Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
  4 + *
  5 + * Based on arch/arm/cpu/armv7/u8500/timer.c:
  6 + * Copyright (C) 2010 Linaro Limited
  7 + * John Rigby <john.rigby@linaro.org>
  8 + *
  9 + * Based on Linux kernel source and internal ST-Ericsson U-Boot source:
  10 + * Copyright (C) 2009 Alessandro Rubini
  11 + * Copyright (C) 2010 ST-Ericsson
  12 + * Copyright (C) 2010 Linus Walleij for ST-Ericsson
  13 + */
  14 +
  15 +#include <common.h>
  16 +#include <dm.h>
  17 +#include <timer.h>
  18 +#include <asm/io.h>
  19 +
  20 +#define MTU_NUM_TIMERS 4
  21 +
  22 +/* The timers */
  23 +struct nomadik_mtu_timer_regs {
  24 + u32 lr; /* Load register */
  25 + u32 cv; /* Current value */
  26 + u32 cr; /* Control register */
  27 + u32 bglr; /* Background load register */
  28 +};
  29 +
  30 +/* The MTU that contains the timers */
  31 +struct nomadik_mtu_regs {
  32 + u32 imsc; /* Interrupt mask set/clear */
  33 + u32 ris; /* Raw interrupt status */
  34 + u32 mis; /* Masked interrupt status */
  35 + u32 icr; /* Interrupt clear register */
  36 +
  37 + struct nomadik_mtu_timer_regs timers[MTU_NUM_TIMERS];
  38 +};
  39 +
  40 +/* Bits for the control register */
  41 +#define MTU_CR_ONESHOT BIT(0) /* if 0 = wraps reloading from BGLR */
  42 +#define MTU_CR_32BITS BIT(1) /* if 0 = 16-bit counter */
  43 +
  44 +#define MTU_CR_PRESCALE_SHIFT 2
  45 +#define MTU_CR_PRESCALE_1 (0 << MTU_CR_PRESCALE_SHIFT)
  46 +#define MTU_CR_PRESCALE_16 (1 << MTU_CR_PRESCALE_SHIFT)
  47 +#define MTU_CR_PRESCALE_256 (2 << MTU_CR_PRESCALE_SHIFT)
  48 +
  49 +#define MTU_CR_PERIODIC BIT(6) /* if 0 = free-running */
  50 +#define MTU_CR_ENABLE BIT(7)
  51 +
  52 +struct nomadik_mtu_priv {
  53 + struct nomadik_mtu_timer_regs *timer;
  54 +};
  55 +
  56 +static int nomadik_mtu_get_count(struct udevice *dev, u64 *count)
  57 +{
  58 + struct nomadik_mtu_priv *priv = dev_get_priv(dev);
  59 +
  60 + /* Decrementing counter: invert the value */
  61 + *count = timer_conv_64(~readl(&priv->timer->cv));
  62 +
  63 + return 0;
  64 +}
  65 +
  66 +static int nomadik_mtu_probe(struct udevice *dev)
  67 +{
  68 + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  69 + struct nomadik_mtu_priv *priv = dev_get_priv(dev);
  70 + struct nomadik_mtu_regs *mtu;
  71 + fdt_addr_t addr;
  72 + u32 prescale;
  73 +
  74 + addr = dev_read_addr(dev);
  75 + if (addr == FDT_ADDR_T_NONE)
  76 + return -EINVAL;
  77 +
  78 + mtu = (struct nomadik_mtu_regs *)addr;
  79 + priv->timer = mtu->timers; /* Use first timer */
  80 +
  81 + if (!uc_priv->clock_rate)
  82 + return -EINVAL;
  83 +
  84 + /* Use divide-by-16 counter if tick rate is more than 32 MHz */
  85 + if (uc_priv->clock_rate > 32000000) {
  86 + uc_priv->clock_rate /= 16;
  87 + prescale = MTU_CR_PRESCALE_16;
  88 + } else {
  89 + prescale = MTU_CR_PRESCALE_1;
  90 + }
  91 +
  92 + /* Configure a free-running, auto-wrap counter with selected prescale */
  93 + writel(MTU_CR_ENABLE | prescale | MTU_CR_32BITS, &priv->timer->cr);
  94 +
  95 + return 0;
  96 +}
  97 +
  98 +static const struct timer_ops nomadik_mtu_ops = {
  99 + .get_count = nomadik_mtu_get_count,
  100 +};
  101 +
  102 +static const struct udevice_id nomadik_mtu_ids[] = {
  103 + { .compatible = "st,nomadik-mtu" },
  104 + {}
  105 +};
  106 +
  107 +U_BOOT_DRIVER(nomadik_mtu) = {
  108 + .name = "nomadik_mtu",
  109 + .id = UCLASS_TIMER,
  110 + .of_match = nomadik_mtu_ids,
  111 + .priv_auto_alloc_size = sizeof(struct nomadik_mtu_priv),
  112 + .probe = nomadik_mtu_probe,
  113 + .ops = &nomadik_mtu_ops,
  114 +};