167 lines
4.3 KiB
C
167 lines
4.3 KiB
C
|
/*
|
||
|
* linux/arch/arm/mach-omap2/timer.c
|
||
|
*
|
||
|
* OMAP2 GP timer support.
|
||
|
*
|
||
|
* Copyright (C) 2009 Nokia Corporation
|
||
|
*
|
||
|
* Update to use new clocksource/clockevent layers
|
||
|
* Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
|
||
|
* Copyright (C) 2007 MontaVista Software, Inc.
|
||
|
*
|
||
|
* Original driver:
|
||
|
* Copyright (C) 2005 Nokia Corporation
|
||
|
* Author: Paul Mundt <paul.mundt@nokia.com>
|
||
|
* Juha Yrjölä <juha.yrjola@nokia.com>
|
||
|
* OMAP Dual-mode timer framework support by Timo Teras
|
||
|
*
|
||
|
* Some parts based off of TI's 24xx code:
|
||
|
*
|
||
|
* Copyright (C) 2004-2009 Texas Instruments, Inc.
|
||
|
*
|
||
|
* Roughly modelled after the OMAP1 MPU timer code.
|
||
|
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||
|
*
|
||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||
|
* License. See the file "COPYING" in the main directory of this archive
|
||
|
* for more details.
|
||
|
*/
|
||
|
#include <linux/clk.h>
|
||
|
#include <linux/clocksource.h>
|
||
|
|
||
|
#include "soc.h"
|
||
|
#include "common.h"
|
||
|
#include "control.h"
|
||
|
#include "omap-secure.h"
|
||
|
|
||
|
#define REALTIME_COUNTER_BASE 0x48243200
|
||
|
#define INCREMENTER_NUMERATOR_OFFSET 0x10
|
||
|
#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14
|
||
|
#define NUMERATOR_DENUMERATOR_MASK 0xfffff000
|
||
|
|
||
|
static unsigned long arch_timer_freq;
|
||
|
|
||
|
void set_cntfreq(void)
|
||
|
{
|
||
|
omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The realtime counter also called master counter, is a free-running
|
||
|
* counter, which is related to real time. It produces the count used
|
||
|
* by the CPU local timer peripherals in the MPU cluster. The timer counts
|
||
|
* at a rate of 6.144 MHz. Because the device operates on different clocks
|
||
|
* in different power modes, the master counter shifts operation between
|
||
|
* clocks, adjusting the increment per clock in hardware accordingly to
|
||
|
* maintain a constant count rate.
|
||
|
*/
|
||
|
static void __init realtime_counter_init(void)
|
||
|
{
|
||
|
void __iomem *base;
|
||
|
static struct clk *sys_clk;
|
||
|
unsigned long rate;
|
||
|
unsigned int reg;
|
||
|
unsigned long long num, den;
|
||
|
|
||
|
base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
|
||
|
if (!base) {
|
||
|
pr_err("%s: ioremap failed\n", __func__);
|
||
|
return;
|
||
|
}
|
||
|
sys_clk = clk_get(NULL, "sys_clkin");
|
||
|
if (IS_ERR(sys_clk)) {
|
||
|
pr_err("%s: failed to get system clock handle\n", __func__);
|
||
|
iounmap(base);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rate = clk_get_rate(sys_clk);
|
||
|
|
||
|
if (soc_is_dra7xx()) {
|
||
|
/*
|
||
|
* Errata i856 says the 32.768KHz crystal does not start at
|
||
|
* power on, so the CPU falls back to an emulated 32KHz clock
|
||
|
* based on sysclk / 610 instead. This causes the master counter
|
||
|
* frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2
|
||
|
* (OR sysclk * 75 / 244)
|
||
|
*
|
||
|
* This affects at least the DRA7/AM572x 1.0, 1.1 revisions.
|
||
|
* Of course any board built without a populated 32.768KHz
|
||
|
* crystal would also need this fix even if the CPU is fixed
|
||
|
* later.
|
||
|
*
|
||
|
* Either case can be detected by using the two speedselect bits
|
||
|
* If they are not 0, then the 32.768KHz clock driving the
|
||
|
* coarse counter that corrects the fine counter every time it
|
||
|
* ticks is actually rate/610 rather than 32.768KHz and we
|
||
|
* should compensate to avoid the 570ppm (at 20MHz, much worse
|
||
|
* at other rates) too fast system time.
|
||
|
*/
|
||
|
reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP);
|
||
|
if (reg & DRA7_SPEEDSELECT_MASK) {
|
||
|
num = 75;
|
||
|
den = 244;
|
||
|
goto sysclk1_based;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Numerator/denumerator values refer TRM Realtime Counter section */
|
||
|
switch (rate) {
|
||
|
case 12000000:
|
||
|
num = 64;
|
||
|
den = 125;
|
||
|
break;
|
||
|
case 13000000:
|
||
|
num = 768;
|
||
|
den = 1625;
|
||
|
break;
|
||
|
case 19200000:
|
||
|
num = 8;
|
||
|
den = 25;
|
||
|
break;
|
||
|
case 20000000:
|
||
|
num = 192;
|
||
|
den = 625;
|
||
|
break;
|
||
|
case 26000000:
|
||
|
num = 384;
|
||
|
den = 1625;
|
||
|
break;
|
||
|
case 27000000:
|
||
|
num = 256;
|
||
|
den = 1125;
|
||
|
break;
|
||
|
case 38400000:
|
||
|
default:
|
||
|
/* Program it for 38.4 MHz */
|
||
|
num = 4;
|
||
|
den = 25;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sysclk1_based:
|
||
|
/* Program numerator and denumerator registers */
|
||
|
reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) &
|
||
|
NUMERATOR_DENUMERATOR_MASK;
|
||
|
reg |= num;
|
||
|
writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET);
|
||
|
|
||
|
reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) &
|
||
|
NUMERATOR_DENUMERATOR_MASK;
|
||
|
reg |= den;
|
||
|
writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
|
||
|
|
||
|
arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den);
|
||
|
set_cntfreq();
|
||
|
|
||
|
iounmap(base);
|
||
|
}
|
||
|
|
||
|
void __init omap5_realtime_timer_init(void)
|
||
|
{
|
||
|
omap_clk_init();
|
||
|
realtime_counter_init();
|
||
|
|
||
|
timer_probe();
|
||
|
}
|