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/timer-mediatek: Split out CPUXGPT timers

On MediaTek platforms, CPUXGPT is the source for the AArch64 System
Timer, read through CNTVCT_EL0.

The handling for starting this timer ASAP was introduced in commit
327e93cf9a59 ("clocksource/drivers/timer-mediatek: Implement CPUXGPT timers")
which description also contains an important full explanation of the
reasons why this driver is necessary and cannot be a module.

In preparation for an eventual conversion of timer-mediatek to a
platform_driver that would be possibly built as a module, split out
the CPUXGPT timers driver to a new timer-mediatek-cpux.c driver.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Walter Chang <walter.chang@mediatek.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20230309103913.116775-1-angelogioacchino.delregno@collabora.com

authored by

AngeloGioacchino Del Regno and committed by
Daniel Lezcano
49d576ea fd3f088f

+150 -114
+9
drivers/clocksource/Kconfig
··· 479 479 help 480 480 Support for Mediatek timer driver. 481 481 482 + config MTK_CPUX_TIMER 483 + bool "MediaTek CPUX timer driver" if COMPILE_TEST 484 + depends on HAS_IOMEM 485 + default ARCH_MEDIATEK 486 + select TIMER_OF 487 + select CLKSRC_MMIO 488 + help 489 + Support for MediaTek CPUXGPT timer driver. 490 + 482 491 config SPRD_TIMER 483 492 bool "Spreadtrum timer driver" if EXPERT 484 493 depends on HAS_IOMEM
+1
drivers/clocksource/Makefile
··· 51 51 obj-$(CONFIG_VF_PIT_TIMER) += timer-vf-pit.o 52 52 obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o 53 53 obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o 54 + obj-$(CONFIG_MTK_CPUX_TIMER) += timer-mediatek-cpux.o 54 55 obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o 55 56 obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o 56 57 obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
+140
drivers/clocksource/timer-mediatek-cpux.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * MediaTek SoCs CPUX General Purpose Timer handling 4 + * 5 + * Based on timer-mediatek.c: 6 + * Copyright (C) 2014 Matthias Brugger <matthias.bgg@gmail.com> 7 + * 8 + * Copyright (C) 2022 Collabora Ltd. 9 + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 10 + */ 11 + 12 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 + 14 + #include <linux/clockchips.h> 15 + #include <linux/clocksource.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/irqreturn.h> 18 + #include <linux/sched_clock.h> 19 + #include <linux/slab.h> 20 + #include "timer-of.h" 21 + 22 + #define TIMER_SYNC_TICKS 3 23 + 24 + /* cpux mcusys wrapper */ 25 + #define CPUX_CON_REG 0x0 26 + #define CPUX_IDX_REG 0x4 27 + 28 + /* cpux */ 29 + #define CPUX_IDX_GLOBAL_CTRL 0x0 30 + #define CPUX_ENABLE BIT(0) 31 + #define CPUX_CLK_DIV_MASK GENMASK(10, 8) 32 + #define CPUX_CLK_DIV1 BIT(8) 33 + #define CPUX_CLK_DIV2 BIT(9) 34 + #define CPUX_CLK_DIV4 BIT(10) 35 + #define CPUX_IDX_GLOBAL_IRQ 0x30 36 + 37 + static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to) 38 + { 39 + writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); 40 + return readl(timer_of_base(to) + CPUX_CON_REG); 41 + } 42 + 43 + static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to) 44 + { 45 + writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); 46 + writel(val, timer_of_base(to) + CPUX_CON_REG); 47 + } 48 + 49 + static void mtk_cpux_set_irq(struct timer_of *to, bool enable) 50 + { 51 + const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask); 52 + u32 val; 53 + 54 + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to); 55 + 56 + if (enable) 57 + val |= *irq_mask; 58 + else 59 + val &= ~(*irq_mask); 60 + 61 + mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to); 62 + } 63 + 64 + static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt) 65 + { 66 + /* Clear any irq */ 67 + mtk_cpux_set_irq(to_timer_of(clkevt), false); 68 + 69 + /* 70 + * Disabling CPUXGPT timer will crash the platform, especially 71 + * if Trusted Firmware is using it (usually, for sleep states), 72 + * so we only mask the IRQ and call it a day. 73 + */ 74 + return 0; 75 + } 76 + 77 + static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt) 78 + { 79 + mtk_cpux_set_irq(to_timer_of(clkevt), true); 80 + return 0; 81 + } 82 + 83 + static struct timer_of to = { 84 + /* 85 + * There are per-cpu interrupts for the CPUX General Purpose Timer 86 + * but since this timer feeds the AArch64 System Timer we can rely 87 + * on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ. 88 + */ 89 + .flags = TIMER_OF_BASE | TIMER_OF_CLOCK, 90 + 91 + .clkevt = { 92 + .name = "mtk-cpuxgpt", 93 + .cpumask = cpu_possible_mask, 94 + .rating = 10, 95 + .set_state_shutdown = mtk_cpux_clkevt_shutdown, 96 + .tick_resume = mtk_cpux_clkevt_resume, 97 + }, 98 + }; 99 + 100 + static int __init mtk_cpux_init(struct device_node *node) 101 + { 102 + u32 freq, val; 103 + int ret; 104 + 105 + /* If this fails, bad things are about to happen... */ 106 + ret = timer_of_init(node, &to); 107 + if (ret) { 108 + WARN(1, "Cannot start CPUX timers.\n"); 109 + return ret; 110 + } 111 + 112 + /* 113 + * Check if we're given a clock with the right frequency for this 114 + * timer, otherwise warn but keep going with the setup anyway, as 115 + * that makes it possible to still boot the kernel, even though 116 + * it may not work correctly (random lockups, etc). 117 + * The reason behind this is that having an early UART may not be 118 + * possible for everyone and this gives a chance to retrieve kmsg 119 + * for eventual debugging even on consumer devices. 120 + */ 121 + freq = timer_of_rate(&to); 122 + if (freq > 13000000) 123 + WARN(1, "Requested unsupported timer frequency %u\n", freq); 124 + 125 + /* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */ 126 + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to); 127 + val &= ~CPUX_CLK_DIV_MASK; 128 + val |= CPUX_CLK_DIV2; 129 + mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to); 130 + 131 + /* Enable all CPUXGPT timers */ 132 + val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to); 133 + mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to); 134 + 135 + clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 136 + TIMER_SYNC_TICKS, 0xffffffff); 137 + 138 + return 0; 139 + } 140 + TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init);
-114
drivers/clocksource/timer-mediatek.c
··· 22 22 23 23 #define TIMER_SYNC_TICKS (3) 24 24 25 - /* cpux mcusys wrapper */ 26 - #define CPUX_CON_REG 0x0 27 - #define CPUX_IDX_REG 0x4 28 - 29 - /* cpux */ 30 - #define CPUX_IDX_GLOBAL_CTRL 0x0 31 - #define CPUX_ENABLE BIT(0) 32 - #define CPUX_CLK_DIV_MASK GENMASK(10, 8) 33 - #define CPUX_CLK_DIV1 BIT(8) 34 - #define CPUX_CLK_DIV2 BIT(9) 35 - #define CPUX_CLK_DIV4 BIT(10) 36 - #define CPUX_IDX_GLOBAL_IRQ 0x30 37 - 38 25 /* gpt */ 39 26 #define GPT_IRQ_EN_REG 0x00 40 27 #define GPT_IRQ_ENABLE(val) BIT((val) - 1) ··· 71 84 #define SYST_CON_IRQ_CLR BIT(4) 72 85 73 86 static void __iomem *gpt_sched_reg __read_mostly; 74 - 75 - static u32 mtk_cpux_readl(u32 reg_idx, struct timer_of *to) 76 - { 77 - writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); 78 - return readl(timer_of_base(to) + CPUX_CON_REG); 79 - } 80 - 81 - static void mtk_cpux_writel(u32 val, u32 reg_idx, struct timer_of *to) 82 - { 83 - writel(reg_idx, timer_of_base(to) + CPUX_IDX_REG); 84 - writel(val, timer_of_base(to) + CPUX_CON_REG); 85 - } 86 - 87 - static void mtk_cpux_set_irq(struct timer_of *to, bool enable) 88 - { 89 - const unsigned long *irq_mask = cpumask_bits(cpu_possible_mask); 90 - u32 val; 91 - 92 - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ, to); 93 - 94 - if (enable) 95 - val |= *irq_mask; 96 - else 97 - val &= ~(*irq_mask); 98 - 99 - mtk_cpux_writel(val, CPUX_IDX_GLOBAL_IRQ, to); 100 - } 101 - 102 - static int mtk_cpux_clkevt_shutdown(struct clock_event_device *clkevt) 103 - { 104 - /* Clear any irq */ 105 - mtk_cpux_set_irq(to_timer_of(clkevt), false); 106 - 107 - /* 108 - * Disabling CPUXGPT timer will crash the platform, especially 109 - * if Trusted Firmware is using it (usually, for sleep states), 110 - * so we only mask the IRQ and call it a day. 111 - */ 112 - return 0; 113 - } 114 - 115 - static int mtk_cpux_clkevt_resume(struct clock_event_device *clkevt) 116 - { 117 - mtk_cpux_set_irq(to_timer_of(clkevt), true); 118 - return 0; 119 - } 120 87 121 88 static void mtk_syst_ack_irq(struct timer_of *to) 122 89 { ··· 281 340 }, 282 341 }; 283 342 284 - static int __init mtk_cpux_init(struct device_node *node) 285 - { 286 - static struct timer_of to_cpux; 287 - u32 freq, val; 288 - int ret; 289 - 290 - /* 291 - * There are per-cpu interrupts for the CPUX General Purpose Timer 292 - * but since this timer feeds the AArch64 System Timer we can rely 293 - * on the CPU timer PPIs as well, so we don't declare TIMER_OF_IRQ. 294 - */ 295 - to_cpux.flags = TIMER_OF_BASE | TIMER_OF_CLOCK; 296 - to_cpux.clkevt.name = "mtk-cpuxgpt"; 297 - to_cpux.clkevt.rating = 10; 298 - to_cpux.clkevt.cpumask = cpu_possible_mask; 299 - to_cpux.clkevt.set_state_shutdown = mtk_cpux_clkevt_shutdown; 300 - to_cpux.clkevt.tick_resume = mtk_cpux_clkevt_resume; 301 - 302 - /* If this fails, bad things are about to happen... */ 303 - ret = timer_of_init(node, &to_cpux); 304 - if (ret) { 305 - WARN(1, "Cannot start CPUX timers.\n"); 306 - return ret; 307 - } 308 - 309 - /* 310 - * Check if we're given a clock with the right frequency for this 311 - * timer, otherwise warn but keep going with the setup anyway, as 312 - * that makes it possible to still boot the kernel, even though 313 - * it may not work correctly (random lockups, etc). 314 - * The reason behind this is that having an early UART may not be 315 - * possible for everyone and this gives a chance to retrieve kmsg 316 - * for eventual debugging even on consumer devices. 317 - */ 318 - freq = timer_of_rate(&to_cpux); 319 - if (freq > 13000000) 320 - WARN(1, "Requested unsupported timer frequency %u\n", freq); 321 - 322 - /* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */ 323 - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux); 324 - val &= ~CPUX_CLK_DIV_MASK; 325 - val |= CPUX_CLK_DIV2; 326 - mtk_cpux_writel(val, CPUX_IDX_GLOBAL_CTRL, &to_cpux); 327 - 328 - /* Enable all CPUXGPT timers */ 329 - val = mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL, &to_cpux); 330 - mtk_cpux_writel(val | CPUX_ENABLE, CPUX_IDX_GLOBAL_CTRL, &to_cpux); 331 - 332 - clockevents_config_and_register(&to_cpux.clkevt, timer_of_rate(&to_cpux), 333 - TIMER_SYNC_TICKS, 0xffffffff); 334 - 335 - return 0; 336 - } 337 - 338 343 static int __init mtk_syst_init(struct device_node *node) 339 344 { 340 345 int ret; ··· 339 452 } 340 453 TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_gpt_init); 341 454 TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer", mtk_syst_init); 342 - TIMER_OF_DECLARE(mtk_mt6795, "mediatek,mt6795-systimer", mtk_cpux_init);