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-pxa.c (5995B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * arch/arm/mach-pxa/time.c
      4 *
      5 * PXA clocksource, clockevents, and OST interrupt handlers.
      6 * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
      7 *
      8 * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
      9 * by MontaVista Software, Inc.  (Nico, your code rocks!)
     10 */
     11
     12#include <linux/kernel.h>
     13#include <linux/init.h>
     14#include <linux/interrupt.h>
     15#include <linux/clk.h>
     16#include <linux/clockchips.h>
     17#include <linux/of_address.h>
     18#include <linux/of_irq.h>
     19#include <linux/sched/clock.h>
     20#include <linux/sched_clock.h>
     21
     22#include <clocksource/pxa.h>
     23
     24#include <asm/div64.h>
     25
     26#define OSMR0		0x00	/* OS Timer 0 Match Register */
     27#define OSMR1		0x04	/* OS Timer 1 Match Register */
     28#define OSMR2		0x08	/* OS Timer 2 Match Register */
     29#define OSMR3		0x0C	/* OS Timer 3 Match Register */
     30
     31#define OSCR		0x10	/* OS Timer Counter Register */
     32#define OSSR		0x14	/* OS Timer Status Register */
     33#define OWER		0x18	/* OS Timer Watchdog Enable Register */
     34#define OIER		0x1C	/* OS Timer Interrupt Enable Register */
     35
     36#define OSSR_M3		(1 << 3)	/* Match status channel 3 */
     37#define OSSR_M2		(1 << 2)	/* Match status channel 2 */
     38#define OSSR_M1		(1 << 1)	/* Match status channel 1 */
     39#define OSSR_M0		(1 << 0)	/* Match status channel 0 */
     40
     41#define OIER_E0		(1 << 0)	/* Interrupt enable channel 0 */
     42
     43/*
     44 * This is PXA's sched_clock implementation. This has a resolution
     45 * of at least 308 ns and a maximum value of 208 days.
     46 *
     47 * The return value is guaranteed to be monotonic in that range as
     48 * long as there is always less than 582 seconds between successive
     49 * calls to sched_clock() which should always be the case in practice.
     50 */
     51
     52#define timer_readl(reg) readl_relaxed(timer_base + (reg))
     53#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
     54
     55static void __iomem *timer_base;
     56
     57static u64 notrace pxa_read_sched_clock(void)
     58{
     59	return timer_readl(OSCR);
     60}
     61
     62
     63#define MIN_OSCR_DELTA 16
     64
     65static irqreturn_t
     66pxa_ost0_interrupt(int irq, void *dev_id)
     67{
     68	struct clock_event_device *c = dev_id;
     69
     70	/* Disarm the compare/match, signal the event. */
     71	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
     72	timer_writel(OSSR_M0, OSSR);
     73	c->event_handler(c);
     74
     75	return IRQ_HANDLED;
     76}
     77
     78static int
     79pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
     80{
     81	unsigned long next, oscr;
     82
     83	timer_writel(timer_readl(OIER) | OIER_E0, OIER);
     84	next = timer_readl(OSCR) + delta;
     85	timer_writel(next, OSMR0);
     86	oscr = timer_readl(OSCR);
     87
     88	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
     89}
     90
     91static int pxa_osmr0_shutdown(struct clock_event_device *evt)
     92{
     93	/* initializing, released, or preparing for suspend */
     94	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
     95	timer_writel(OSSR_M0, OSSR);
     96	return 0;
     97}
     98
     99#ifdef CONFIG_PM
    100static unsigned long osmr[4], oier, oscr;
    101
    102static void pxa_timer_suspend(struct clock_event_device *cedev)
    103{
    104	osmr[0] = timer_readl(OSMR0);
    105	osmr[1] = timer_readl(OSMR1);
    106	osmr[2] = timer_readl(OSMR2);
    107	osmr[3] = timer_readl(OSMR3);
    108	oier = timer_readl(OIER);
    109	oscr = timer_readl(OSCR);
    110}
    111
    112static void pxa_timer_resume(struct clock_event_device *cedev)
    113{
    114	/*
    115	 * Ensure that we have at least MIN_OSCR_DELTA between match
    116	 * register 0 and the OSCR, to guarantee that we will receive
    117	 * the one-shot timer interrupt.  We adjust OSMR0 in preference
    118	 * to OSCR to guarantee that OSCR is monotonically incrementing.
    119	 */
    120	if (osmr[0] - oscr < MIN_OSCR_DELTA)
    121		osmr[0] += MIN_OSCR_DELTA;
    122
    123	timer_writel(osmr[0], OSMR0);
    124	timer_writel(osmr[1], OSMR1);
    125	timer_writel(osmr[2], OSMR2);
    126	timer_writel(osmr[3], OSMR3);
    127	timer_writel(oier, OIER);
    128	timer_writel(oscr, OSCR);
    129}
    130#else
    131#define pxa_timer_suspend NULL
    132#define pxa_timer_resume NULL
    133#endif
    134
    135static struct clock_event_device ckevt_pxa_osmr0 = {
    136	.name			= "osmr0",
    137	.features		= CLOCK_EVT_FEAT_ONESHOT,
    138	.rating			= 200,
    139	.set_next_event		= pxa_osmr0_set_next_event,
    140	.set_state_shutdown	= pxa_osmr0_shutdown,
    141	.set_state_oneshot	= pxa_osmr0_shutdown,
    142	.suspend		= pxa_timer_suspend,
    143	.resume			= pxa_timer_resume,
    144};
    145
    146static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
    147{
    148	int ret;
    149
    150	timer_writel(0, OIER);
    151	timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
    152
    153	sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
    154
    155	ckevt_pxa_osmr0.cpumask = cpumask_of(0);
    156
    157	ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
    158			  "ost0", &ckevt_pxa_osmr0);
    159	if (ret) {
    160		pr_err("Failed to setup irq\n");
    161		return ret;
    162	}
    163
    164	ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
    165				    32, clocksource_mmio_readl_up);
    166	if (ret) {
    167		pr_err("Failed to init clocksource\n");
    168		return ret;
    169	}
    170
    171	clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
    172					MIN_OSCR_DELTA * 2, 0x7fffffff);
    173
    174	return 0;
    175}
    176
    177static int __init pxa_timer_dt_init(struct device_node *np)
    178{
    179	struct clk *clk;
    180	int irq, ret;
    181
    182	/* timer registers are shared with watchdog timer */
    183	timer_base = of_iomap(np, 0);
    184	if (!timer_base) {
    185		pr_err("%pOFn: unable to map resource\n", np);
    186		return -ENXIO;
    187	}
    188
    189	clk = of_clk_get(np, 0);
    190	if (IS_ERR(clk)) {
    191		pr_crit("%pOFn: unable to get clk\n", np);
    192		return PTR_ERR(clk);
    193	}
    194
    195	ret = clk_prepare_enable(clk);
    196	if (ret) {
    197		pr_crit("Failed to prepare clock\n");
    198		return ret;
    199	}
    200
    201	/* we are only interested in OS-timer0 irq */
    202	irq = irq_of_parse_and_map(np, 0);
    203	if (irq <= 0) {
    204		pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np);
    205		return -EINVAL;
    206	}
    207
    208	return pxa_timer_common_init(irq, clk_get_rate(clk));
    209}
    210TIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
    211
    212/*
    213 * Legacy timer init for non device-tree boards.
    214 */
    215void __init pxa_timer_nodt_init(int irq, void __iomem *base)
    216{
    217	struct clk *clk;
    218
    219	timer_base = base;
    220	clk = clk_get(NULL, "OSTIMER0");
    221	if (clk && !IS_ERR(clk)) {
    222		clk_prepare_enable(clk);
    223		pxa_timer_common_init(irq, clk_get_rate(clk));
    224	} else {
    225		pr_crit("%s: unable to get clk\n", __func__);
    226	}
    227}