uboot/arch/arm/mach-zynq/timer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
   4 * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
   5 *
   6 * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
   7 * Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
   8 *
   9 * (C) Copyright 2008
  10 * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
  11 *
  12 * (C) Copyright 2004
  13 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
  14 *
  15 * (C) Copyright 2002-2004
  16 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
  17 *
  18 * (C) Copyright 2003
  19 * Texas Instruments <www.ti.com>
  20 *
  21 * (C) Copyright 2002
  22 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  23 * Marius Groeger <mgroeger@sysgo.de>
  24 *
  25 * (C) Copyright 2002
  26 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  27 * Alex Zuepke <azu@sysgo.de>
  28 */
  29
  30#include <clk.h>
  31#include <common.h>
  32#include <div64.h>
  33#include <dm.h>
  34#include <init.h>
  35#include <time.h>
  36#include <malloc.h>
  37#include <asm/io.h>
  38#include <asm/arch/hardware.h>
  39#include <asm/arch/clk.h>
  40
  41DECLARE_GLOBAL_DATA_PTR;
  42
  43struct scu_timer {
  44        u32 load; /* Timer Load Register */
  45        u32 counter; /* Timer Counter Register */
  46        u32 control; /* Timer Control Register */
  47};
  48
  49static struct scu_timer *timer_base =
  50                              (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
  51
  52#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
  53#define SCUTIMER_CONTROL_PRESCALER_SHIFT        8
  54#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK       0x00000002 /* Auto-reload */
  55#define SCUTIMER_CONTROL_ENABLE_MASK            0x00000001 /* Timer enable */
  56
  57#define TIMER_LOAD_VAL 0xFFFFFFFF
  58#define TIMER_PRESCALE 255
  59
  60int timer_init(void)
  61{
  62        const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
  63                        (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
  64                        SCUTIMER_CONTROL_ENABLE_MASK;
  65
  66        struct udevice *dev;
  67        struct clk clk;
  68        int ret;
  69
  70        ret = uclass_get_device_by_driver(UCLASS_CLK,
  71                DM_GET_DRIVER(zynq_clk), &dev);
  72        if (ret)
  73                return ret;
  74
  75        clk.id = cpu_6or4x_clk;
  76        ret = clk_request(dev, &clk);
  77        if (ret < 0)
  78                return ret;
  79
  80        gd->cpu_clk = clk_get_rate(&clk);
  81
  82        clk_free(&clk);
  83
  84        gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
  85
  86        /* Load the timer counter register */
  87        writel(0xFFFFFFFF, &timer_base->load);
  88
  89        /*
  90         * Start the A9Timer device
  91         * Enable Auto reload mode, Clear prescaler control bits
  92         * Set prescaler value, Enable the decrementer
  93         */
  94        clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
  95                                                                emask);
  96
  97        /* Reset time */
  98        gd->arch.lastinc = readl(&timer_base->counter) /
  99                                (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
 100        gd->arch.tbl = 0;
 101
 102        return 0;
 103}
 104
 105/*
 106 * This function is derived from PowerPC code (timebase clock frequency).
 107 * On ARM it returns the number of timer ticks per second.
 108 */
 109ulong get_tbclk(void)
 110{
 111        return gd->arch.timer_rate_hz;
 112}
 113