18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap2/timer.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * OMAP2 GP timer support. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Update to use new clocksource/clockevent layers 98c2ecf20Sopenharmony_ci * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> 108c2ecf20Sopenharmony_ci * Copyright (C) 2007 MontaVista Software, Inc. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Original driver: 138c2ecf20Sopenharmony_ci * Copyright (C) 2005 Nokia Corporation 148c2ecf20Sopenharmony_ci * Author: Paul Mundt <paul.mundt@nokia.com> 158c2ecf20Sopenharmony_ci * Juha Yrjölä <juha.yrjola@nokia.com> 168c2ecf20Sopenharmony_ci * OMAP Dual-mode timer framework support by Timo Teras 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Some parts based off of TI's 24xx code: 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Copyright (C) 2004-2009 Texas Instruments, Inc. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Roughly modelled after the OMAP1 MPU timer code. 238c2ecf20Sopenharmony_ci * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 268c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 278c2ecf20Sopenharmony_ci * for more details. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#include <linux/clk.h> 308c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "soc.h" 338c2ecf20Sopenharmony_ci#include "common.h" 348c2ecf20Sopenharmony_ci#include "control.h" 358c2ecf20Sopenharmony_ci#include "omap-secure.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define REALTIME_COUNTER_BASE 0x48243200 388c2ecf20Sopenharmony_ci#define INCREMENTER_NUMERATOR_OFFSET 0x10 398c2ecf20Sopenharmony_ci#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 408c2ecf20Sopenharmony_ci#define NUMERATOR_DENUMERATOR_MASK 0xfffff000 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic unsigned long arch_timer_freq; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_civoid set_cntfreq(void) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * The realtime counter also called master counter, is a free-running 518c2ecf20Sopenharmony_ci * counter, which is related to real time. It produces the count used 528c2ecf20Sopenharmony_ci * by the CPU local timer peripherals in the MPU cluster. The timer counts 538c2ecf20Sopenharmony_ci * at a rate of 6.144 MHz. Because the device operates on different clocks 548c2ecf20Sopenharmony_ci * in different power modes, the master counter shifts operation between 558c2ecf20Sopenharmony_ci * clocks, adjusting the increment per clock in hardware accordingly to 568c2ecf20Sopenharmony_ci * maintain a constant count rate. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic void __init realtime_counter_init(void) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci void __iomem *base; 618c2ecf20Sopenharmony_ci static struct clk *sys_clk; 628c2ecf20Sopenharmony_ci unsigned long rate; 638c2ecf20Sopenharmony_ci unsigned int reg; 648c2ecf20Sopenharmony_ci unsigned long long num, den; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci base = ioremap(REALTIME_COUNTER_BASE, SZ_32); 678c2ecf20Sopenharmony_ci if (!base) { 688c2ecf20Sopenharmony_ci pr_err("%s: ioremap failed\n", __func__); 698c2ecf20Sopenharmony_ci return; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci sys_clk = clk_get(NULL, "sys_clkin"); 728c2ecf20Sopenharmony_ci if (IS_ERR(sys_clk)) { 738c2ecf20Sopenharmony_ci pr_err("%s: failed to get system clock handle\n", __func__); 748c2ecf20Sopenharmony_ci iounmap(base); 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci rate = clk_get_rate(sys_clk); 798c2ecf20Sopenharmony_ci clk_put(sys_clk); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (soc_is_dra7xx()) { 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * Errata i856 says the 32.768KHz crystal does not start at 848c2ecf20Sopenharmony_ci * power on, so the CPU falls back to an emulated 32KHz clock 858c2ecf20Sopenharmony_ci * based on sysclk / 610 instead. This causes the master counter 868c2ecf20Sopenharmony_ci * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2 878c2ecf20Sopenharmony_ci * (OR sysclk * 75 / 244) 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * This affects at least the DRA7/AM572x 1.0, 1.1 revisions. 908c2ecf20Sopenharmony_ci * Of course any board built without a populated 32.768KHz 918c2ecf20Sopenharmony_ci * crystal would also need this fix even if the CPU is fixed 928c2ecf20Sopenharmony_ci * later. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * Either case can be detected by using the two speedselect bits 958c2ecf20Sopenharmony_ci * If they are not 0, then the 32.768KHz clock driving the 968c2ecf20Sopenharmony_ci * coarse counter that corrects the fine counter every time it 978c2ecf20Sopenharmony_ci * ticks is actually rate/610 rather than 32.768KHz and we 988c2ecf20Sopenharmony_ci * should compensate to avoid the 570ppm (at 20MHz, much worse 998c2ecf20Sopenharmony_ci * at other rates) too fast system time. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP); 1028c2ecf20Sopenharmony_ci if (reg & DRA7_SPEEDSELECT_MASK) { 1038c2ecf20Sopenharmony_ci num = 75; 1048c2ecf20Sopenharmony_ci den = 244; 1058c2ecf20Sopenharmony_ci goto sysclk1_based; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Numerator/denumerator values refer TRM Realtime Counter section */ 1108c2ecf20Sopenharmony_ci switch (rate) { 1118c2ecf20Sopenharmony_ci case 12000000: 1128c2ecf20Sopenharmony_ci num = 64; 1138c2ecf20Sopenharmony_ci den = 125; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case 13000000: 1168c2ecf20Sopenharmony_ci num = 768; 1178c2ecf20Sopenharmony_ci den = 1625; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case 19200000: 1208c2ecf20Sopenharmony_ci num = 8; 1218c2ecf20Sopenharmony_ci den = 25; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case 20000000: 1248c2ecf20Sopenharmony_ci num = 192; 1258c2ecf20Sopenharmony_ci den = 625; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case 26000000: 1288c2ecf20Sopenharmony_ci num = 384; 1298c2ecf20Sopenharmony_ci den = 1625; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case 27000000: 1328c2ecf20Sopenharmony_ci num = 256; 1338c2ecf20Sopenharmony_ci den = 1125; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci case 38400000: 1368c2ecf20Sopenharmony_ci default: 1378c2ecf20Sopenharmony_ci /* Program it for 38.4 MHz */ 1388c2ecf20Sopenharmony_ci num = 4; 1398c2ecf20Sopenharmony_ci den = 25; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cisysclk1_based: 1448c2ecf20Sopenharmony_ci /* Program numerator and denumerator registers */ 1458c2ecf20Sopenharmony_ci reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) & 1468c2ecf20Sopenharmony_ci NUMERATOR_DENUMERATOR_MASK; 1478c2ecf20Sopenharmony_ci reg |= num; 1488c2ecf20Sopenharmony_ci writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) & 1518c2ecf20Sopenharmony_ci NUMERATOR_DENUMERATOR_MASK; 1528c2ecf20Sopenharmony_ci reg |= den; 1538c2ecf20Sopenharmony_ci writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den); 1568c2ecf20Sopenharmony_ci set_cntfreq(); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci iounmap(base); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid __init omap5_realtime_timer_init(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci omap_clk_init(); 1648c2ecf20Sopenharmony_ci realtime_counter_init(); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci timer_probe(); 1678c2ecf20Sopenharmony_ci} 168