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

dw_apb_timer.c (12004B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * (C) Copyright 2009 Intel Corporation
      4 * Author: Jacob Pan (jacob.jun.pan@intel.com)
      5 *
      6 * Shared with ARM platforms, Jamie Iles, Picochip 2011
      7 *
      8 * Support for the Synopsys DesignWare APB Timers.
      9 */
     10#include <linux/dw_apb_timer.h>
     11#include <linux/delay.h>
     12#include <linux/kernel.h>
     13#include <linux/interrupt.h>
     14#include <linux/irq.h>
     15#include <linux/io.h>
     16#include <linux/slab.h>
     17
     18#define APBT_MIN_PERIOD			4
     19#define APBT_MIN_DELTA_USEC		200
     20
     21#define APBTMR_N_LOAD_COUNT		0x00
     22#define APBTMR_N_CURRENT_VALUE		0x04
     23#define APBTMR_N_CONTROL		0x08
     24#define APBTMR_N_EOI			0x0c
     25#define APBTMR_N_INT_STATUS		0x10
     26
     27#define APBTMRS_INT_STATUS		0xa0
     28#define APBTMRS_EOI			0xa4
     29#define APBTMRS_RAW_INT_STATUS		0xa8
     30#define APBTMRS_COMP_VERSION		0xac
     31
     32#define APBTMR_CONTROL_ENABLE		(1 << 0)
     33/* 1: periodic, 0:free running. */
     34#define APBTMR_CONTROL_MODE_PERIODIC	(1 << 1)
     35#define APBTMR_CONTROL_INT		(1 << 2)
     36
     37static inline struct dw_apb_clock_event_device *
     38ced_to_dw_apb_ced(struct clock_event_device *evt)
     39{
     40	return container_of(evt, struct dw_apb_clock_event_device, ced);
     41}
     42
     43static inline struct dw_apb_clocksource *
     44clocksource_to_dw_apb_clocksource(struct clocksource *cs)
     45{
     46	return container_of(cs, struct dw_apb_clocksource, cs);
     47}
     48
     49static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
     50{
     51	return readl(timer->base + offs);
     52}
     53
     54static inline void apbt_writel(struct dw_apb_timer *timer, u32 val,
     55			unsigned long offs)
     56{
     57	writel(val, timer->base + offs);
     58}
     59
     60static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs)
     61{
     62	return readl_relaxed(timer->base + offs);
     63}
     64
     65static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val,
     66			unsigned long offs)
     67{
     68	writel_relaxed(val, timer->base + offs);
     69}
     70
     71static void apbt_disable_int(struct dw_apb_timer *timer)
     72{
     73	u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
     74
     75	ctrl |= APBTMR_CONTROL_INT;
     76	apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
     77}
     78
     79/**
     80 * dw_apb_clockevent_pause() - stop the clock_event_device from running
     81 *
     82 * @dw_ced:	The APB clock to stop generating events.
     83 */
     84void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced)
     85{
     86	disable_irq(dw_ced->timer.irq);
     87	apbt_disable_int(&dw_ced->timer);
     88}
     89
     90static void apbt_eoi(struct dw_apb_timer *timer)
     91{
     92	apbt_readl_relaxed(timer, APBTMR_N_EOI);
     93}
     94
     95static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
     96{
     97	struct clock_event_device *evt = data;
     98	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
     99
    100	if (!evt->event_handler) {
    101		pr_info("Spurious APBT timer interrupt %d\n", irq);
    102		return IRQ_NONE;
    103	}
    104
    105	if (dw_ced->eoi)
    106		dw_ced->eoi(&dw_ced->timer);
    107
    108	evt->event_handler(evt);
    109	return IRQ_HANDLED;
    110}
    111
    112static void apbt_enable_int(struct dw_apb_timer *timer)
    113{
    114	u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
    115	/* clear pending intr */
    116	apbt_readl(timer, APBTMR_N_EOI);
    117	ctrl &= ~APBTMR_CONTROL_INT;
    118	apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
    119}
    120
    121static int apbt_shutdown(struct clock_event_device *evt)
    122{
    123	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
    124	u32 ctrl;
    125
    126	pr_debug("%s CPU %d state=shutdown\n", __func__,
    127		 cpumask_first(evt->cpumask));
    128
    129	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
    130	ctrl &= ~APBTMR_CONTROL_ENABLE;
    131	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    132	return 0;
    133}
    134
    135static int apbt_set_oneshot(struct clock_event_device *evt)
    136{
    137	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
    138	u32 ctrl;
    139
    140	pr_debug("%s CPU %d state=oneshot\n", __func__,
    141		 cpumask_first(evt->cpumask));
    142
    143	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
    144	/*
    145	 * set free running mode, this mode will let timer reload max
    146	 * timeout which will give time (3min on 25MHz clock) to rearm
    147	 * the next event, therefore emulate the one-shot mode.
    148	 */
    149	ctrl &= ~APBTMR_CONTROL_ENABLE;
    150	ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC;
    151
    152	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    153	/* write again to set free running mode */
    154	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    155
    156	/*
    157	 * DW APB p. 46, load counter with all 1s before starting free
    158	 * running mode.
    159	 */
    160	apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT);
    161	ctrl &= ~APBTMR_CONTROL_INT;
    162	ctrl |= APBTMR_CONTROL_ENABLE;
    163	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    164	return 0;
    165}
    166
    167static int apbt_set_periodic(struct clock_event_device *evt)
    168{
    169	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
    170	unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
    171	u32 ctrl;
    172
    173	pr_debug("%s CPU %d state=periodic\n", __func__,
    174		 cpumask_first(evt->cpumask));
    175
    176	ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
    177	ctrl |= APBTMR_CONTROL_MODE_PERIODIC;
    178	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    179	/*
    180	 * DW APB p. 46, have to disable timer before load counter,
    181	 * may cause sync problem.
    182	 */
    183	ctrl &= ~APBTMR_CONTROL_ENABLE;
    184	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    185	udelay(1);
    186	pr_debug("Setting clock period %lu for HZ %d\n", period, HZ);
    187	apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT);
    188	ctrl |= APBTMR_CONTROL_ENABLE;
    189	apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    190	return 0;
    191}
    192
    193static int apbt_resume(struct clock_event_device *evt)
    194{
    195	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
    196
    197	pr_debug("%s CPU %d state=resume\n", __func__,
    198		 cpumask_first(evt->cpumask));
    199
    200	apbt_enable_int(&dw_ced->timer);
    201	return 0;
    202}
    203
    204static int apbt_next_event(unsigned long delta,
    205			   struct clock_event_device *evt)
    206{
    207	u32 ctrl;
    208	struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
    209
    210	/* Disable timer */
    211	ctrl = apbt_readl_relaxed(&dw_ced->timer, APBTMR_N_CONTROL);
    212	ctrl &= ~APBTMR_CONTROL_ENABLE;
    213	apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    214	/* write new count */
    215	apbt_writel_relaxed(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
    216	ctrl |= APBTMR_CONTROL_ENABLE;
    217	apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
    218
    219	return 0;
    220}
    221
    222/**
    223 * dw_apb_clockevent_init() - use an APB timer as a clock_event_device
    224 *
    225 * @cpu:	The CPU the events will be targeted at or -1 if CPU affiliation
    226 *		isn't required.
    227 * @name:	The name used for the timer and the IRQ for it.
    228 * @rating:	The rating to give the timer.
    229 * @base:	I/O base for the timer registers.
    230 * @irq:	The interrupt number to use for the timer.
    231 * @freq:	The frequency that the timer counts at.
    232 *
    233 * This creates a clock_event_device for using with the generic clock layer
    234 * but does not start and register it.  This should be done with
    235 * dw_apb_clockevent_register() as the next step.  If this is the first time
    236 * it has been called for a timer then the IRQ will be requested, if not it
    237 * just be enabled to allow CPU hotplug to avoid repeatedly requesting and
    238 * releasing the IRQ.
    239 */
    240struct dw_apb_clock_event_device *
    241dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
    242		       void __iomem *base, int irq, unsigned long freq)
    243{
    244	struct dw_apb_clock_event_device *dw_ced =
    245		kzalloc(sizeof(*dw_ced), GFP_KERNEL);
    246	int err;
    247
    248	if (!dw_ced)
    249		return NULL;
    250
    251	dw_ced->timer.base = base;
    252	dw_ced->timer.irq = irq;
    253	dw_ced->timer.freq = freq;
    254
    255	clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD);
    256	dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff,
    257						       &dw_ced->ced);
    258	dw_ced->ced.max_delta_ticks = 0x7fffffff;
    259	dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
    260	dw_ced->ced.min_delta_ticks = 5000;
    261	dw_ced->ced.cpumask = cpu < 0 ? cpu_possible_mask : cpumask_of(cpu);
    262	dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
    263				CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
    264	dw_ced->ced.set_state_shutdown = apbt_shutdown;
    265	dw_ced->ced.set_state_periodic = apbt_set_periodic;
    266	dw_ced->ced.set_state_oneshot = apbt_set_oneshot;
    267	dw_ced->ced.set_state_oneshot_stopped = apbt_shutdown;
    268	dw_ced->ced.tick_resume = apbt_resume;
    269	dw_ced->ced.set_next_event = apbt_next_event;
    270	dw_ced->ced.irq = dw_ced->timer.irq;
    271	dw_ced->ced.rating = rating;
    272	dw_ced->ced.name = name;
    273
    274	dw_ced->eoi = apbt_eoi;
    275	err = request_irq(irq, dw_apb_clockevent_irq,
    276			  IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
    277			  dw_ced->ced.name, &dw_ced->ced);
    278	if (err) {
    279		pr_err("failed to request timer irq\n");
    280		kfree(dw_ced);
    281		dw_ced = NULL;
    282	}
    283
    284	return dw_ced;
    285}
    286
    287/**
    288 * dw_apb_clockevent_resume() - resume a clock that has been paused.
    289 *
    290 * @dw_ced:	The APB clock to resume.
    291 */
    292void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced)
    293{
    294	enable_irq(dw_ced->timer.irq);
    295}
    296
    297/**
    298 * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ.
    299 *
    300 * @dw_ced:	The APB clock to stop generating the events.
    301 */
    302void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced)
    303{
    304	free_irq(dw_ced->timer.irq, &dw_ced->ced);
    305}
    306
    307/**
    308 * dw_apb_clockevent_register() - register the clock with the generic layer
    309 *
    310 * @dw_ced:	The APB clock to register as a clock_event_device.
    311 */
    312void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced)
    313{
    314	apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL);
    315	clockevents_register_device(&dw_ced->ced);
    316	apbt_enable_int(&dw_ced->timer);
    317}
    318
    319/**
    320 * dw_apb_clocksource_start() - start the clocksource counting.
    321 *
    322 * @dw_cs:	The clocksource to start.
    323 *
    324 * This is used to start the clocksource before registration and can be used
    325 * to enable calibration of timers.
    326 */
    327void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
    328{
    329	/*
    330	 * start count down from 0xffff_ffff. this is done by toggling the
    331	 * enable bit then load initial load count to ~0.
    332	 */
    333	u32 ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
    334
    335	ctrl &= ~APBTMR_CONTROL_ENABLE;
    336	apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
    337	apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT);
    338	/* enable, mask interrupt */
    339	ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC;
    340	ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT);
    341	apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
    342	/* read it once to get cached counter value initialized */
    343	dw_apb_clocksource_read(dw_cs);
    344}
    345
    346static u64 __apbt_read_clocksource(struct clocksource *cs)
    347{
    348	u32 current_count;
    349	struct dw_apb_clocksource *dw_cs =
    350		clocksource_to_dw_apb_clocksource(cs);
    351
    352	current_count = apbt_readl_relaxed(&dw_cs->timer,
    353					APBTMR_N_CURRENT_VALUE);
    354
    355	return (u64)~current_count;
    356}
    357
    358static void apbt_restart_clocksource(struct clocksource *cs)
    359{
    360	struct dw_apb_clocksource *dw_cs =
    361		clocksource_to_dw_apb_clocksource(cs);
    362
    363	dw_apb_clocksource_start(dw_cs);
    364}
    365
    366/**
    367 * dw_apb_clocksource_init() - use an APB timer as a clocksource.
    368 *
    369 * @rating:	The rating to give the clocksource.
    370 * @name:	The name for the clocksource.
    371 * @base:	The I/O base for the timer registers.
    372 * @freq:	The frequency that the timer counts at.
    373 *
    374 * This creates a clocksource using an APB timer but does not yet register it
    375 * with the clocksource system.  This should be done with
    376 * dw_apb_clocksource_register() as the next step.
    377 */
    378struct dw_apb_clocksource *
    379dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
    380			unsigned long freq)
    381{
    382	struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL);
    383
    384	if (!dw_cs)
    385		return NULL;
    386
    387	dw_cs->timer.base = base;
    388	dw_cs->timer.freq = freq;
    389	dw_cs->cs.name = name;
    390	dw_cs->cs.rating = rating;
    391	dw_cs->cs.read = __apbt_read_clocksource;
    392	dw_cs->cs.mask = CLOCKSOURCE_MASK(32);
    393	dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
    394	dw_cs->cs.resume = apbt_restart_clocksource;
    395
    396	return dw_cs;
    397}
    398
    399/**
    400 * dw_apb_clocksource_register() - register the APB clocksource.
    401 *
    402 * @dw_cs:	The clocksource to register.
    403 */
    404void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs)
    405{
    406	clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq);
    407}
    408
    409/**
    410 * dw_apb_clocksource_read() - read the current value of a clocksource.
    411 *
    412 * @dw_cs:	The clocksource to read.
    413 */
    414u64 dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs)
    415{
    416	return (u64)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
    417}