linux/arch/arm/mach-omap2/timer.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-omap2/timer.c
   3 *
   4 * OMAP2 GP timer support.
   5 *
   6 * Copyright (C) 2009 Nokia Corporation
   7 *
   8 * Update to use new clocksource/clockevent layers
   9 * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
  10 * Copyright (C) 2007 MontaVista Software, Inc.
  11 *
  12 * Original driver:
  13 * Copyright (C) 2005 Nokia Corporation
  14 * Author: Paul Mundt <paul.mundt@nokia.com>
  15 *         Juha Yrjölä <juha.yrjola@nokia.com>
  16 * OMAP Dual-mode timer framework support by Timo Teras
  17 *
  18 * Some parts based off of TI's 24xx code:
  19 *
  20 * Copyright (C) 2004-2009 Texas Instruments, Inc.
  21 *
  22 * Roughly modelled after the OMAP1 MPU timer code.
  23 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
  24 *
  25 * This file is subject to the terms and conditions of the GNU General Public
  26 * License. See the file "COPYING" in the main directory of this archive
  27 * for more details.
  28 */
  29#include <linux/clk.h>
  30#include <linux/clocksource.h>
  31
  32#include "soc.h"
  33#include "common.h"
  34#include "control.h"
  35#include "omap-secure.h"
  36
  37#define REALTIME_COUNTER_BASE                           0x48243200
  38#define INCREMENTER_NUMERATOR_OFFSET                    0x10
  39#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET           0x14
  40#define NUMERATOR_DENUMERATOR_MASK                      0xfffff000
  41
  42static unsigned long arch_timer_freq;
  43
  44void set_cntfreq(void)
  45{
  46        omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq);
  47}
  48
  49/*
  50 * The realtime counter also called master counter, is a free-running
  51 * counter, which is related to real time. It produces the count used
  52 * by the CPU local timer peripherals in the MPU cluster. The timer counts
  53 * at a rate of 6.144 MHz. Because the device operates on different clocks
  54 * in different power modes, the master counter shifts operation between
  55 * clocks, adjusting the increment per clock in hardware accordingly to
  56 * maintain a constant count rate.
  57 */
  58static void __init realtime_counter_init(void)
  59{
  60        void __iomem *base;
  61        static struct clk *sys_clk;
  62        unsigned long rate;
  63        unsigned int reg;
  64        unsigned long long num, den;
  65
  66        base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
  67        if (!base) {
  68                pr_err("%s: ioremap failed\n", __func__);
  69                return;
  70        }
  71        sys_clk = clk_get(NULL, "sys_clkin");
  72        if (IS_ERR(sys_clk)) {
  73                pr_err("%s: failed to get system clock handle\n", __func__);
  74                iounmap(base);
  75                return;
  76        }
  77
  78        rate = clk_get_rate(sys_clk);
  79
  80        if (soc_is_dra7xx()) {
  81                /*
  82                 * Errata i856 says the 32.768KHz crystal does not start at
  83                 * power on, so the CPU falls back to an emulated 32KHz clock
  84                 * based on sysclk / 610 instead. This causes the master counter
  85                 * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2
  86                 * (OR sysclk * 75 / 244)
  87                 *
  88                 * This affects at least the DRA7/AM572x 1.0, 1.1 revisions.
  89                 * Of course any board built without a populated 32.768KHz
  90                 * crystal would also need this fix even if the CPU is fixed
  91                 * later.
  92                 *
  93                 * Either case can be detected by using the two speedselect bits
  94                 * If they are not 0, then the 32.768KHz clock driving the
  95                 * coarse counter that corrects the fine counter every time it
  96                 * ticks is actually rate/610 rather than 32.768KHz and we
  97                 * should compensate to avoid the 570ppm (at 20MHz, much worse
  98                 * at other rates) too fast system time.
  99                 */
 100                reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP);
 101                if (reg & DRA7_SPEEDSELECT_MASK) {
 102                        num = 75;
 103                        den = 244;
 104                        goto sysclk1_based;
 105                }
 106        }
 107
 108        /* Numerator/denumerator values refer TRM Realtime Counter section */
 109        switch (rate) {
 110        case 12000000:
 111                num = 64;
 112                den = 125;
 113                break;
 114        case 13000000:
 115                num = 768;
 116                den = 1625;
 117                break;
 118        case 19200000:
 119                num = 8;
 120                den = 25;
 121                break;
 122        case 20000000:
 123                num = 192;
 124                den = 625;
 125                break;
 126        case 26000000:
 127                num = 384;
 128                den = 1625;
 129                break;
 130        case 27000000:
 131                num = 256;
 132                den = 1125;
 133                break;
 134        case 38400000:
 135        default:
 136                /* Program it for 38.4 MHz */
 137                num = 4;
 138                den = 25;
 139                break;
 140        }
 141
 142sysclk1_based:
 143        /* Program numerator and denumerator registers */
 144        reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) &
 145                        NUMERATOR_DENUMERATOR_MASK;
 146        reg |= num;
 147        writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET);
 148
 149        reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) &
 150                        NUMERATOR_DENUMERATOR_MASK;
 151        reg |= den;
 152        writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
 153
 154        arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den);
 155        set_cntfreq();
 156
 157        iounmap(base);
 158}
 159
 160void __init omap5_realtime_timer_init(void)
 161{
 162        omap_clk_init();
 163        realtime_counter_init();
 164
 165        timer_probe();
 166}
 167