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 (3958B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * arch/arm/plat-iop/time.c
      4 *
      5 * Timer code for IOP32x and IOP33x based systems
      6 *
      7 * Author: Deepak Saxena <dsaxena@mvista.com>
      8 *
      9 * Copyright 2002-2003 MontaVista Software Inc.
     10 */
     11
     12#include <linux/kernel.h>
     13#include <linux/interrupt.h>
     14#include <linux/time.h>
     15#include <linux/init.h>
     16#include <linux/timex.h>
     17#include <linux/io.h>
     18#include <linux/clocksource.h>
     19#include <linux/clockchips.h>
     20#include <linux/export.h>
     21#include <linux/sched_clock.h>
     22#include <asm/irq.h>
     23#include <linux/uaccess.h>
     24#include <asm/mach/irq.h>
     25#include <asm/mach/time.h>
     26
     27#include "hardware.h"
     28#include "irqs.h"
     29
     30/*
     31 * Minimum clocksource/clockevent timer range in seconds
     32 */
     33#define IOP_MIN_RANGE 4
     34
     35/*
     36 * IOP clocksource (free-running timer 1).
     37 */
     38static u64 notrace iop_clocksource_read(struct clocksource *unused)
     39{
     40	return 0xffffffffu - read_tcr1();
     41}
     42
     43static struct clocksource iop_clocksource = {
     44	.name 		= "iop_timer1",
     45	.rating		= 300,
     46	.read		= iop_clocksource_read,
     47	.mask		= CLOCKSOURCE_MASK(32),
     48	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
     49};
     50
     51/*
     52 * IOP sched_clock() implementation via its clocksource.
     53 */
     54static u64 notrace iop_read_sched_clock(void)
     55{
     56	return 0xffffffffu - read_tcr1();
     57}
     58
     59/*
     60 * IOP clockevents (interrupting timer 0).
     61 */
     62static int iop_set_next_event(unsigned long delta,
     63			      struct clock_event_device *unused)
     64{
     65	u32 tmr = IOP_TMR_PRIVILEGED | IOP_TMR_RATIO_1_1;
     66
     67	BUG_ON(delta == 0);
     68	write_tmr0(tmr & ~(IOP_TMR_EN | IOP_TMR_RELOAD));
     69	write_tcr0(delta);
     70	write_tmr0((tmr & ~IOP_TMR_RELOAD) | IOP_TMR_EN);
     71
     72	return 0;
     73}
     74
     75static unsigned long ticks_per_jiffy;
     76
     77static int iop_set_periodic(struct clock_event_device *evt)
     78{
     79	u32 tmr = read_tmr0();
     80
     81	write_tmr0(tmr & ~IOP_TMR_EN);
     82	write_tcr0(ticks_per_jiffy - 1);
     83	write_trr0(ticks_per_jiffy - 1);
     84	tmr |= (IOP_TMR_RELOAD | IOP_TMR_EN);
     85
     86	write_tmr0(tmr);
     87	return 0;
     88}
     89
     90static int iop_set_oneshot(struct clock_event_device *evt)
     91{
     92	u32 tmr = read_tmr0();
     93
     94	/* ->set_next_event sets period and enables timer */
     95	tmr &= ~(IOP_TMR_RELOAD | IOP_TMR_EN);
     96	write_tmr0(tmr);
     97	return 0;
     98}
     99
    100static int iop_shutdown(struct clock_event_device *evt)
    101{
    102	u32 tmr = read_tmr0();
    103
    104	tmr &= ~IOP_TMR_EN;
    105	write_tmr0(tmr);
    106	return 0;
    107}
    108
    109static int iop_resume(struct clock_event_device *evt)
    110{
    111	u32 tmr = read_tmr0();
    112
    113	tmr |= IOP_TMR_EN;
    114	write_tmr0(tmr);
    115	return 0;
    116}
    117
    118static struct clock_event_device iop_clockevent = {
    119	.name			= "iop_timer0",
    120	.features		= CLOCK_EVT_FEAT_PERIODIC |
    121				  CLOCK_EVT_FEAT_ONESHOT,
    122	.rating			= 300,
    123	.set_next_event		= iop_set_next_event,
    124	.set_state_shutdown	= iop_shutdown,
    125	.set_state_periodic	= iop_set_periodic,
    126	.tick_resume		= iop_resume,
    127	.set_state_oneshot	= iop_set_oneshot,
    128};
    129
    130static irqreturn_t
    131iop_timer_interrupt(int irq, void *dev_id)
    132{
    133	struct clock_event_device *evt = dev_id;
    134
    135	write_tisr(1);
    136	evt->event_handler(evt);
    137	return IRQ_HANDLED;
    138}
    139
    140static unsigned long iop_tick_rate;
    141unsigned long get_iop_tick_rate(void)
    142{
    143	return iop_tick_rate;
    144}
    145EXPORT_SYMBOL(get_iop_tick_rate);
    146
    147void __init iop_init_time(unsigned long tick_rate)
    148{
    149	u32 timer_ctl;
    150	int irq = IRQ_IOP32X_TIMER0;
    151
    152	sched_clock_register(iop_read_sched_clock, 32, tick_rate);
    153
    154	ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
    155	iop_tick_rate = tick_rate;
    156
    157	timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
    158			IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
    159
    160	/*
    161	 * Set up interrupting clockevent timer 0.
    162	 */
    163	write_tmr0(timer_ctl & ~IOP_TMR_EN);
    164	write_tisr(1);
    165	if (request_irq(irq, iop_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
    166			"IOP Timer Tick", &iop_clockevent))
    167		pr_err("Failed to request irq() %d (IOP Timer Tick)\n", irq);
    168	iop_clockevent.cpumask = cpumask_of(0);
    169	clockevents_config_and_register(&iop_clockevent, tick_rate,
    170					0xf, 0xfffffffe);
    171
    172	/*
    173	 * Set up free-running clocksource timer 1.
    174	 */
    175	write_trr1(0xffffffff);
    176	write_tcr1(0xffffffff);
    177	write_tmr1(timer_ctl);
    178	clocksource_register_hz(&iop_clocksource, tick_rate);
    179}