Skip to content

Commit d95c884

Browse files
committed
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull missed timer updates from Thomas Gleixner: "This is a branch which got forgotten during the merge window, but it contains only fixes and hardware enablement. No fundamental changes. - Various fixes for the imx-tpm clocksource driver - A new timer driver for the NCPM7xx SoC family" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clocksource/drivers/imx-tpm: Add different counter width support clocksource/drivers/imx-tpm: Correct some registers operation flow clocksource/drivers/imx-tpm: Fix typo of clock name dt-bindings: timer: tpm: fix typo of clock name clocksource/drivers/npcm: Add NPCM7xx timer driver dt-binding: timer: document NPCM7xx timer DT bindings
2 parents e6d9bfd + 90c7c0c commit d95c884

File tree

6 files changed

+279
-11
lines changed

6 files changed

+279
-11
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Nuvoton NPCM7xx timer
2+
3+
Nuvoton NPCM7xx have three timer modules, each timer module provides five 24-bit
4+
timer counters.
5+
6+
Required properties:
7+
- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750.
8+
- reg : Offset and length of the register set for the device.
9+
- interrupts : Contain the timer interrupt with flags for
10+
falling edge.
11+
- clocks : phandle of timer reference clock (usually a 25 MHz clock).
12+
13+
Example:
14+
15+
timer@f0008000 {
16+
compatible = "nuvoton,npcm750-timer";
17+
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
18+
reg = <0xf0008000 0x50>;
19+
clocks = <&clk NPCM7XX_CLK_TIMER>;
20+
};
21+

Documentation/devicetree/bindings/timer/nxp,tpm-timer.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Required properties:
1515
- interrupts : Should be the clock event device interrupt.
1616
- clocks : The clocks provided by the SoC to drive the timer, must contain
1717
an entry for each entry in clock-names.
18-
- clock-names : Must include the following entries: "igp" and "per".
18+
- clock-names : Must include the following entries: "ipg" and "per".
1919

2020
Example:
2121
tpm5: tpm@40260000 {

drivers/clocksource/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ config VT8500_TIMER
133133
help
134134
Enables support for the VT8500 driver.
135135

136+
config NPCM7XX_TIMER
137+
bool "NPCM7xx timer driver" if COMPILE_TEST
138+
depends on HAS_IOMEM
139+
select CLKSRC_MMIO
140+
help
141+
Enable 24-bit TIMER0 and TIMER1 counters in the NPCM7xx architecture,
142+
While TIMER0 serves as clockevent and TIMER1 serves as clocksource.
143+
136144
config CADENCE_TTC_TIMER
137145
bool "Cadence TTC timer driver" if COMPILE_TEST
138146
depends on COMMON_CLK

drivers/clocksource/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
5656
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
5757
obj-$(CONFIG_OWL_TIMER) += owl-timer.o
5858
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
59+
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
5960

6061
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
6162
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o

drivers/clocksource/timer-imx-tpm.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
#include <linux/of_irq.h>
1818
#include <linux/sched_clock.h>
1919

20+
#define TPM_PARAM 0x4
21+
#define TPM_PARAM_WIDTH_SHIFT 16
22+
#define TPM_PARAM_WIDTH_MASK (0xff << 16)
2023
#define TPM_SC 0x10
2124
#define TPM_SC_CMOD_INC_PER_CNT (0x1 << 3)
2225
#define TPM_SC_CMOD_DIV_DEFAULT 0x3
26+
#define TPM_SC_CMOD_DIV_MAX 0x7
27+
#define TPM_SC_TOF_MASK (0x1 << 7)
2328
#define TPM_CNT 0x14
2429
#define TPM_MOD 0x18
2530
#define TPM_STATUS 0x1c
@@ -29,8 +34,11 @@
2934
#define TPM_C0SC_MODE_SHIFT 2
3035
#define TPM_C0SC_MODE_MASK 0x3c
3136
#define TPM_C0SC_MODE_SW_COMPARE 0x4
37+
#define TPM_C0SC_CHF_MASK (0x1 << 7)
3238
#define TPM_C0V 0x24
3339

40+
static int counter_width;
41+
static int rating;
3442
static void __iomem *timer_base;
3543
static struct clock_event_device clockevent_tpm;
3644

@@ -83,10 +91,11 @@ static int __init tpm_clocksource_init(unsigned long rate)
8391
tpm_delay_timer.freq = rate;
8492
register_current_timer_delay(&tpm_delay_timer);
8593

86-
sched_clock_register(tpm_read_sched_clock, 32, rate);
94+
sched_clock_register(tpm_read_sched_clock, counter_width, rate);
8795

8896
return clocksource_mmio_init(timer_base + TPM_CNT, "imx-tpm",
89-
rate, 200, 32, clocksource_mmio_readl_up);
97+
rate, rating, counter_width,
98+
clocksource_mmio_readl_up);
9099
}
91100

