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: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml
|
||||||
F: drivers/spi/spi-realtek-rtl-snand.c
|
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)
|
REALTEK WIRELESS DRIVER (rtlwifi family)
|
||||||
M: Ping-Ke Shih <pkshih@realtek.com>
|
M: Ping-Ke Shih <pkshih@realtek.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
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
|
Enables the support for NXP System Timer Module found in the
|
||||||
s32g NXP platform series.
|
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
|
endmenu
|
||||||
|
|
|
||||||
|
|
@ -95,3 +95,4 @@ obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o
|
||||||
obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o
|
obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o
|
||||||
obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o
|
obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o
|
||||||
obj-$(CONFIG_NXP_STM_TIMER) += timer-nxp-stm.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 = {
|
.driver = {
|
||||||
.name = "arch-timer-mmio",
|
.name = "arch-timer-mmio",
|
||||||
.of_match_table = arch_timer_mmio_of_table,
|
.of_match_table = arch_timer_mmio_of_table,
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
.probe = arch_timer_mmio_probe,
|
.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 = {
|
static struct platform_driver arch_timer_mmio_acpi_drv = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gtdt-arm-mmio-timer",
|
.name = "gtdt-arm-mmio-timer",
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
.probe = arch_timer_mmio_probe,
|
.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);
|
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 */
|
/* make sure channel is disabled */
|
||||||
sh_cmt_start_stop_ch(ch, 0);
|
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)) {
|
if (ret || sh_cmt_read_cmcnt(ch)) {
|
||||||
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
|
dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
|
||||||
ch->index);
|
ch->index);
|
||||||
ret = -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
goto err1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable channel */
|
/* enable channel */
|
||||||
sh_cmt_start_stop_ch(ch, 1);
|
sh_cmt_start_stop_ch(ch, 1);
|
||||||
return 0;
|
return 0;
|
||||||
err1:
|
|
||||||
/* stop clock */
|
|
||||||
clk_disable(ch->cmt->clk);
|
|
||||||
|
|
||||||
err0:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh_cmt_disable(struct sh_cmt_channel *ch)
|
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 */
|
/* disable interrupts in CMT block */
|
||||||
sh_cmt_write_cmcsr(ch, 0);
|
sh_cmt_write_cmcsr(ch, 0);
|
||||||
|
|
||||||
/* stop clock */
|
|
||||||
clk_disable(ch->cmt->clk);
|
|
||||||
|
|
||||||
dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
|
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;
|
int ret = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
pm_runtime_get_sync(&ch->cmt->pdev->dev);
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&ch->lock, flags);
|
raw_spin_lock_irqsave(&ch->lock, flags);
|
||||||
|
|
||||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
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);
|
sh_cmt_disable(ch);
|
||||||
|
|
||||||
raw_spin_unlock_irqrestore(&ch->lock, flags);
|
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)
|
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);
|
raw_spin_lock_irqsave(&ch->lock, flags);
|
||||||
|
|
||||||
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
|
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||||
pm_runtime_get_sync(&ch->cmt->pdev->dev);
|
|
||||||
ret = sh_cmt_enable(ch);
|
ret = sh_cmt_enable(ch);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -656,10 +632,8 @@ static void sh_cmt_stop_clockevent(struct sh_cmt_channel *ch)
|
||||||
|
|
||||||
ch->flags &= ~FLAG_CLOCKEVENT;
|
ch->flags &= ~FLAG_CLOCKEVENT;
|
||||||
|
|
||||||
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
|
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
|
||||||
sh_cmt_disable(ch);
|
sh_cmt_disable(ch);
|
||||||
pm_runtime_put(&ch->cmt->pdev->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* adjust the timeout to maximum if only clocksource left */
|
/* adjust the timeout to maximum if only clocksource left */
|
||||||
if (ch->flags & FLAG_CLOCKSOURCE)
|
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);
|
mask &= ~(1 << hwidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_disable(cmt->clk);
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, cmt);
|
platform_set_drvdata(pdev, cmt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1183,8 +1155,6 @@ static int sh_cmt_probe(struct platform_device *pdev)
|
||||||
out:
|
out:
|
||||||
if (cmt->has_clockevent || cmt->has_clocksource)
|
if (cmt->has_clockevent || cmt->has_clocksource)
|
||||||
pm_runtime_irq_safe(&pdev->dev);
|
pm_runtime_irq_safe(&pdev->dev);
|
||||||
else
|
|
||||||
pm_runtime_idle(&pdev->dev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -374,9 +374,10 @@ static struct platform_driver nxp_pit_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "nxp-pit",
|
.name = "nxp-pit",
|
||||||
.of_match_table = pit_timer_of_match,
|
.of_match_table = pit_timer_of_match,
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
},
|
},
|
||||||
.probe = pit_timer_probe,
|
.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);
|
TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init);
|
||||||
|
|
|
||||||
|
|
@ -177,14 +177,14 @@ static void nxp_stm_clocksource_resume(struct clocksource *cs)
|
||||||
nxp_stm_clocksource_enable(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;
|
struct stm_timer *stm_timer = data;
|
||||||
|
|
||||||
clocksource_unregister(&stm_timer->cs);
|
clocksource_unregister(&stm_timer->cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer,
|
static int nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer,
|
||||||
const char *name, void __iomem *base, struct clk *clk)
|
const char *name, void __iomem *base, struct clk *clk)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -208,10 +208,8 @@ static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer);
|
ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer);
|
||||||
if (ret) {
|
if (ret)
|
||||||
clocksource_unregister(&stm_timer->cs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
stm_sched_clock = stm_timer;
|
stm_sched_clock = stm_timer;
|
||||||
|
|
||||||
|
|
@ -298,7 +296,7 @@ static void nxp_stm_clockevent_resume(struct clock_event_device *ced)
|
||||||
nxp_stm_module_get(stm_timer);
|
nxp_stm_module_get(stm_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer,
|
static int nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer,
|
||||||
const char *name, void __iomem *base, int irq,
|
const char *name, void __iomem *base, int irq,
|
||||||
struct clk *clk, int cpu)
|
struct clk *clk, int cpu)
|
||||||
{
|
{
|
||||||
|
|
@ -388,7 +386,7 @@ static irqreturn_t nxp_stm_module_interrupt(int irq, void *dev_id)
|
||||||
return IRQ_HANDLED;
|
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 stm_timer *stm_timer;
|
||||||
struct device *dev = &pdev->dev;
|
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);
|
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,
|
.probe = nxp_stm_timer_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "nxp-stm",
|
.name = "nxp-stm",
|
||||||
.of_match_table = nxp_stm_of_match,
|
.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_DESCRIPTION("NXP System Timer Module driver");
|
||||||
MODULE_LICENSE("GPL");
|
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);
|
systick.dev.irq = irq_of_parse_and_map(np, 0);
|
||||||
if (!systick.dev.irq) {
|
if (!systick.dev.irq) {
|
||||||
pr_err("%pOFn: request_irq failed", np);
|
pr_err("%pOFn: request_irq failed", np);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto err_iounmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
|
ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
|
||||||
SYSTICK_FREQ, 301, 16,
|
SYSTICK_FREQ, 301, 16,
|
||||||
clocksource_mmio_readl_up);
|
clocksource_mmio_readl_up);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_free_irq;
|
||||||
|
|
||||||
clockevents_register_device(&systick.dev);
|
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);
|
np, systick.dev.mult, systick.dev.shift);
|
||||||
|
|
||||||
return 0;
|
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);
|
TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched_clock.h>
|
||||||
|
|
||||||
#include "timer-of.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);
|
void __iomem *base = timer_of_base(&rda_ostimer_of);
|
||||||
u32 lo, hi;
|
u32 lo, hi;
|
||||||
|
|
@ -167,6 +168,11 @@ static u64 rda_hwtimer_read(struct clocksource *cs)
|
||||||
return ((u64)hi << 32) | lo;
|
return ((u64)hi << 32) | lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 rda_hwtimer_read(struct clocksource *cs)
|
||||||
|
{
|
||||||
|
return rda_hwtimer_clocksource_read();
|
||||||
|
}
|
||||||
|
|
||||||
static struct clocksource rda_hwtimer_clocksource = {
|
static struct clocksource rda_hwtimer_clocksource = {
|
||||||
.name = "rda-timer",
|
.name = "rda-timer",
|
||||||
.rating = 400,
|
.rating = 400,
|
||||||
|
|
@ -185,6 +191,7 @@ static int __init rda_timer_init(struct device_node *np)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
clocksource_register_hz(&rda_hwtimer_clocksource, rate);
|
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,
|
clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
|
||||||
0x2, UINT_MAX);
|
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/of_irq.h>
|
||||||
#include <linux/sched_clock.h>
|
#include <linux/sched_clock.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "timer-sp.h"
|
#include "timer-sp.h"
|
||||||
|
|
||||||
/* Hisilicon 64-bit timer(a variant of ARM SP804) */
|
/* 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);
|
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,
|
static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
||||||
const char *name,
|
const char *name,
|
||||||
struct clk *clk,
|
struct clk *clk,
|
||||||
|
|
@ -114,6 +135,8 @@ static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
|
||||||
if (rate < 0)
|
if (rate < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
sp804_register_delay_timer(rate);
|
||||||
|
|
||||||
clkevt = sp804_clkevt_get(base);
|
clkevt = sp804_clkevt_get(base);
|
||||||
|
|
||||||
writel(0, clkevt->ctrl);
|
writel(0, clkevt->ctrl);
|
||||||
|
|
@ -318,6 +341,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#define TIMER_VALUE_SHDW_HI 0x1c
|
#define TIMER_VALUE_SHDW_HI 0x1c
|
||||||
|
|
||||||
#define TIMER_VALUE_LO_MASK GENMASK(31, 0)
|
#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)
|
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)
|
static u64 sprd_suspend_timer_read(struct clocksource *cs)
|
||||||
{
|
{
|
||||||
return ~(u64)readl_relaxed(timer_of_base(&suspend_to) +
|
u32 lo, hi;
|
||||||
TIMER_VALUE_SHDW_LO) & cs->mask;
|
|
||||||
|
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)
|
static int sprd_suspend_timer_enable(struct clocksource *cs)
|
||||||
{
|
{
|
||||||
sprd_timer_update_counter(timer_of_base(&suspend_to),
|
writel_relaxed(TIMER_VALUE_LO_MASK,
|
||||||
TIMER_VALUE_LO_MASK);
|
timer_of_base(&suspend_to) + TIMER_LOAD_LO);
|
||||||
sprd_timer_enable(timer_of_base(&suspend_to), TIMER_CTL_PERIOD_MODE);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +198,7 @@ static struct clocksource suspend_clocksource = {
|
||||||
.read = sprd_suspend_timer_read,
|
.read = sprd_suspend_timer_read,
|
||||||
.enable = sprd_suspend_timer_enable,
|
.enable = sprd_suspend_timer_enable,
|
||||||
.disable = sprd_suspend_timer_disable,
|
.disable = sprd_suspend_timer_disable,
|
||||||
.mask = CLOCKSOURCE_MASK(32),
|
.mask = CLOCKSOURCE_MASK(64),
|
||||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
|
.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_platform_driver(stm32_clkevent_lp_driver);
|
||||||
|
|
||||||
MODULE_ALIAS("platform:stm32-lptimer-timer");
|
|
||||||
MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
|
MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue