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-rda.c (4749B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * RDA8810PL SoC timer driver
      4 *
      5 * Copyright RDA Microelectronics Company Limited
      6 * Copyright (c) 2017 Andreas Färber
      7 * Copyright (c) 2018 Manivannan Sadhasivam
      8 *
      9 * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
     10 * Each timer provides optional interrupt support. In this driver, OSTIMER is
     11 * used for clockevents and HWTIMER is used for clocksource.
     12 */
     13
     14#include <linux/init.h>
     15#include <linux/interrupt.h>
     16
     17#include "timer-of.h"
     18
     19#define RDA_OSTIMER_LOADVAL_L	0x000
     20#define RDA_OSTIMER_CTRL	0x004
     21#define RDA_HWTIMER_LOCKVAL_L	0x024
     22#define RDA_HWTIMER_LOCKVAL_H	0x028
     23#define RDA_TIMER_IRQ_MASK_SET	0x02c
     24#define RDA_TIMER_IRQ_MASK_CLR	0x030
     25#define RDA_TIMER_IRQ_CLR	0x034
     26
     27#define RDA_OSTIMER_CTRL_ENABLE		BIT(24)
     28#define RDA_OSTIMER_CTRL_REPEAT		BIT(28)
     29#define RDA_OSTIMER_CTRL_LOAD		BIT(30)
     30
     31#define RDA_TIMER_IRQ_MASK_OSTIMER	BIT(0)
     32
     33#define RDA_TIMER_IRQ_CLR_OSTIMER	BIT(0)
     34
     35static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
     36{
     37	u32 ctrl, load_l;
     38
     39	load_l = (u32)cycles;
     40	ctrl = ((cycles >> 32) & 0xffffff);
     41	ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
     42	if (periodic)
     43		ctrl |= RDA_OSTIMER_CTRL_REPEAT;
     44
     45	/* Enable ostimer interrupt first */
     46	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
     47		       base + RDA_TIMER_IRQ_MASK_SET);
     48
     49	/* Write low 32 bits first, high 24 bits are with ctrl */
     50	writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
     51	writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
     52
     53	return 0;
     54}
     55
     56static int rda_ostimer_stop(void __iomem *base)
     57{
     58	/* Disable ostimer interrupt first */
     59	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
     60		       base + RDA_TIMER_IRQ_MASK_CLR);
     61
     62	writel_relaxed(0, base + RDA_OSTIMER_CTRL);
     63
     64	return 0;
     65}
     66
     67static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
     68{
     69	struct timer_of *to = to_timer_of(evt);
     70
     71	rda_ostimer_stop(timer_of_base(to));
     72
     73	return 0;
     74}
     75
     76static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
     77{
     78	struct timer_of *to = to_timer_of(evt);
     79
     80	rda_ostimer_stop(timer_of_base(to));
     81
     82	return 0;
     83}
     84
     85static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
     86{
     87	struct timer_of *to = to_timer_of(evt);
     88	unsigned long cycles_per_jiffy;
     89
     90	rda_ostimer_stop(timer_of_base(to));
     91
     92	cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
     93			     evt->mult) >> evt->shift;
     94	rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
     95
     96	return 0;
     97}
     98
     99static int rda_ostimer_tick_resume(struct clock_event_device *evt)
    100{
    101	return 0;
    102}
    103
    104static int rda_ostimer_set_next_event(unsigned long evt,
    105				      struct clock_event_device *ev)
    106{
    107	struct timer_of *to = to_timer_of(ev);
    108
    109	rda_ostimer_start(timer_of_base(to), false, evt);
    110
    111	return 0;
    112}
    113
    114static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
    115{
    116	struct clock_event_device *evt = dev_id;
    117	struct timer_of *to = to_timer_of(evt);
    118
    119	/* clear timer int */
    120	writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
    121		       timer_of_base(to) + RDA_TIMER_IRQ_CLR);
    122
    123	if (evt->event_handler)
    124		evt->event_handler(evt);
    125
    126	return IRQ_HANDLED;
    127}
    128
    129static struct timer_of rda_ostimer_of = {
    130	.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
    131
    132	.clkevt = {
    133		.name = "rda-ostimer",
    134		.rating = 250,
    135		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
    136			    CLOCK_EVT_FEAT_DYNIRQ,
    137		.set_state_shutdown = rda_ostimer_set_state_shutdown,
    138		.set_state_oneshot = rda_ostimer_set_state_oneshot,
    139		.set_state_periodic = rda_ostimer_set_state_periodic,
    140		.tick_resume = rda_ostimer_tick_resume,
    141		.set_next_event	= rda_ostimer_set_next_event,
    142	},
    143
    144	.of_base = {
    145		.name = "rda-timer",
    146		.index = 0,
    147	},
    148
    149	.of_irq = {
    150		.name = "ostimer",
    151		.handler = rda_ostimer_interrupt,
    152		.flags = IRQF_TIMER,
    153	},
    154};
    155
    156static u64 rda_hwtimer_read(struct clocksource *cs)
    157{
    158	void __iomem *base = timer_of_base(&rda_ostimer_of);
    159	u32 lo, hi;
    160
    161	/* Always read low 32 bits first */
    162	do {
    163		lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
    164		hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
    165	} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
    166
    167	return ((u64)hi << 32) | lo;
    168}
    169
    170static struct clocksource rda_hwtimer_clocksource = {
    171	.name           = "rda-timer",
    172	.rating         = 400,
    173	.read           = rda_hwtimer_read,
    174	.mask           = CLOCKSOURCE_MASK(64),
    175	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
    176};
    177
    178static int __init rda_timer_init(struct device_node *np)
    179{
    180	unsigned long rate = 2000000;
    181	int ret;
    182
    183	ret = timer_of_init(np, &rda_ostimer_of);
    184	if (ret)
    185		return ret;
    186
    187	clocksource_register_hz(&rda_hwtimer_clocksource, rate);
    188
    189	clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
    190					0x2, UINT_MAX);
    191
    192	return 0;
    193}
    194
    195TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);