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-npcm7xx.c (5831B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com
      4 * All rights reserved.
      5 *
      6 * Copyright 2017 Google, Inc.
      7 */
      8
      9#include <linux/kernel.h>
     10#include <linux/sched.h>
     11#include <linux/init.h>
     12#include <linux/interrupt.h>
     13#include <linux/err.h>
     14#include <linux/clk.h>
     15#include <linux/io.h>
     16#include <linux/clockchips.h>
     17#include <linux/of_irq.h>
     18#include <linux/of_address.h>
     19#include "timer-of.h"
     20
     21/* Timers registers */
     22#define NPCM7XX_REG_TCSR0	0x0 /* Timer 0 Control and Status Register */
     23#define NPCM7XX_REG_TICR0	0x8 /* Timer 0 Initial Count Register */
     24#define NPCM7XX_REG_TCSR1	0x4 /* Timer 1 Control and Status Register */
     25#define NPCM7XX_REG_TICR1	0xc /* Timer 1 Initial Count Register */
     26#define NPCM7XX_REG_TDR1	0x14 /* Timer 1 Data Register */
     27#define NPCM7XX_REG_TISR	0x18 /* Timer Interrupt Status Register */
     28
     29/* Timers control */
     30#define NPCM7XX_Tx_RESETINT		0x1f
     31#define NPCM7XX_Tx_PERIOD		BIT(27)
     32#define NPCM7XX_Tx_INTEN		BIT(29)
     33#define NPCM7XX_Tx_COUNTEN		BIT(30)
     34#define NPCM7XX_Tx_ONESHOT		0x0
     35#define NPCM7XX_Tx_OPER			GENMASK(28, 27)
     36#define NPCM7XX_Tx_MIN_PRESCALE		0x1
     37#define NPCM7XX_Tx_TDR_MASK_BITS	24
     38#define NPCM7XX_Tx_MAX_CNT		0xFFFFFF
     39#define NPCM7XX_T0_CLR_INT		0x1
     40#define NPCM7XX_Tx_CLR_CSR		0x0
     41
     42/* Timers operating mode */
     43#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \
     44					NPCM7XX_Tx_INTEN | \
     45					NPCM7XX_Tx_MIN_PRESCALE)
     46
     47#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \
     48					NPCM7XX_Tx_INTEN | \
     49					NPCM7XX_Tx_MIN_PRESCALE)
     50
     51#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \
     52				NPCM7XX_Tx_MIN_PRESCALE)
     53
     54#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE)
     55
     56static int npcm7xx_timer_resume(struct clock_event_device *evt)
     57{
     58	struct timer_of *to = to_timer_of(evt);
     59	u32 val;
     60
     61	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
     62	val |= NPCM7XX_Tx_COUNTEN;
     63	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
     64
     65	return 0;
     66}
     67
     68static int npcm7xx_timer_shutdown(struct clock_event_device *evt)
     69{
     70	struct timer_of *to = to_timer_of(evt);
     71	u32 val;
     72
     73	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
     74	val &= ~NPCM7XX_Tx_COUNTEN;
     75	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
     76
     77	return 0;
     78}
     79
     80static int npcm7xx_timer_oneshot(struct clock_event_device *evt)
     81{
     82	struct timer_of *to = to_timer_of(evt);
     83	u32 val;
     84
     85	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
     86	val &= ~NPCM7XX_Tx_OPER;
     87	val |= NPCM7XX_START_ONESHOT_Tx;
     88	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
     89
     90	return 0;
     91}
     92
     93static int npcm7xx_timer_periodic(struct clock_event_device *evt)
     94{
     95	struct timer_of *to = to_timer_of(evt);
     96	u32 val;
     97
     98	writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);
     99
    100	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
    101	val &= ~NPCM7XX_Tx_OPER;
    102	val |= NPCM7XX_START_PERIODIC_Tx;
    103	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
    104
    105	return 0;
    106}
    107
    108static int npcm7xx_clockevent_set_next_event(unsigned long evt,
    109		struct clock_event_device *clk)
    110{
    111	struct timer_of *to = to_timer_of(clk);
    112	u32 val;
    113
    114	writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);
    115	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
    116	val |= NPCM7XX_START_Tx;
    117	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
    118
    119	return 0;
    120}
    121
    122static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)
    123{
    124	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
    125	struct timer_of *to = to_timer_of(evt);
    126
    127	writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);
    128
    129	evt->event_handler(evt);
    130
    131	return IRQ_HANDLED;
    132}
    133
    134static struct timer_of npcm7xx_to = {
    135	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
    136
    137	.clkevt = {
    138		.name		    = "npcm7xx-timer0",
    139		.features	    = CLOCK_EVT_FEAT_PERIODIC |
    140				      CLOCK_EVT_FEAT_ONESHOT,
    141		.set_next_event	    = npcm7xx_clockevent_set_next_event,
    142		.set_state_shutdown = npcm7xx_timer_shutdown,
    143		.set_state_periodic = npcm7xx_timer_periodic,
    144		.set_state_oneshot  = npcm7xx_timer_oneshot,
    145		.tick_resume	    = npcm7xx_timer_resume,
    146		.rating		    = 300,
    147	},
    148
    149	.of_irq = {
    150		.handler = npcm7xx_timer0_interrupt,
    151		.flags = IRQF_TIMER | IRQF_IRQPOLL,
    152	},
    153};
    154
    155static void __init npcm7xx_clockevents_init(void)
    156{
    157	writel(NPCM7XX_DEFAULT_CSR,
    158		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);
    159
    160	writel(NPCM7XX_Tx_RESETINT,
    161		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);
    162
    163	npcm7xx_to.clkevt.cpumask = cpumask_of(0);
    164	clockevents_config_and_register(&npcm7xx_to.clkevt,
    165					timer_of_rate(&npcm7xx_to),
    166					0x1, NPCM7XX_Tx_MAX_CNT);
    167}
    168
    169static void __init npcm7xx_clocksource_init(void)
    170{
    171	u32 val;
    172
    173	writel(NPCM7XX_DEFAULT_CSR,
    174		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
    175	writel(NPCM7XX_Tx_MAX_CNT,
    176		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);
    177
    178	val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
    179	val |= NPCM7XX_START_Tx;
    180	writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
    181
    182	clocksource_mmio_init(timer_of_base(&npcm7xx_to) +
    183				NPCM7XX_REG_TDR1,
    184				"npcm7xx-timer1", timer_of_rate(&npcm7xx_to),
    185				200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,
    186				clocksource_mmio_readl_down);
    187}
    188
    189static int __init npcm7xx_timer_init(struct device_node *np)
    190{
    191	int ret;
    192
    193	ret = timer_of_init(np, &npcm7xx_to);
    194	if (ret)
    195		return ret;
    196
    197	/* Clock input is divided by PRESCALE + 1 before it is fed */
    198	/* to the counter */
    199	npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
    200		(NPCM7XX_Tx_MIN_PRESCALE + 1);
    201
    202	npcm7xx_clocksource_init();
    203	npcm7xx_clockevents_init();
    204
    205	pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",
    206		timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));
    207
    208	return 0;
    209}
    210
    211TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init);
    212TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
    213