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/global_data.h> 38#include <asm/io.h> 39#include <asm/arch/hardware.h> 40#include <asm/arch/clk.h> 41 42DECLARE_GLOBAL_DATA_PTR; 43 44struct scu_timer { 45 u32 load; /* Timer Load Register */ 46 u32 counter; /* Timer Counter Register */ 47 u32 control; /* Timer Control Register */ 48}; 49 50static struct scu_timer *timer_base = 51 (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR; 52 53#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ 54#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8 55#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */ 56#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */ 57 58#define TIMER_LOAD_VAL 0xFFFFFFFF 59#define TIMER_PRESCALE 255 60 61int timer_init(void) 62{ 63 const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK | 64 (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | 65 SCUTIMER_CONTROL_ENABLE_MASK; 66 67 struct udevice *dev; 68 struct clk clk; 69 int ret; 70 71 ret = uclass_get_device_by_driver(UCLASS_CLK, 72 DM_DRIVER_GET(zynq_clk), &dev); 73 if (ret) 74 return ret; 75 76 clk.id = cpu_6or4x_clk; 77 ret = clk_request(dev, &clk); 78 if (ret < 0) 79 return ret; 80 81 gd->cpu_clk = clk_get_rate(&clk); 82 83 clk_free(&clk); 84 85 gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1); 86 87 /* Load the timer counter register */ 88 writel(0xFFFFFFFF, &timer_base->load); 89 90 /* 91 * Start the A9Timer device 92 * Enable Auto reload mode, Clear prescaler control bits 93 * Set prescaler value, Enable the decrementer 94 */ 95 clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK, 96 emask); 97 98 /* Reset time */ 99 gd->arch.lastinc = readl(&timer_base->counter) / 100 (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); 101 gd->arch.tbl = 0; 102 103 return 0; 104} 105 106/* 107 * This function is derived from PowerPC code (timebase clock frequency). 108 * On ARM it returns the number of timer ticks per second. 109 */ 110ulong get_tbclk(void) 111{ 112 return gd->arch.timer_rate_hz; 113} 114