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