mirror of https://github.com/torvalds/linux.git
- Use 64-bits for timer compensation for IoT usage where the suspend
time is much longer than what 32-bits can provide (Enlin Mu)
- Add delay support on sp804 for ARM32 platforms (Stephen Eta Zhou)
- Fix missing resource release on error in the probe path of in the
ralink driver (Haotian Zhang)
- Fix double deregistration on probe failure in the NXP STM driver
(Johan Hovold)
- Disable runtime PM for the Renesas SH CMT timer because it is
incompatible with PREEMPT_RT=y (Niklas Söderlund)
- Fix section mismatches in the NXP STM driver (Johan Hovold)
- Preventing unbinding the NXP PIT, STM and MMIO ARM Arch timers as
the code does not suppport bind/unbind (Johan Hovold)
- Use the clocksource instead of ticks on the RDA8810PL platform
(Enlin Mu)
- Drop the unused module alias for the STM32-LP (Johan Hovold)
- Add Realtek system timer driver (Hao-Wen Ting)
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmkm6t4ACgkQqDIjiipP
6E8xqQgAlXnV3vRJmEbjd3ILECvbKMLI2haHV2eA+75P+DvbfriL+ePMHkfkOPI6
CC5UhCSy410cQLO88tzy5+9K8Po2KnHxb+lVS2P6zzcdefL5ZWMZ9Q+CAOwSo1s9
An1A4nUgcTB52mAR+jlz++SF1VV/fMvskMrtiTg8bSIScSc+xi4sEC3GaZR09qSG
RODtzmVsyeoHQ1u6ziRJen8GzpX1q6vUP0eAAr+vXqTUXdCuUL8P20h2mwzxPJWH
mFo53OuKVbTMOoY1Av7euvO1ZZ1tsHsS4NxJfD1qatq+eh1As1dxYodB4dp44qZt
jjnVuj0QrE40VB6EnHAA4kKb6WWpow==
=WXsR
-----END PGP SIGNATURE-----
Merge tag 'timers-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daniel.lezcano/linux into timers/clocksource
Pull clocksource/event changes from Daniel Lezcano:
- Use 64-bits for timer compensation for IoT usage where the suspend
time is much longer than what 32-bits can provide (Enlin Mu)
- Add delay support on sp804 for ARM32 platforms (Stephen Eta Zhou)
- Fix missing resource release on error in the probe path of in the
ralink driver (Haotian Zhang)
- Fix double deregistration on probe failure in the NXP STM driver
(Johan Hovold)
- Disable runtime PM for the Renesas SH CMT timer because it is
incompatible with PREEMPT_RT=y (Niklas Söderlund)
- Fix section mismatches in the NXP STM driver (Johan Hovold)
- Preventing unbinding the NXP PIT, STM and MMIO ARM Arch timers as
the code does not suppport bind/unbind (Johan Hovold)
- Use the clocksource instead of ticks on the RDA8810PL platform
(Enlin Mu)
- Drop the unused module alias for the STM32-LP (Johan Hovold)
- Add Realtek system timer driver (Hao-Wen Ting)
Link: https://lore.kernel.org/all/9303b790-28d4-4bd9-b01d-28fb05493596@linaro.org
This commit is contained in:
commit
2437f79880
|
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/timer/realtek,rtd1625-systimer.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek System Timer
|
||||
|
||||
maintainers:
|
||||
- Hao-Wen Ting <haowen.ting@realtek.com>
|
||||
|
||||
description:
|
||||
The Realtek SYSTIMER (System Timer) is a 64-bit global hardware counter operating
|
||||
at a fixed 1MHz frequency. Thanks to its compare match interrupt capability,
|
||||
the timer natively supports oneshot mode for tick broadcast functionality.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: realtek,rtd1625-systimer
|
||||
- items:
|
||||
- const: realtek,rtd1635-systimer
|
||||
- const: realtek,rtd1625-systimer
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
timer@89420 {
|
||||
compatible = "realtek,rtd1635-systimer",
|
||||
"realtek,rtd1625-systimer";
|
||||
reg = <0x89420 0x18>;
|
||||
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
|
@ -21669,6 +21669,11 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml
|
||||
F: drivers/spi/spi-realtek-rtl-snand.c
|
||||
|
||||
REALTEK SYSTIMER DRIVER
|
||||
M: Hao-Wen Ting <haowen.ting@realtek.com>
|
||||
S: Maintained
|
||||
F: drivers/clocksource/timer-realtek.c
|
||||
|
||||
REALTEK WIRELESS DRIVER (rtlwifi family)
|
||||
M: Ping-Ke Shih <pkshih@realtek.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -782,4 +782,15 @@ config NXP_STM_TIMER
|
|||
Enables the support for NXP System Timer Module found in the
|
||||
s32g NXP platform series.
|
||||
|
||||
config RTK_SYSTIMER
|
||||
bool "Realtek SYSTIMER support"
|
||||
depends on ARM || ARM64
|
||||
depends on ARCH_REALTEK || COMPILE_TEST
|
||||
select TIMER_OF
|
||||
help
|
||||
This option enables the driver that registers the global 1 MHz hardware
|
||||
counter as a clock event device on Realtek SoCs. Make sure to enable
|
||||
this option only when building for a Realtek platform or for compilation
|
||||
testing.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -95,3 +95,4 @@ obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o
|
|||
obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o
|
||||
obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o
|
||||
obj-$(CONFIG_NXP_STM_TIMER) += timer-nxp-stm.o
|
||||
obj-$(CONFIG_RTK_SYSTIMER) += timer-realtek.o
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ static struct platform_driver arch_timer_mmio_drv = {
|
|||
.driver = {
|
||||
.name = "arch-timer-mmio",
|
||||
.of_match_table = arch_timer_mmio_of_table,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = arch_timer_mmio_probe,
|
||||
};
|
||||
|
|
@ -434,6 +435,7 @@ builtin_platform_driver(arch_timer_mmio_drv);
|
|||
static struct platform_driver arch_timer_mmio_acpi_drv = {
|
||||
.driver = {
|
||||
.name = "gtdt-arm-mmio-timer",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = arch_timer_mmio_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -355,14 +355,6 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
|
|||
|
||||
dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
|
||||
|
||||
/* enable clock */
|
||||
ret = clk_enable(ch->cmt->clk);
|
||||
if (ret) {
|
||||
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n",
|
||||
ch->index);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* make sure channel is disabled */
|
||||
sh_cmt_start_stop_ch(ch, 0);
|
||||
|
||||
|
|
@ -384,19 +376,12 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
|
|||
if (ret || sh_cmt_read_cmcnt(ch)) {
|
||||
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
|
||||
ch->index);
|
||||
ret = -ETIMEDOUT;
|
||||
goto err1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* enable channel */
|
||||
sh_cmt_start_stop_ch(ch, 1);
|
||||
return 0;
|
||||
err1:
|
||||
/* stop clock */
|
||||
clk_disable(ch->cmt->clk);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sh_cmt_disable(struct sh_cmt_channel *ch)
|
||||
|
|
@ -407,9 +392,6 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch)
|
|||
/* disable interrupts in CMT block */
|
||||
sh_cmt_write_cmcsr(ch, 0);
|
||||
|
||||
/* stop clock */
|
||||
clk_disable(ch->cmt->clk);
|
||||
|
||||
dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
|
||||
}
|
||||
|
||||
|
|
@ -583,8 +565,6 @@ static int sh_cmt_start_clocksource(struct sh_cmt_channel *ch)
|
|||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(&ch->cmt->pdev->dev);
|
||||
|
||||
raw_spin_lock_irqsave(&ch->lock, flags);
|
||||
|
||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||
|
|
@ -619,8 +599,6 @@ static void sh_cmt_stop_clocksource(struct sh_cmt_channel *ch)
|
|||
sh_cmt_disable(ch);
|
||||
|
||||
raw_spin_unlock_irqrestore(&ch->lock, flags);
|
||||
|
||||
pm_runtime_put(&ch->cmt->pdev->dev);
|
||||
}
|
||||
|
||||
static int sh_cmt_start_clockevent(struct sh_cmt_channel *ch)
|
||||
|
|
@ -630,10 +608,8 @@ static int sh_cmt_start_clockevent(struct sh_cmt_channel *ch)
|
|||
|
||||
raw_spin_lock_irqsave(&ch->lock, flags);
|
||||
|
||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
|
||||
pm_runtime_get_sync(&ch->cmt->pdev->dev);
|
||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||
ret = sh_cmt_enable(ch);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
@ -656,10 +632,8 @@ static void sh_cmt_stop_clockevent(struct sh_cmt_channel *ch)
|
|||
|
||||
ch->flags &= ~FLAG_CLOCKEVENT;
|
||||
|
||||
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
|
||||
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||
sh_cmt_disable(ch);
|
||||
pm_runtime_put(&ch->cmt->pdev->dev);
|
||||
}
|
||||
|
||||
/* adjust the timeout to maximum if only clocksource left */
|
||||
if (ch->flags & FLAG_CLOCKSOURCE)
|
||||
|
|
@ -1134,8 +1108,6 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
|
|||
mask &= ~(1 << hwidx);
|
||||
}
|
||||
|
||||
clk_disable(cmt->clk);
|
||||
|
||||
platform_set_drvdata(pdev, cmt);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1183,8 +1155,6 @@ static int sh_cmt_probe(struct platform_device *pdev)
|
|||
out:
|
||||
if (cmt->has_clockevent || cmt->has_clocksource)
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
else
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,9 +374,10 @@ static struct platform_driver nxp_pit_driver = {
|
|||
.driver = {
|
||||
.name = "nxp-pit",
|
||||
.of_match_table = pit_timer_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = pit_timer_probe,
|
||||
};
|
||||
module_platform_driver(nxp_pit_driver);
|
||||
builtin_platform_driver(nxp_pit_driver);
|
||||
|
||||
TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init);
|
||||
|
|
|
|||
|
|
@ -177,15 +177,15 @@ static void nxp_stm_clocksource_resume(struct clocksource *cs)
|
|||
nxp_stm_clocksource_enable(cs);
|
||||
}
|
||||
|
||||
static void __init devm_clocksource_unregister(void *data)
|
||||
static void devm_clocksource_unregister(void *data)
|
||||
{
|
||||
struct stm_timer *stm_timer = data;
|
||||
|
||||
clocksource_unregister(&stm_timer->cs);
|
||||
}
|
||||
|
||||
static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer,
|
||||
const char *name, void __iomem *base, struct clk *clk)
|
||||
static int nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer,
|
||||
const char *name, void __iomem *base, struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -208,10 +208,8 @@ static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer
|
|||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer);
|
||||
if (ret) {
|
||||
clocksource_unregister(&stm_timer->cs);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
stm_sched_clock = stm_timer;
|
||||
|
||||
|
|
@ -298,9 +296,9 @@ static void nxp_stm_clockevent_resume(struct clock_event_device *ced)
|
|||
nxp_stm_module_get(stm_timer);
|
||||
}
|
||||
|
||||
static int __init nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer,
|
||||
const char *name, void __iomem *base, int irq,
|
||||
struct clk *clk, int cpu)
|
||||
static int nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer,
|
||||
const char *name, void __iomem *base, int irq,
|
||||
struct clk *clk, int cpu)
|
||||
{
|
||||
stm_timer->base = base;
|
||||
stm_timer->rate = clk_get_rate(clk);
|
||||
|
|
@ -388,7 +386,7 @@ static irqreturn_t nxp_stm_module_interrupt(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init nxp_stm_timer_probe(struct platform_device *pdev)
|
||||
static int nxp_stm_timer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm_timer *stm_timer;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -484,14 +482,15 @@ static const struct of_device_id nxp_stm_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, nxp_stm_of_match);
|
||||
|
||||
static struct platform_driver nxp_stm_probe = {
|
||||
static struct platform_driver nxp_stm_driver = {
|
||||
.probe = nxp_stm_timer_probe,
|
||||
.driver = {
|
||||
.name = "nxp-stm",
|
||||
.of_match_table = nxp_stm_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
module_platform_driver(nxp_stm_probe);
|
||||
builtin_platform_driver(nxp_stm_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NXP System Timer Module driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -130,14 +130,15 @@ static int __init ralink_systick_init(struct device_node *np)
|
|||
systick.dev.irq = irq_of_parse_and_map(np, 0);
|
||||
if (!systick.dev.irq) {
|
||||
pr_err("%pOFn: request_irq failed", np);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
|
||||
SYSTICK_FREQ, 301, 16,
|
||||
clocksource_mmio_readl_up);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_free_irq;
|
||||
|
||||
clockevents_register_device(&systick.dev);
|
||||
|
||||
|
|
@ -145,6 +146,12 @@ static int __init ralink_systick_init(struct device_node *np)
|
|||
np, systick.dev.mult, systick.dev.shift);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
irq_dispose_mapping(systick.dev.irq);
|
||||
err_iounmap:
|
||||
iounmap(systick.membase);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched_clock.h>
|
||||
|
||||
#include "timer-of.h"
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ static struct timer_of rda_ostimer_of = {
|
|||
},
|
||||
};
|
||||
|
||||
static u64 rda_hwtimer_read(struct clocksource *cs)
|
||||
static u64 rda_hwtimer_clocksource_read(void)
|
||||
{
|
||||
void __iomem *base = timer_of_base(&rda_ostimer_of);
|
||||
u32 lo, hi;
|
||||
|
|
@ -167,6 +168,11 @@ static u64 rda_hwtimer_read(struct clocksource *cs)
|
|||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
static u64 rda_hwtimer_read(struct clocksource *cs)
|
||||
{
|
||||
return rda_hwtimer_clocksource_read();
|
||||
}
|
||||
|
||||
static struct clocksource rda_hwtimer_clocksource = {
|
||||
.name = "rda-timer",
|
||||
.rating = 400,
|
||||
|
|
@ -185,6 +191,7 @@ static int __init rda_timer_init(struct device_node *np)
|
|||
return ret;
|
||||
|
||||
clocksource_register_hz(&rda_hwtimer_clocksource, rate);
|
||||
sched_clock_register(rda_hwtimer_clocksource_read, 64, rate);
|
||||
|
||||
clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
|
||||
0x2, UINT_MAX);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2025 Realtek Semiconductor Corp.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "timer-of.h"
|
||||
|
||||
#define ENBL 1
|
||||
#define DSBL 0
|
||||
|
||||
#define SYSTIMER_RATE 1000000
|
||||
#define SYSTIMER_MIN_DELTA 0x64
|
||||
#define SYSTIMER_MAX_DELTA ULONG_MAX
|
||||
|
||||
/* SYSTIMER Register Offset (RTK Internal Use) */
|
||||
#define TS_LW_OFST 0x0
|
||||
#define TS_HW_OFST 0x4
|
||||
#define TS_CMP_VAL_LW_OFST 0x8
|
||||
#define TS_CMP_VAL_HW_OFST 0xC
|
||||
#define TS_CMP_CTRL_OFST 0x10
|
||||
#define TS_CMP_STAT_OFST 0x14
|
||||
|
||||
/* SYSTIMER CMP CTRL REG Mask */
|
||||
#define TS_CMP_EN_MASK 0x1
|
||||
#define TS_WR_EN0_MASK 0x2
|
||||
|
||||
static void __iomem *systimer_base;
|
||||
|
||||
static u64 rtk_ts64_read(void)
|
||||
{
|
||||
u32 low, high;
|
||||
u64 ts;
|
||||
|
||||
/* Caution: Read LSB word (TS_LW_OFST) first then MSB (TS_HW_OFST) */
|
||||
low = readl(systimer_base + TS_LW_OFST);
|
||||
high = readl(systimer_base + TS_HW_OFST);
|
||||
ts = ((u64)high << 32) | low;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
static void rtk_cmp_value_write(u64 value)
|
||||
{
|
||||
u32 high, low;
|
||||
|
||||
low = value & 0xFFFFFFFF;
|
||||
high = value >> 32;
|
||||
|
||||
writel(high, systimer_base + TS_CMP_VAL_HW_OFST);
|
||||
writel(low, systimer_base + TS_CMP_VAL_LW_OFST);
|
||||
}
|
||||
|
||||
static inline void rtk_cmp_en_write(bool cmp_en)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = TS_WR_EN0_MASK;
|
||||
if (cmp_en == ENBL)
|
||||
val |= TS_CMP_EN_MASK;
|
||||
|
||||
writel(val, systimer_base + TS_CMP_CTRL_OFST);
|
||||
}
|
||||
|
||||
static int rtk_syst_clkevt_next_event(unsigned long cycles, struct clock_event_device *clkevt)
|
||||
{
|
||||
u64 cmp_val;
|
||||
|
||||
rtk_cmp_en_write(DSBL);
|
||||
cmp_val = rtk_ts64_read();
|
||||
|
||||
/* Set CMP value to current timestamp plus delta_us */
|
||||
rtk_cmp_value_write(cmp_val + cycles);
|
||||
rtk_cmp_en_write(ENBL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t rtk_ts_match_intr_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *clkevt = dev_id;
|
||||
void __iomem *reg_base;
|
||||
u32 val;
|
||||
|
||||
/* Disable TS CMP Match */
|
||||
rtk_cmp_en_write(DSBL);
|
||||
|
||||
/* Clear TS CMP INTR */
|
||||
reg_base = systimer_base + TS_CMP_STAT_OFST;
|
||||
val = readl(reg_base) & TS_CMP_EN_MASK;
|
||||
writel(val | TS_CMP_EN_MASK, reg_base);
|
||||
clkevt->event_handler(clkevt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rtk_syst_shutdown(struct clock_event_device *clkevt)
|
||||
{
|
||||
void __iomem *reg_base;
|
||||
u64 cmp_val = 0;
|
||||
|
||||
/* Disable TS CMP Match */
|
||||
rtk_cmp_en_write(DSBL);
|
||||
/* Set compare value to 0 */
|
||||
rtk_cmp_value_write(cmp_val);
|
||||
|
||||
/* Clear TS CMP INTR */
|
||||
reg_base = systimer_base + TS_CMP_STAT_OFST;
|
||||
writel(TS_CMP_EN_MASK, reg_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct timer_of rtk_timer_to = {
|
||||
.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
|
||||
|
||||
.clkevt = {
|
||||
.name = "rtk-clkevt",
|
||||
.rating = 300,
|
||||
.cpumask = cpu_possible_mask,
|
||||
.features = CLOCK_EVT_FEAT_DYNIRQ |
|
||||
CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_next_event = rtk_syst_clkevt_next_event,
|
||||
.set_state_oneshot = rtk_syst_shutdown,
|
||||
.set_state_shutdown = rtk_syst_shutdown,
|
||||
},
|
||||
|
||||
.of_irq = {
|
||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = rtk_ts_match_intr_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rtk_systimer_init(struct device_node *node)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = timer_of_init(node, &rtk_timer_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
systimer_base = timer_of_base(&rtk_timer_to);
|
||||
clockevents_config_and_register(&rtk_timer_to.clkevt, SYSTIMER_RATE,
|
||||
SYSTIMER_MIN_DELTA, SYSTIMER_MAX_DELTA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TIMER_OF_DECLARE(rtk_systimer, "realtek,rtd1625-systimer", rtk_systimer_init);
|
||||
|
|
@ -21,6 +21,10 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/sched_clock.h>
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
#include <linux/delay.h>
|
||||
#endif
|
||||
|
||||
#include "timer-sp.h"
|
||||
|
||||
/* Hisilicon 64-bit timer(a variant of ARM SP804) */
|
||||
|
|
@ -102,6 +106,23 @@ static u64 notrace sp804_read(void)
|
|||
return ~readl_relaxed(sched_clkevt->value);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
static struct delay_timer delay;
|
||||
static unsigned long sp804_read_delay_timer_read(void)
|
||||
{
|
||||
return sp804_read();
|
||||
}
|
||||
|
||||
static void sp804_register_delay_timer(int freq)
|
||||
{
|
||||
delay.freq = freq;
|
||||
delay.read_current_timer = sp804_read_delay_timer_read;
|
||||
register_current_timer_delay(&delay);
|
||||
}
|
||||
#else
|
||||
static inline void sp804_register_delay_timer(int freq) {}
|
||||
#endif
|
||||
|
||||
static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
||||
const char *name,
|
||||
struct clk *clk,
|
||||
|
|
@ -114,6 +135,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
|||
if (rate < 0)
|
||||
return -EINVAL;
|
||||
|
||||
sp804_register_delay_timer(rate);
|
||||
|
||||
clkevt = sp804_clkevt_get(base);
|
||||
|
||||
writel(0, clkevt->ctrl);
|
||||
|
|
@ -318,6 +341,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
|
|||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#define TIMER_VALUE_SHDW_HI 0x1c
|
||||
|
||||
#define TIMER_VALUE_LO_MASK GENMASK(31, 0)
|
||||
#define TIMER_VALUE_HI_MASK GENMASK(31, 0)
|
||||
|
||||
static void sprd_timer_enable(void __iomem *base, u32 flag)
|
||||
{
|
||||
|
|
@ -162,15 +163,26 @@ static struct timer_of suspend_to = {
|
|||
|
||||
static u64 sprd_suspend_timer_read(struct clocksource *cs)
|
||||
{
|
||||
return ~(u64)readl_relaxed(timer_of_base(&suspend_to) +
|
||||
TIMER_VALUE_SHDW_LO) & cs->mask;
|
||||
u32 lo, hi;
|
||||
|
||||
do {
|
||||
hi = readl_relaxed(timer_of_base(&suspend_to) +
|
||||
TIMER_VALUE_SHDW_HI);
|
||||
lo = readl_relaxed(timer_of_base(&suspend_to) +
|
||||
TIMER_VALUE_SHDW_LO);
|
||||
} while (hi != readl_relaxed(timer_of_base(&suspend_to) + TIMER_VALUE_SHDW_HI));
|
||||
|
||||
return ~(((u64)hi << 32) | lo);
|
||||
}
|
||||
|
||||
static int sprd_suspend_timer_enable(struct clocksource *cs)
|
||||
{
|
||||
sprd_timer_update_counter(timer_of_base(&suspend_to),
|
||||
TIMER_VALUE_LO_MASK);
|
||||
sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE);
|
||||
writel_relaxed(TIMER_VALUE_LO_MASK,
|
||||
timer_of_base(&suspend_to) + TIMER_LOAD_LO);
|
||||
writel_relaxed(TIMER_VALUE_HI_MASK,
|
||||
timer_of_base(&suspend_to) + TIMER_LOAD_HI);
|
||||
sprd_timer_enable(timer_of_base(&suspend_to),
|
||||
TIMER_CTL_PERIOD_MODE|TIMER_CTL_64BIT_WIDTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -186,7 +198,7 @@ static struct clocksource suspend_clocksource = {
|
|||
.read = sprd_suspend_timer_read,
|
||||
.enable = sprd_suspend_timer_enable,
|
||||
.disable = sprd_suspend_timer_disable,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
.mask = CLOCKSOURCE_MASK(64),
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -289,5 +289,4 @@ static struct platform_driver stm32_clkevent_lp_driver = {
|
|||
};
|
||||
module_platform_driver(stm32_clkevent_lp_driver);
|
||||
|
||||
MODULE_ALIAS("platform:stm32-lptimer-timer");
|
||||
MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
|
||||
|
|
|
|||
Loading…
Reference in New Issue