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