92101
static int tpm_set_next_event(unsigned long delta,
@@ -139,7 +148,6 @@ static struct clock_event_device clockevent_tpm = {
139148
.set_state_oneshot = tpm_set_state_oneshot,
140149
.set_next_event = tpm_set_next_event,
141150
.set_state_shutdown = tpm_set_state_shutdown,
142-
.rating = 200,
143151
};
144152

145153
static int __init tpm_clockevent_init(unsigned long rate, int irq)
@@ -149,10 +157,11 @@ static int __init tpm_clockevent_init(unsigned long rate, int irq)
149157
ret = request_irq(irq, tpm_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
150158
"i.MX7ULP TPM Timer", &clockevent_tpm);
151159

160+
clockevent_tpm.rating = rating;
152161
clockevent_tpm.cpumask = cpumask_of(0);
153162
clockevent_tpm.irq = irq;
154-
clockevents_config_and_register(&clockevent_tpm,
155-
rate, 300, 0xfffffffe);
163+
clockevents_config_and_register(&clockevent_tpm, rate, 300,
164+
GENMASK(counter_width - 1, 1));
156165

157166
return ret;
158167
}
@@ -179,7 +188,7 @@ static int __init tpm_timer_init(struct device_node *np)
179188
ipg = of_clk_get_by_name(np, "ipg");
180189
per = of_clk_get_by_name(np, "per");
181190
if (IS_ERR(ipg) || IS_ERR(per)) {
182-
pr_err("tpm: failed to get igp or per clk\n");
191+
pr_err("tpm: failed to get ipg or per clk\n");
183192
ret = -ENODEV;
184193
goto err_clk_get;
185194
}
@@ -197,6 +206,11 @@ static int __init tpm_timer_init(struct device_node *np)
197206
goto err_per_clk_enable;
198207
}
199208

209+
counter_width = (readl(timer_base + TPM_PARAM) & TPM_PARAM_WIDTH_MASK)
210+
>> TPM_PARAM_WIDTH_SHIFT;
211+
/* use rating 200 for 32-bit counter and 150 for 16-bit counter */
212+
rating = counter_width == 0x20 ? 200 : 150;
213+
200214
/*
201215
* Initialize tpm module to a known state
202216
* 1) Counter disabled
@@ -205,16 +219,25 @@ static int __init tpm_timer_init(struct device_node *np)
205219
* 4) Channel0 disabled
206220
* 5) DMA transfers disabled
207221
*/
222+
/* make sure counter is disabled */
208223
writel(0, timer_base + TPM_SC);
224+
/* TOF is W1C */
225+
writel(TPM_SC_TOF_MASK, timer_base + TPM_SC);
209226
writel(0, timer_base + TPM_CNT);
210-
writel(0, timer_base + TPM_C0SC);
227+
/* CHF is W1C */
228+
writel(TPM_C0SC_CHF_MASK, timer_base + TPM_C0SC);
211229

