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

renesas-ostm.c (5711B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Renesas Timer Support - OSTM
      4 *
      5 * Copyright (C) 2017 Renesas Electronics America, Inc.
      6 * Copyright (C) 2017 Chris Brandt
      7 */
      8
      9#include <linux/clk.h>
     10#include <linux/clockchips.h>
     11#include <linux/interrupt.h>
     12#include <linux/platform_device.h>
     13#include <linux/reset.h>
     14#include <linux/sched_clock.h>
     15#include <linux/slab.h>
     16
     17#include "timer-of.h"
     18
     19/*
     20 * The OSTM contains independent channels.
     21 * The first OSTM channel probed will be set up as a free running
     22 * clocksource. Additionally we will use this clocksource for the system
     23 * schedule timer sched_clock().
     24 *
     25 * The second (or more) channel probed will be set up as an interrupt
     26 * driven clock event.
     27 */
     28
     29static void __iomem *system_clock;	/* For sched_clock() */
     30
     31/* OSTM REGISTERS */
     32#define	OSTM_CMP		0x000	/* RW,32 */
     33#define	OSTM_CNT		0x004	/* R,32 */
     34#define	OSTM_TE			0x010	/* R,8 */
     35#define	OSTM_TS			0x014	/* W,8 */
     36#define	OSTM_TT			0x018	/* W,8 */
     37#define	OSTM_CTL		0x020	/* RW,8 */
     38
     39#define	TE			0x01
     40#define	TS			0x01
     41#define	TT			0x01
     42#define	CTL_PERIODIC		0x00
     43#define	CTL_ONESHOT		0x02
     44#define	CTL_FREERUN		0x02
     45
     46static void ostm_timer_stop(struct timer_of *to)
     47{
     48	if (readb(timer_of_base(to) + OSTM_TE) & TE) {
     49		writeb(TT, timer_of_base(to) + OSTM_TT);
     50
     51		/*
     52		 * Read back the register simply to confirm the write operation
     53		 * has completed since I/O writes can sometimes get queued by
     54		 * the bus architecture.
     55		 */
     56		while (readb(timer_of_base(to) + OSTM_TE) & TE)
     57			;
     58	}
     59}
     60
     61static int __init ostm_init_clksrc(struct timer_of *to)
     62{
     63	ostm_timer_stop(to);
     64
     65	writel(0, timer_of_base(to) + OSTM_CMP);
     66	writeb(CTL_FREERUN, timer_of_base(to) + OSTM_CTL);
     67	writeb(TS, timer_of_base(to) + OSTM_TS);
     68
     69	return clocksource_mmio_init(timer_of_base(to) + OSTM_CNT,
     70				     to->np->full_name, timer_of_rate(to), 300,
     71				     32, clocksource_mmio_readl_up);
     72}
     73
     74static u64 notrace ostm_read_sched_clock(void)
     75{
     76	return readl(system_clock);
     77}
     78
     79static void __init ostm_init_sched_clock(struct timer_of *to)
     80{
     81	system_clock = timer_of_base(to) + OSTM_CNT;
     82	sched_clock_register(ostm_read_sched_clock, 32, timer_of_rate(to));
     83}
     84
     85static int ostm_clock_event_next(unsigned long delta,
     86				 struct clock_event_device *ced)
     87{
     88	struct timer_of *to = to_timer_of(ced);
     89
     90	ostm_timer_stop(to);
     91
     92	writel(delta, timer_of_base(to) + OSTM_CMP);
     93	writeb(CTL_ONESHOT, timer_of_base(to) + OSTM_CTL);
     94	writeb(TS, timer_of_base(to) + OSTM_TS);
     95
     96	return 0;
     97}
     98
     99static int ostm_shutdown(struct clock_event_device *ced)
    100{
    101	struct timer_of *to = to_timer_of(ced);
    102
    103	ostm_timer_stop(to);
    104
    105	return 0;
    106}
    107static int ostm_set_periodic(struct clock_event_device *ced)
    108{
    109	struct timer_of *to = to_timer_of(ced);
    110
    111	if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
    112		ostm_timer_stop(to);
    113
    114	writel(timer_of_period(to) - 1, timer_of_base(to) + OSTM_CMP);
    115	writeb(CTL_PERIODIC, timer_of_base(to) + OSTM_CTL);
    116	writeb(TS, timer_of_base(to) + OSTM_TS);
    117
    118	return 0;
    119}
    120
    121static int ostm_set_oneshot(struct clock_event_device *ced)
    122{
    123	struct timer_of *to = to_timer_of(ced);
    124
    125	ostm_timer_stop(to);
    126
    127	return 0;
    128}
    129
    130static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id)
    131{
    132	struct clock_event_device *ced = dev_id;
    133
    134	if (clockevent_state_oneshot(ced))
    135		ostm_timer_stop(to_timer_of(ced));
    136
    137	/* notify clockevent layer */
    138	if (ced->event_handler)
    139		ced->event_handler(ced);
    140
    141	return IRQ_HANDLED;
    142}
    143
    144static int __init ostm_init_clkevt(struct timer_of *to)
    145{
    146	struct clock_event_device *ced = &to->clkevt;
    147
    148	ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
    149	ced->set_state_shutdown = ostm_shutdown;
    150	ced->set_state_periodic = ostm_set_periodic;
    151	ced->set_state_oneshot = ostm_set_oneshot;
    152	ced->set_next_event = ostm_clock_event_next;
    153	ced->shift = 32;
    154	ced->rating = 300;
    155	ced->cpumask = cpumask_of(0);
    156	clockevents_config_and_register(ced, timer_of_rate(to), 0xf,
    157					0xffffffff);
    158
    159	return 0;
    160}
    161
    162static int __init ostm_init(struct device_node *np)
    163{
    164	struct reset_control *rstc;
    165	struct timer_of *to;
    166	int ret;
    167
    168	to = kzalloc(sizeof(*to), GFP_KERNEL);
    169	if (!to)
    170		return -ENOMEM;
    171
    172	rstc = of_reset_control_get_optional_exclusive(np, NULL);
    173	if (IS_ERR(rstc)) {
    174		ret = PTR_ERR(rstc);
    175		goto err_free;
    176	}
    177
    178	reset_control_deassert(rstc);
    179
    180	to->flags = TIMER_OF_BASE | TIMER_OF_CLOCK;
    181	if (system_clock) {
    182		/*
    183		 * clock sources don't use interrupts, clock events do
    184		 */
    185		to->flags |= TIMER_OF_IRQ;
    186		to->of_irq.flags = IRQF_TIMER | IRQF_IRQPOLL;
    187		to->of_irq.handler = ostm_timer_interrupt;
    188	}
    189
    190	ret = timer_of_init(np, to);
    191	if (ret)
    192		goto err_reset;
    193
    194	/*
    195	 * First probed device will be used as system clocksource. Any
    196	 * additional devices will be used as clock events.
    197	 */
    198	if (!system_clock) {
    199		ret = ostm_init_clksrc(to);
    200		if (ret)
    201			goto err_cleanup;
    202
    203		ostm_init_sched_clock(to);
    204		pr_info("%pOF: used for clocksource\n", np);
    205	} else {
    206		ret = ostm_init_clkevt(to);
    207		if (ret)
    208			goto err_cleanup;
    209
    210		pr_info("%pOF: used for clock events\n", np);
    211	}
    212
    213	return 0;
    214
    215err_cleanup:
    216	timer_of_cleanup(to);
    217err_reset:
    218	reset_control_assert(rstc);
    219	reset_control_put(rstc);
    220err_free:
    221	kfree(to);
    222	return ret;
    223}
    224
    225TIMER_OF_DECLARE(ostm, "renesas,ostm", ostm_init);
    226
    227#ifdef CONFIG_ARCH_R9A07G044
    228static int __init ostm_probe(struct platform_device *pdev)
    229{
    230	struct device *dev = &pdev->dev;
    231
    232	return ostm_init(dev->of_node);
    233}
    234
    235static const struct of_device_id ostm_of_table[] = {
    236	{ .compatible = "renesas,ostm", },
    237	{ /* sentinel */ }
    238};
    239
    240static struct platform_driver ostm_device_driver = {
    241	.driver = {
    242		.name = "renesas_ostm",
    243		.of_match_table = of_match_ptr(ostm_of_table),
    244		.suppress_bind_attrs = true,
    245	},
    246};
    247builtin_platform_driver_probe(ostm_device_driver, ostm_probe);
    248#endif