Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clocksource/drivers: Add Realtek system timer driver

Add a system timer driver for Realtek SoCs.

This driver registers the 1 MHz global hardware counter on Realtek
platforms as a clock event device. Since this hardware counter starts
counting automatically after SoC power-on, no clock initialization is
required. Because the counter does not stop or get affected by CPU power
down, and it supports oneshot mode, it is typically used as a tick
broadcast timer.

Signed-off-by: Hao-Wen Ting <haowen.ting@realtek.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://patch.msgid.link/20251126060110.198330-3-haowen.ting@realtek.com

authored by

Hao-Wen Ting and committed by
Daniel Lezcano
d1780dce 40caba2b

+167
+5
MAINTAINERS
··· 21669 21669 F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml 21670 21670 F: drivers/spi/spi-realtek-rtl-snand.c 21671 21671 21672 + REALTEK SYSTIMER DRIVER 21673 + M: Hao-Wen Ting <haowen.ting@realtek.com> 21674 + S: Maintained 21675 + F: drivers/clocksource/timer-realtek.c 21676 + 21672 21677 REALTEK WIRELESS DRIVER (rtlwifi family) 21673 21678 M: Ping-Ke Shih <pkshih@realtek.com> 21674 21679 L: linux-wireless@vger.kernel.org
+11
drivers/clocksource/Kconfig
··· 782 782 Enables the support for NXP System Timer Module found in the 783 783 s32g NXP platform series. 784 784 785 + config RTK_SYSTIMER 786 + bool "Realtek SYSTIMER support" 787 + depends on ARM || ARM64 788 + depends on ARCH_REALTEK || COMPILE_TEST 789 + select TIMER_OF 790 + help 791 + This option enables the driver that registers the global 1 MHz hardware 792 + counter as a clock event device on Realtek SoCs. Make sure to enable 793 + this option only when building for a Realtek platform or for compilation 794 + testing. 795 + 785 796 endmenu
+1
drivers/clocksource/Makefile
··· 95 95 obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o 96 96 obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o 97 97 obj-$(CONFIG_NXP_STM_TIMER) += timer-nxp-stm.o 98 + obj-$(CONFIG_RTK_SYSTIMER) += timer-realtek.o
+150
drivers/clocksource/timer-realtek.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2025 Realtek Semiconductor Corp. 4 + */ 5 + 6 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 + 8 + #include <linux/irqflags.h> 9 + #include <linux/interrupt.h> 10 + #include "timer-of.h" 11 + 12 + #define ENBL 1 13 + #define DSBL 0 14 + 15 + #define SYSTIMER_RATE 1000000 16 + #define SYSTIMER_MIN_DELTA 0x64 17 + #define SYSTIMER_MAX_DELTA ULONG_MAX 18 + 19 + /* SYSTIMER Register Offset (RTK Internal Use) */ 20 + #define TS_LW_OFST 0x0 21 + #define TS_HW_OFST 0x4 22 + #define TS_CMP_VAL_LW_OFST 0x8 23 + #define TS_CMP_VAL_HW_OFST 0xC 24 + #define TS_CMP_CTRL_OFST 0x10 25 + #define TS_CMP_STAT_OFST 0x14 26 + 27 + /* SYSTIMER CMP CTRL REG Mask */ 28 + #define TS_CMP_EN_MASK 0x1 29 + #define TS_WR_EN0_MASK 0x2 30 + 31 + static void __iomem *systimer_base; 32 + 33 + static u64 rtk_ts64_read(void) 34 + { 35 + u32 low, high; 36 + u64 ts; 37 + 38 + /* Caution: Read LSB word (TS_LW_OFST) first then MSB (TS_HW_OFST) */ 39 + low = readl(systimer_base + TS_LW_OFST); 40 + high = readl(systimer_base + TS_HW_OFST); 41 + ts = ((u64)high << 32) | low; 42 + 43 + return ts; 44 + } 45 + 46 + static void rtk_cmp_value_write(u64 value) 47 + { 48 + u32 high, low; 49 + 50 + low = value & 0xFFFFFFFF; 51 + high = value >> 32; 52 + 53 + writel(high, systimer_base + TS_CMP_VAL_HW_OFST); 54 + writel(low, systimer_base + TS_CMP_VAL_LW_OFST); 55 + } 56 + 57 + static inline void rtk_cmp_en_write(bool cmp_en) 58 + { 59 + u32 val; 60 + 61 + val = TS_WR_EN0_MASK; 62 + if (cmp_en == ENBL) 63 + val |= TS_CMP_EN_MASK; 64 + 65 + writel(val, systimer_base + TS_CMP_CTRL_OFST); 66 + } 67 + 68 + static int rtk_syst_clkevt_next_event(unsigned long cycles, struct clock_event_device *clkevt) 69 + { 70 + u64 cmp_val; 71 + 72 + rtk_cmp_en_write(DSBL); 73 + cmp_val = rtk_ts64_read(); 74 + 75 + /* Set CMP value to current timestamp plus delta_us */ 76 + rtk_cmp_value_write(cmp_val + cycles); 77 + rtk_cmp_en_write(ENBL); 78 + return 0; 79 + } 80 + 81 + static irqreturn_t rtk_ts_match_intr_handler(int irq, void *dev_id) 82 + { 83 + struct clock_event_device *clkevt = dev_id; 84 + void __iomem *reg_base; 85 + u32 val; 86 + 87 + /* Disable TS CMP Match */ 88 + rtk_cmp_en_write(DSBL); 89 + 90 + /* Clear TS CMP INTR */ 91 + reg_base = systimer_base + TS_CMP_STAT_OFST; 92 + val = readl(reg_base) & TS_CMP_EN_MASK; 93 + writel(val | TS_CMP_EN_MASK, reg_base); 94 + clkevt->event_handler(clkevt); 95 + 96 + return IRQ_HANDLED; 97 + } 98 + 99 + static int rtk_syst_shutdown(struct clock_event_device *clkevt) 100 + { 101 + void __iomem *reg_base; 102 + u64 cmp_val = 0; 103 + 104 + /* Disable TS CMP Match */ 105 + rtk_cmp_en_write(DSBL); 106 + /* Set compare value to 0 */ 107 + rtk_cmp_value_write(cmp_val); 108 + 109 + /* Clear TS CMP INTR */ 110 + reg_base = systimer_base + TS_CMP_STAT_OFST; 111 + writel(TS_CMP_EN_MASK, reg_base); 112 + return 0; 113 + } 114 + 115 + static struct timer_of rtk_timer_to = { 116 + .flags = TIMER_OF_IRQ | TIMER_OF_BASE, 117 + 118 + .clkevt = { 119 + .name = "rtk-clkevt", 120 + .rating = 300, 121 + .cpumask = cpu_possible_mask, 122 + .features = CLOCK_EVT_FEAT_DYNIRQ | 123 + CLOCK_EVT_FEAT_ONESHOT, 124 + .set_next_event = rtk_syst_clkevt_next_event, 125 + .set_state_oneshot = rtk_syst_shutdown, 126 + .set_state_shutdown = rtk_syst_shutdown, 127 + }, 128 + 129 + .of_irq = { 130 + .flags = IRQF_TIMER | IRQF_IRQPOLL, 131 + .handler = rtk_ts_match_intr_handler, 132 + }, 133 + }; 134 + 135 + static int __init rtk_systimer_init(struct device_node *node) 136 + { 137 + int ret; 138 + 139 + ret = timer_of_init(node, &rtk_timer_to); 140 + if (ret) 141 + return ret; 142 + 143 + systimer_base = timer_of_base(&rtk_timer_to); 144 + clockevents_config_and_register(&rtk_timer_to.clkevt, SYSTIMER_RATE, 145 + SYSTIMER_MIN_DELTA, SYSTIMER_MAX_DELTA); 146 + 147 + return 0; 148 + } 149 + 150 + TIMER_OF_DECLARE(rtk_systimer, "realtek,rtd1625-systimer", rtk_systimer_init);