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

timer.c (7814B)


      1/*
      2 * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu>
      3 * Copyright (C) 2012-2013 Xilinx, Inc.
      4 * Copyright (C) 2007-2009 PetaLogix
      5 * Copyright (C) 2006 Atmark Techno, Inc.
      6 *
      7 * This file is subject to the terms and conditions of the GNU General Public
      8 * License. See the file "COPYING" in the main directory of this archive
      9 * for more details.
     10 */
     11
     12#include <linux/interrupt.h>
     13#include <linux/delay.h>
     14#include <linux/sched.h>
     15#include <linux/sched/clock.h>
     16#include <linux/sched_clock.h>
     17#include <linux/clk.h>
     18#include <linux/clockchips.h>
     19#include <linux/of_address.h>
     20#include <linux/of_irq.h>
     21#include <linux/timecounter.h>
     22#include <asm/cpuinfo.h>
     23
     24static void __iomem *timer_baseaddr;
     25
     26static unsigned int freq_div_hz;
     27static unsigned int timer_clock_freq;
     28
     29#define TCSR0	(0x00)
     30#define TLR0	(0x04)
     31#define TCR0	(0x08)
     32#define TCSR1	(0x10)
     33#define TLR1	(0x14)
     34#define TCR1	(0x18)
     35
     36#define TCSR_MDT	(1<<0)
     37#define TCSR_UDT	(1<<1)
     38#define TCSR_GENT	(1<<2)
     39#define TCSR_CAPT	(1<<3)
     40#define TCSR_ARHT	(1<<4)
     41#define TCSR_LOAD	(1<<5)
     42#define TCSR_ENIT	(1<<6)
     43#define TCSR_ENT	(1<<7)
     44#define TCSR_TINT	(1<<8)
     45#define TCSR_PWMA	(1<<9)
     46#define TCSR_ENALL	(1<<10)
     47
     48static unsigned int (*read_fn)(void __iomem *);
     49static void (*write_fn)(u32, void __iomem *);
     50
     51static void timer_write32(u32 val, void __iomem *addr)
     52{
     53	iowrite32(val, addr);
     54}
     55
     56static unsigned int timer_read32(void __iomem *addr)
     57{
     58	return ioread32(addr);
     59}
     60
     61static void timer_write32_be(u32 val, void __iomem *addr)
     62{
     63	iowrite32be(val, addr);
     64}
     65
     66static unsigned int timer_read32_be(void __iomem *addr)
     67{
     68	return ioread32be(addr);
     69}
     70
     71static inline void xilinx_timer0_stop(void)
     72{
     73	write_fn(read_fn(timer_baseaddr + TCSR0) & ~TCSR_ENT,
     74		 timer_baseaddr + TCSR0);
     75}
     76
     77static inline void xilinx_timer0_start_periodic(unsigned long load_val)
     78{
     79	if (!load_val)
     80		load_val = 1;
     81	/* loading value to timer reg */
     82	write_fn(load_val, timer_baseaddr + TLR0);
     83
     84	/* load the initial value */
     85	write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
     86
     87	/* see timer data sheet for detail
     88	 * !ENALL - don't enable 'em all
     89	 * !PWMA - disable pwm
     90	 * TINT - clear interrupt status
     91	 * ENT- enable timer itself
     92	 * ENIT - enable interrupt
     93	 * !LOAD - clear the bit to let go
     94	 * ARHT - auto reload
     95	 * !CAPT - no external trigger
     96	 * !GENT - no external signal
     97	 * UDT - set the timer as down counter
     98	 * !MDT0 - generate mode
     99	 */
    100	write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
    101		 timer_baseaddr + TCSR0);
    102}
    103
    104static inline void xilinx_timer0_start_oneshot(unsigned long load_val)
    105{
    106	if (!load_val)
    107		load_val = 1;
    108	/* loading value to timer reg */
    109	write_fn(load_val, timer_baseaddr + TLR0);
    110
    111	/* load the initial value */
    112	write_fn(TCSR_LOAD, timer_baseaddr + TCSR0);
    113
    114	write_fn(TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT,
    115		 timer_baseaddr + TCSR0);
    116}
    117
    118static int xilinx_timer_set_next_event(unsigned long delta,
    119					struct clock_event_device *dev)
    120{
    121	pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
    122	xilinx_timer0_start_oneshot(delta);
    123	return 0;
    124}
    125
    126static int xilinx_timer_shutdown(struct clock_event_device *evt)
    127{
    128	pr_info("%s\n", __func__);
    129	xilinx_timer0_stop();
    130	return 0;
    131}
    132
    133static int xilinx_timer_set_periodic(struct clock_event_device *evt)
    134{
    135	pr_info("%s\n", __func__);
    136	xilinx_timer0_start_periodic(freq_div_hz);
    137	return 0;
    138}
    139
    140static struct clock_event_device clockevent_xilinx_timer = {
    141	.name			= "xilinx_clockevent",
    142	.features		= CLOCK_EVT_FEAT_ONESHOT |
    143				  CLOCK_EVT_FEAT_PERIODIC,
    144	.shift			= 8,
    145	.rating			= 300,
    146	.set_next_event		= xilinx_timer_set_next_event,
    147	.set_state_shutdown	= xilinx_timer_shutdown,
    148	.set_state_periodic	= xilinx_timer_set_periodic,
    149};
    150
    151static inline void timer_ack(void)
    152{
    153	write_fn(read_fn(timer_baseaddr + TCSR0), timer_baseaddr + TCSR0);
    154}
    155
    156static irqreturn_t timer_interrupt(int irq, void *dev_id)
    157{
    158	struct clock_event_device *evt = &clockevent_xilinx_timer;
    159	timer_ack();
    160	evt->event_handler(evt);
    161	return IRQ_HANDLED;
    162}
    163
    164static __init int xilinx_clockevent_init(void)
    165{
    166	clockevent_xilinx_timer.mult =
    167		div_sc(timer_clock_freq, NSEC_PER_SEC,
    168				clockevent_xilinx_timer.shift);
    169	clockevent_xilinx_timer.max_delta_ns =
    170		clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
    171	clockevent_xilinx_timer.max_delta_ticks = (u32)~0;
    172	clockevent_xilinx_timer.min_delta_ns =
    173		clockevent_delta2ns(1, &clockevent_xilinx_timer);
    174	clockevent_xilinx_timer.min_delta_ticks = 1;
    175	clockevent_xilinx_timer.cpumask = cpumask_of(0);
    176	clockevents_register_device(&clockevent_xilinx_timer);
    177
    178	return 0;
    179}
    180
    181static u64 xilinx_clock_read(void)
    182{
    183	return read_fn(timer_baseaddr + TCR1);
    184}
    185
    186static u64 xilinx_read(struct clocksource *cs)
    187{
    188	/* reading actual value of timer 1 */
    189	return (u64)xilinx_clock_read();
    190}
    191
    192static struct timecounter xilinx_tc = {
    193	.cc = NULL,
    194};
    195
    196static u64 xilinx_cc_read(const struct cyclecounter *cc)
    197{
    198	return xilinx_read(NULL);
    199}
    200
    201static struct cyclecounter xilinx_cc = {
    202	.read = xilinx_cc_read,
    203	.mask = CLOCKSOURCE_MASK(32),
    204	.shift = 8,
    205};
    206
    207static int __init init_xilinx_timecounter(void)
    208{
    209	xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
    210				xilinx_cc.shift);
    211
    212	timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
    213
    214	return 0;
    215}
    216
    217static struct clocksource clocksource_microblaze = {
    218	.name		= "xilinx_clocksource",
    219	.rating		= 300,
    220	.read		= xilinx_read,
    221	.mask		= CLOCKSOURCE_MASK(32),
    222	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
    223};
    224
    225static int __init xilinx_clocksource_init(void)
    226{
    227	int ret;
    228
    229	ret = clocksource_register_hz(&clocksource_microblaze,
    230				      timer_clock_freq);
    231	if (ret) {
    232		pr_err("failed to register clocksource");
    233		return ret;
    234	}
    235
    236	/* stop timer1 */
    237	write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT,
    238		 timer_baseaddr + TCSR1);
    239	/* start timer1 - up counting without interrupt */
    240	write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1);
    241
    242	/* register timecounter - for ftrace support */
    243	return init_xilinx_timecounter();
    244}
    245
    246static int __init xilinx_timer_init(struct device_node *timer)
    247{
    248	struct clk *clk;
    249	static int initialized;
    250	u32 irq;
    251	u32 timer_num = 1;
    252	int ret;
    253
    254	/* If this property is present, the device is a PWM and not a timer */
    255	if (of_property_read_bool(timer, "#pwm-cells"))
    256		return 0;
    257
    258	if (initialized)
    259		return -EINVAL;
    260
    261	initialized = 1;
    262
    263	timer_baseaddr = of_iomap(timer, 0);
    264	if (!timer_baseaddr) {
    265		pr_err("ERROR: invalid timer base address\n");
    266		return -ENXIO;
    267	}
    268
    269	write_fn = timer_write32;
    270	read_fn = timer_read32;
    271
    272	write_fn(TCSR_MDT, timer_baseaddr + TCSR0);
    273	if (!(read_fn(timer_baseaddr + TCSR0) & TCSR_MDT)) {
    274		write_fn = timer_write32_be;
    275		read_fn = timer_read32_be;
    276	}
    277
    278	irq = irq_of_parse_and_map(timer, 0);
    279	if (irq <= 0) {
    280		pr_err("Failed to parse and map irq");
    281		return -EINVAL;
    282	}
    283
    284	of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
    285	if (timer_num) {
    286		pr_err("Please enable two timers in HW\n");
    287		return -EINVAL;
    288	}
    289
    290	pr_info("%pOF: irq=%d\n", timer, irq);
    291
    292	clk = of_clk_get(timer, 0);
    293	if (IS_ERR(clk)) {
    294		pr_err("ERROR: timer CCF input clock not found\n");
    295		/* If there is clock-frequency property than use it */
    296		of_property_read_u32(timer, "clock-frequency",
    297				    &timer_clock_freq);
    298	} else {
    299		timer_clock_freq = clk_get_rate(clk);
    300	}
    301
    302	if (!timer_clock_freq) {
    303		pr_err("ERROR: Using CPU clock frequency\n");
    304		timer_clock_freq = cpuinfo.cpu_clock_freq;
    305	}
    306
    307	freq_div_hz = timer_clock_freq / HZ;
    308
    309	ret = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer",
    310			  &clockevent_xilinx_timer);
    311	if (ret) {
    312		pr_err("Failed to setup IRQ");
    313		return ret;
    314	}
    315
    316	ret = xilinx_clocksource_init();
    317	if (ret)
    318		return ret;
    319
    320	ret = xilinx_clockevent_init();
    321	if (ret)
    322		return ret;
    323
    324	sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);
    325
    326	return 0;
    327}
    328
    329TIMER_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
    330		       xilinx_timer_init);