212-
/* increase per cnt, div 8 by default */
213-
writel(TPM_SC_CMOD_INC_PER_CNT | TPM_SC_CMOD_DIV_DEFAULT,
230+
/*
231+
* increase per cnt,
232+
* div 8 for 32-bit counter and div 128 for 16-bit counter
233+
*/
234+
writel(TPM_SC_CMOD_INC_PER_CNT |
235+
(counter_width == 0x20 ?
236+
TPM_SC_CMOD_DIV_DEFAULT : TPM_SC_CMOD_DIV_MAX),
214237
timer_base + TPM_SC);
215238

216239
/* set MOD register to maximum for free running mode */
217-
writel(0xffffffff, timer_base + TPM_MOD);
240+
writel(GENMASK(counter_width - 1, 0), timer_base + TPM_MOD);
218241

219242
rate = clk_get_rate(per) >> 3;
220243
ret = tpm_clocksource_init(rate);
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2014-2018 Nuvoton Technologies [email protected]
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(3, 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+
56+
static 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+
68+
static 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+
80+
static 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+
88+
val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
89+
val |= NPCM7XX_START_ONESHOT_Tx;
90+
writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
91+
92+
return 0;
93+
}
94+
95+
static int npcm7xx_timer_periodic(struct clock_event_device *evt)
96+
{
97+
struct timer_of *to = to_timer_of(evt);
98+
u32 val;
99+
100+
val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
101+
val &= ~NPCM7XX_Tx_OPER;
102+
103+
writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);
104+
val |= NPCM7XX_START_PERIODIC_Tx;
105+
106+
writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
107+
108+
return 0;
109+
}
110+
111+
static int npcm7xx_clockevent_set_next_event(unsigned long evt,
112+
struct clock_event_device *clk)
113+
{
114+
struct timer_of *to = to_timer_of(clk);
115+
u32 val;
116+
117+
writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);
118+
val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
119+
val |= NPCM7XX_START_Tx;
120+
writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
121+
122+
return 0;
123+
}
124+
125+
static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)
126+
{
127+
struct clock_event_device *evt = (struct clock_event_device *)dev_id;
128+
struct timer_of *to = to_timer_of(evt);
129+
130+
writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);
131+
132+
evt->event_handler(evt);
133+
134+
return IRQ_HANDLED;
135+
}
136+
137+
static struct timer_of npcm7xx_to = {
138+
.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
139+
140+
.clkevt = {
141+
.name = "npcm7xx-timer0",
142+
.features = CLOCK_EVT_FEAT_PERIODIC |
143+
CLOCK_EVT_FEAT_ONESHOT,
144+
.set_next_event = npcm7xx_clockevent_set_next_event,
145+
.set_state_shutdown = npcm7xx_timer_shutdown,
146+
.set_state_periodic = npcm7xx_timer_periodic,
147+
.set_state_oneshot = npcm7xx_timer_oneshot,
148+
.tick_resume = npcm7xx_timer_resume,
149+
.rating = 300,
150+
},
151+
152+
.of_irq = {
153+
.handler = npcm7xx_timer0_interrupt,
154+
.flags = IRQF_TIMER | IRQF_IRQPOLL,
155+
},
156+
};
157+
158+
static void __init npcm7xx_clockevents_init(void)
159+
{
160+
writel(NPCM7XX_DEFAULT_CSR,
161+
timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);
162+
163+
writel(NPCM7XX_Tx_RESETINT,
164+
timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);
165+
166+
npcm7xx_to.clkevt.cpumask = cpumask_of(0);
167+
clockevents_config_and_register(&npcm7xx_to.clkevt,
168+
timer_of_rate(&npcm7xx_to),
169+
0x1, NPCM7XX_Tx_MAX_CNT);
170+
}
171+
172+
static void __init npcm7xx_clocksource_init(void)
173+
{
174+
u32 val;
175+
176+
writel(NPCM7XX_DEFAULT_CSR,
177+
timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
178+
writel(NPCM7XX_Tx_MAX_CNT,
179+
timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);
180+
181+
val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
182+
val |= NPCM7XX_START_Tx;
183+
writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
184+
185+
clocksource_mmio_init(timer_of_base(&npcm7xx_to) +
186+
NPCM7XX_REG_TDR1,
187+
"npcm7xx-timer1", timer_of_rate(&npcm7xx_to),
188+
200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,
189+
clocksource_mmio_readl_down);
190+
}
191+
192+
static int __init npcm7xx_timer_init(struct device_node *np)
193+
{
194+
int ret;
195+
196+
ret = timer_of_init(np, &npcm7xx_to);
197+
if (ret)
198+
return ret;
199+
200+
/* Clock input is divided by PRESCALE + 1 before it is fed */
201+
/* to the counter */
202+
npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
203+
(NPCM7XX_Tx_MIN_PRESCALE + 1);
204+
205+
npcm7xx_clocksource_init();
206+
npcm7xx_clockevents_init();
207+
208+
pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",
209+
timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));
210+
211+
return 0;
212+
}
213+
214+
TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
215+

0 commit comments

Comments
 (0)