cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

time.c (6616B)


      1/*
      2 * linux/arch/arm/mach-omap1/time.c
      3 *
      4 * OMAP Timers
      5 *
      6 * Copyright (C) 2004 Nokia Corporation
      7 * Partial timer rewrite and additional dynamic tick timer support by
      8 * Tony Lindgen <tony@atomide.com> and
      9 * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
     10 *
     11 * MPU timer code based on the older MPU timer code for OMAP
     12 * Copyright (C) 2000 RidgeRun, Inc.
     13 * Author: Greg Lonnon <glonnon@ridgerun.com>
     14 *
     15 * This program is free software; you can redistribute it and/or modify it
     16 * under the terms of the GNU General Public License as published by the
     17 * Free Software Foundation; either version 2 of the License, or (at your
     18 * option) any later version.
     19 *
     20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
     23 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
     26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 *
     31 * You should have received a copy of the  GNU General Public License along
     32 * with this program; if not, write  to the Free Software Foundation, Inc.,
     33 * 675 Mass Ave, Cambridge, MA 02139, USA.
     34 */
     35
     36#include <linux/kernel.h>
     37#include <linux/init.h>
     38#include <linux/delay.h>
     39#include <linux/interrupt.h>
     40#include <linux/spinlock.h>
     41#include <linux/clk.h>
     42#include <linux/err.h>
     43#include <linux/clocksource.h>
     44#include <linux/clockchips.h>
     45#include <linux/io.h>
     46#include <linux/sched_clock.h>
     47
     48#include <asm/irq.h>
     49
     50#include <asm/mach/irq.h>
     51#include <asm/mach/time.h>
     52
     53#include "hardware.h"
     54#include "mux.h"
     55#include "iomap.h"
     56#include "common.h"
     57#include "clock.h"
     58
     59#ifdef CONFIG_OMAP_MPU_TIMER
     60
     61#define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
     62#define OMAP_MPU_TIMER_OFFSET		0x100
     63
     64typedef struct {
     65	u32 cntl;			/* CNTL_TIMER, R/W */
     66	u32 load_tim;			/* LOAD_TIM,   W */
     67	u32 read_tim;			/* READ_TIM,   R */
     68} omap_mpu_timer_regs_t;
     69
     70#define omap_mpu_timer_base(n)							\
     71((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE +	\
     72				 (n)*OMAP_MPU_TIMER_OFFSET))
     73
     74static inline unsigned long notrace omap_mpu_timer_read(int nr)
     75{
     76	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
     77	return readl(&timer->read_tim);
     78}
     79
     80static inline void omap_mpu_set_autoreset(int nr)
     81{
     82	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
     83
     84	writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
     85}
     86
     87static inline void omap_mpu_remove_autoreset(int nr)
     88{
     89	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
     90
     91	writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
     92}
     93
     94static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
     95					int autoreset)
     96{
     97	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
     98	unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;
     99
    100	if (autoreset)
    101		timerflags |= MPU_TIMER_AR;
    102
    103	writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
    104	udelay(1);
    105	writel(load_val, &timer->load_tim);
    106        udelay(1);
    107	writel(timerflags, &timer->cntl);
    108}
    109
    110static inline void omap_mpu_timer_stop(int nr)
    111{
    112	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
    113
    114	writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
    115}
    116
    117/*
    118 * ---------------------------------------------------------------------------
    119 * MPU timer 1 ... count down to zero, interrupt, reload
    120 * ---------------------------------------------------------------------------
    121 */
    122static int omap_mpu_set_next_event(unsigned long cycles,
    123				   struct clock_event_device *evt)
    124{
    125	omap_mpu_timer_start(0, cycles, 0);
    126	return 0;
    127}
    128
    129static int omap_mpu_set_oneshot(struct clock_event_device *evt)
    130{
    131	omap_mpu_timer_stop(0);
    132	omap_mpu_remove_autoreset(0);
    133	return 0;
    134}
    135
    136static int omap_mpu_set_periodic(struct clock_event_device *evt)
    137{
    138	omap_mpu_set_autoreset(0);
    139	return 0;
    140}
    141
    142static struct clock_event_device clockevent_mpu_timer1 = {
    143	.name			= "mpu_timer1",
    144	.features		= CLOCK_EVT_FEAT_PERIODIC |
    145				  CLOCK_EVT_FEAT_ONESHOT,
    146	.set_next_event		= omap_mpu_set_next_event,
    147	.set_state_periodic	= omap_mpu_set_periodic,
    148	.set_state_oneshot	= omap_mpu_set_oneshot,
    149};
    150
    151static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
    152{
    153	struct clock_event_device *evt = &clockevent_mpu_timer1;
    154
    155	evt->event_handler(evt);
    156
    157	return IRQ_HANDLED;
    158}
    159
    160static __init void omap_init_mpu_timer(unsigned long rate)
    161{
    162	if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
    163			IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
    164		pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
    165	omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
    166
    167	clockevent_mpu_timer1.cpumask = cpumask_of(0);
    168	clockevents_config_and_register(&clockevent_mpu_timer1, rate,
    169					1, -1);
    170}
    171
    172
    173/*
    174 * ---------------------------------------------------------------------------
    175 * MPU timer 2 ... free running 32-bit clock source and scheduler clock
    176 * ---------------------------------------------------------------------------
    177 */
    178
    179static u64 notrace omap_mpu_read_sched_clock(void)
    180{
    181	return ~omap_mpu_timer_read(1);
    182}
    183
    184static void __init omap_init_clocksource(unsigned long rate)
    185{
    186	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
    187	static char err[] __initdata = KERN_ERR
    188			"%s: can't register clocksource!\n";
    189
    190	omap_mpu_timer_start(1, ~0, 1);
    191	sched_clock_register(omap_mpu_read_sched_clock, 32, rate);
    192
    193	if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
    194			300, 32, clocksource_mmio_readl_down))
    195		printk(err, "mpu_timer2");
    196}
    197
    198static void __init omap_mpu_timer_init(void)
    199{
    200	struct clk	*ck_ref = clk_get(NULL, "ck_ref");
    201	unsigned long	rate;
    202
    203	BUG_ON(IS_ERR(ck_ref));
    204
    205	rate = clk_get_rate(ck_ref);
    206	clk_put(ck_ref);
    207
    208	/* PTV = 0 */
    209	rate /= 2;
    210
    211	omap_init_mpu_timer(rate);
    212	omap_init_clocksource(rate);
    213}
    214
    215#else
    216static inline void omap_mpu_timer_init(void)
    217{
    218	pr_err("Bogus timer, should not happen\n");
    219}
    220#endif	/* CONFIG_OMAP_MPU_TIMER */
    221
    222/*
    223 * ---------------------------------------------------------------------------
    224 * Timer initialization
    225 * ---------------------------------------------------------------------------
    226 */
    227void __init omap1_timer_init(void)
    228{
    229	omap1_clk_init();
    230	omap1_mux_init();
    231
    232	if (omap_32k_timer_init() != 0)
    233		omap_mpu_timer_init();
    234}