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