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