* [PATCH v10 0/3] Add timer driver for StarFive JH7110 RISC-V SoC
@ 2024-04-12 8:45 Ziv Xu
2024-04-12 8:45 ` [PATCH v10 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC Ziv Xu
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Ziv Xu @ 2024-04-12 8:45 UTC (permalink / raw)
To: Daniel Lezcano, Thomas Gleixner, Emil Renner Berthing,
Christophe JAILLET
Cc: linux-riscv, devicetree, Rob Herring, Krzysztof Kozlowski,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel,
Walker Chen, Xingyu Wu, linux-kernel, Conor Dooley
This patch serises are to add timer driver for the StarFive JH7110
RISC-V SoC. The first patch adds documentation to describe device
tree bindings. The subsequent patch adds timer driver and support
JH7110 SoC. The last patch adds device node about timer in JH7110
dts.
This timer has four free-running 32 bit counters and runs in 24MHz
clock on StarFive JH7110 SoC. And each channel(counter) triggers
an interrupt when timeout. They support one-shot mode and
continuous-run mode.
This timer is used as global timer and register clockevent for each
CPU core after riscv-timer registration on the StarFive JH7110 SoC.
Changes since v9:
- Rebase on 6.9-rc2.
- checked the return value in the jh7110_timer_start function.
v9: https://lore.kernel.org/all/20240318030649.10413-1-ziv.xu@starfivetech.com/
Changes since v8:
- Rebased on 6.8
- Improved the cpu hot swap startup process of the timer.
- Modified irq request timing to prevent sleep.
- Deleted clockevent suspend and resume function and these
operations are included in cpu hot swap operations.
- Formated data structures.
v8: https://lore.kernel.org/all/20231219145402.7879-1-xingyu.wu@starfivetech.com/
Changes since v7:
- Rebased on 6.7-rc6.
- Modified the Kconfig file and added selection in SOC_STARFIVE.
- Used the timer as a global timer and registered as clockevent
for each CPU core.
- Dropped the timeout function in the interrupt handler callback.
- Changed the way in the functions of jh7110_timer_tick_resume() and
jh7110_timer_resume().
- Dropped the registration of clocksource in the probe.
v7: https://lore.kernel.org/all/20231019053501.46899-1-xingyu.wu@starfivetech.com/
Changes since v6:
- Rebased on 6.6-rc6.
- Used sizeof() instead of the numbers of characters about names.
- Added devm_add_action_or_reset() to release the resets and
clocksources in the case of remove or error in the probe.
- Added flags to check each clocksource is suceessfully registered and
used in the release function.
- Dropped the variable of irq in the jh7110_clkevt struct.
- Dropped the wrappers and used enum definitions and writel() calls
directly.
v6: https://lore.kernel.org/all/20231012081015.33121-1-xingyu.wu@starfivetech.com/
Changes since v5:
- Rebased on 6.6-rc5.
- Changed the number about characters of name.
- Made the clkevt->periodic to a local variable.
- Dropped the variables of device and base.
- Used clkevt->evt.irq directly and dropped the extra copy of irq.
V5: https://lore.kernel.org/all/20230907053742.250444-1-xingyu.wu@starfivetech.com/
Changes since v4:
- Rebased on 6.5.
- Dropped the useless enum and used value directly when writing
registers.
- Modified the description in Kconfig.
- Add the reviewed tag in patch 3.
v4: https://lore.kernel.org/all/20230814101603.166951-1-xingyu.wu@starfivetech.com/
Changes since v3:
- Rebased on 6.5-rc6
- Dropped the useless enum names like 'JH7110_TIMER_CH_0'.
- Dropped the platform data about JH7110 and used the register offsets
directly.
- Drroped the useless functions of clk_disable_unprepare().
v3: https://lore.kernel.org/all/20230627055313.252519-1-xingyu.wu@starfivetech.com/
Changes since v2:
- Rebased on 6.4-rc7.
- Merged the header file into the c file.
- Renamed the functions from 'starfive_' to 'jh7110_'
- Used function 'clocksource_register_hz' instead of
'clocksource_mmio_init'.
v2: https://lore.kernel.org/all/20230320135433.144832-1-xingyu.wu@starfivetech.com/
Changes since v1:
- Added description about timer and modified properties' description
in dt-bindings.
- Dropped the 'interrupt-names' and 'clock-frequency' in dt-bindings.
- Renamed the functions and added 'starfive_'
- Modified that the driver probe by platform bus.
v1: https://lore.kernel.org/all/20221223094801.181315-1-xingyu.wu@starfivetech.com/
Xingyu Wu (3):
dt-bindings: timer: Add timer for StarFive JH7110 SoC
clocksource: Add JH7110 timer driver
riscv: dts: jh7110: starfive: Add timer node
.../bindings/timer/starfive,jh7110-timer.yaml | 96 +++++
MAINTAINERS | 7 +
arch/riscv/boot/dts/starfive/jh7110.dtsi | 20 +
drivers/clocksource/Kconfig | 11 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-jh7110.c | 345 ++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
7 files changed, 481 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml
create mode 100644 drivers/clocksource/timer-jh7110.c
--
2.17.1
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v10 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC 2024-04-12 8:45 [PATCH v10 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Ziv Xu @ 2024-04-12 8:45 ` Ziv Xu 2024-04-12 8:45 ` [PATCH v10 2/3] clocksource: Add JH7110 timer driver Ziv Xu 2024-04-12 8:45 ` [PATCH v10 3/3] riscv: dts: jh7110: starfive: Add timer node Ziv Xu 2 siblings, 0 replies; 9+ messages in thread From: Ziv Xu @ 2024-04-12 8:45 UTC (permalink / raw) To: Daniel Lezcano, Thomas Gleixner, Emil Renner Berthing, Christophe JAILLET Cc: linux-riscv, devicetree, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel, Conor Dooley From: Xingyu Wu <xingyu.wu@starfivetech.com> Add bindings for the timer on the JH7110 RISC-V SoC by StarFive Technology Ltd. Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> --- .../bindings/timer/starfive,jh7110-timer.yaml | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml diff --git a/Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml b/Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml new file mode 100644 index 000000000000..9a2dac11eb06 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/starfive,jh7110-timer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7110 Timer + +maintainers: + - Xingyu Wu <xingyu.wu@starfivetech.com> + - Samin Guo <samin.guo@starfivetech.com> + +description: + This timer has four free-running 32 bit counters in StarFive JH7110 SoC. + And each channel(counter) triggers an interrupt when timeout. They support + one-shot mode and continuous-run mode. + +properties: + compatible: + const: starfive,jh7110-timer + + reg: + maxItems: 1 + + interrupts: + items: + - description: channel 0 + - description: channel 1 + - description: channel 2 + - description: channel 3 + + clocks: + items: + - description: timer APB + - description: channel 0 + - description: channel 1 + - description: channel 2 + - description: channel 3 + + clock-names: + items: + - const: apb + - const: ch0 + - const: ch1 + - const: ch2 + - const: ch3 + + resets: + items: + - description: timer APB + - description: channel 0 + - description: channel 1 + - description: channel 2 + - description: channel 3 + + reset-names: + items: + - const: apb + - const: ch0 + - const: ch1 + - const: ch2 + - const: ch3 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - reset-names + +additionalProperties: false + +examples: + - | + timer@13050000 { + compatible = "starfive,jh7110-timer"; + reg = <0x13050000 0x10000>; + interrupts = <69>, <70>, <71> ,<72>; + clocks = <&clk 124>, + <&clk 125>, + <&clk 126>, + <&clk 127>, + <&clk 128>; + clock-names = "apb", "ch0", "ch1", + "ch2", "ch3"; + resets = <&rst 117>, + <&rst 118>, + <&rst 119>, + <&rst 120>, + <&rst 121>; + reset-names = "apb", "ch0", "ch1", + "ch2", "ch3"; + }; + -- 2.17.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-04-12 8:45 [PATCH v10 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Ziv Xu 2024-04-12 8:45 ` [PATCH v10 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC Ziv Xu @ 2024-04-12 8:45 ` Ziv Xu 2024-04-30 6:21 ` 回复: " Ziv Xu 2024-04-12 8:45 ` [PATCH v10 3/3] riscv: dts: jh7110: starfive: Add timer node Ziv Xu 2 siblings, 1 reply; 9+ messages in thread From: Ziv Xu @ 2024-04-12 8:45 UTC (permalink / raw) To: Daniel Lezcano, Thomas Gleixner, Emil Renner Berthing, Christophe JAILLET Cc: linux-riscv, devicetree, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel, Conor Dooley From: Xingyu Wu <xingyu.wu@starfivetech.com> Add timer driver for the StarFive JH7110 SoC. This timer has four free-running and independent 32-bit counters. Each channel(counter) can trigger an interrupt when timeout even CPU is sleeping. So this timer is used as global timer and register clockevent for each CPU core after riscv-timer registration on the StarFive JH7110 SoC. Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com> Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> --- MAINTAINERS | 7 + drivers/clocksource/Kconfig | 11 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-jh7110.c | 345 +++++++++++++++++++++++++++++ include/linux/cpuhotplug.h | 1 + 5 files changed, 365 insertions(+) create mode 100644 drivers/clocksource/timer-jh7110.c diff --git a/MAINTAINERS b/MAINTAINERS index 7c121493f43d..ef9b5f5bad9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21043,6 +21043,13 @@ S: Maintained F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml F: sound/soc/starfive/jh7110_tdm.c +STARFIVE JH7110 TIMER DRIVER +M: Samin Guo <samin.guo@starfivetech.com> +M: Xingyu Wu <xingyu.wu@starfivetech.com> +S: Supported +F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml +F: drivers/clocksource/timer-jh7110.c + STARFIVE JH71X0 CLOCK DRIVERS M: Emil Renner Berthing <kernel@esmil.dk> M: Hal Feng <hal.feng@starfivetech.com> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 34faa0320ece..2dc97201dee1 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -641,6 +641,17 @@ config RISCV_TIMER is accessed via both the SBI and the rdcycle instruction. This is required for all RISC-V systems. +config STARFIVE_JH7110_TIMER + bool "Timer for the STARFIVE JH7110 SoC" + depends on ARCH_STARFIVE || COMPILE_TEST + select TIMER_OF + select CLKSRC_MMIO + default ARCH_STARFIVE + help + This enables the timer for StarFive JH7110 SoC. On RISC-V platform, + the system has started RISCV_TIMER, but you can also use this timer + which can provide four channels to do a lot more things on JH7110 SoC. + config CLINT_TIMER bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST depends on GENERIC_SCHED_CLOCK && RISCV diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4bb856e4df55..8dc2f0ea2d0f 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o obj-$(CONFIG_X86_NUMACHIP) += numachip.o obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o +obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o obj-$(CONFIG_CLINT_TIMER) += timer-clint.o obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o diff --git a/drivers/clocksource/timer-jh7110.c b/drivers/clocksource/timer-jh7110.c new file mode 100644 index 000000000000..dc770507f209 --- /dev/null +++ b/drivers/clocksource/timer-jh7110.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Starfive JH7110 Timer driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * + * This timer has four free-running and independent 32-bit counters and runs in 24MHz + * clock on the StarFive JH7110 SoC. Each channel(counter) can trigger an interrupt + * when timeout even CPU is sleeping. They support one-shot mode and continuous-run mode. + * + * Each channel is used as a global timer that serves each cpu core: + * JH7110 Timer Channel 0 -- CPU 0 + * JH7110 Timer Channel 1 -- CPU 1 + * JH7110 Timer Channel 2 -- CPU 2 + * JH7110 Timer Channel 3 -- CPU 3 + */ + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/iopoll.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ +#define JH7110_TIMER_CH_LEN 0x40 +#define JH7110_TIMER_CH_BASE(x) ((x) * JH7110_TIMER_CH_LEN) +#define JH7110_TIMER_CH_MAX 4 + +#define JH7110_DELAY_US 0 +#define JH7110_TIMEOUT_US 10000 +#define JH7110_CLOCKEVENT_RATING 300 +#define JH7110_TIMER_MAX_TICKS 0xffffffff +#define JH7110_TIMER_MIN_TICKS 0xf + +#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status for channel0~4 */ +#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run */ +#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter */ +#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable register */ +#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both reload counter */ +#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ +#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear register */ +#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer interrupt mask register */ + +#define JH7110_TIMER_INT_CLR_ENA BIT(0) +#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) + +#define JH7110_PERCPU_GET_CLKEVT (&jh7110_timer_info.clkevt[smp_processor_id()]) + +/** + * struct jh7110_clkevt - Description of each timer channel + * @clk: Clock of each timer channel + * @rst: Reset of each timer channel + * @base: Virtual address of each timer channel + * @irq: Interrupt number of each timer channel + * @timer_enabled: Enabled flag for each timer channel + * @name: Name of each timer channel + */ +struct jh7110_clkevt { + struct clk *clk; + struct reset_control *rst; + void __iomem *base; + int irq; + bool timer_enabled; + char name[sizeof("jh7110-timer.chX")]; +}; + +struct jh7110_timer_priv { + struct clk *pclk; + struct reset_control *prst; + struct device *dev; + struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; +}; + +static struct jh7110_timer_priv jh7110_timer_info; + +/* 0:continuous-run mode, 1:single-run mode */ +enum jh7110_timer_mode { + JH7110_TIMER_MODE_CONTIN, + JH7110_TIMER_MODE_SINGLE, +}; + +/* Interrupt Mask, 0:Unmask, 1:Mask */ +enum jh7110_timer_int_mask { + JH7110_TIMER_INT_ENA, + JH7110_TIMER_INT_DIS, +}; + +enum jh7110_timer_enable { + JH7110_TIMER_DIS, + JH7110_TIMER_ENA, +}; + +/* + * BIT(0): Read value represent channel int status. + * Write 1 to this bit to clear interrupt. Write 0 has no effects. + * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. + */ +static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt) +{ + u32 value; + int ret; + + /* Waiting interrupt can be cleared */ + ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, value, + !(value & JH7110_TIMER_INT_CLR_AVA_MASK), + JH7110_DELAY_US, JH7110_TIMEOUT_US); + if (!ret) + writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + JH7110_TIMER_INT_CLR); + + return ret; +} + +static int jh7110_timer_start(struct jh7110_clkevt *clkevt) +{ + int ret; + + /* Disable and clear interrupt first */ + writel(JH7110_TIMER_INT_DIS, clkevt->base + JH7110_TIMER_INT_MASK); + ret = jh7110_timer_int_clear(clkevt); + + writel(JH7110_TIMER_INT_ENA, clkevt->base + JH7110_TIMER_INT_MASK); + writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); + + return ret; +} + +static int jh7110_timer_shutdown(struct clock_event_device *evt) +{ + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; + + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); + return jh7110_timer_int_clear(clkevt); +} + +/* IRQ handler for the timer */ +static irqreturn_t jh7110_timer_interrupt(int irq, void *data) +{ + struct clock_event_device *evt = (struct clock_event_device *)data; + struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0]; + u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS); + u8 cpu_id = smp_processor_id(); + + /* Check interrupt status and channel(cpu) ID */ + if (!(reg & BIT(cpu_id))) + return IRQ_NONE; + + clkevt = &jh7110_timer_info.clkevt[cpu_id]; + writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + JH7110_TIMER_INT_CLR)); + + if (evt->event_handler) + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static int jh7110_timer_set_periodic(struct clock_event_device *evt) +{ + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; + + writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL); + return 0; +} + +static int jh7110_timer_set_oneshot(struct clock_event_device *evt) +{ + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; + + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL); + return 0; +} + +static int jh7110_timer_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; + + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL); + writel(next, clkevt->base + JH7110_TIMER_LOAD); + + return jh7110_timer_start(clkevt); +} + +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = { + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = JH7110_CLOCKEVENT_RATING, + .set_state_shutdown = jh7110_timer_shutdown, + .set_state_periodic = jh7110_timer_set_periodic, + .set_state_oneshot = jh7110_timer_set_oneshot, + .set_state_oneshot_stopped = jh7110_timer_shutdown, + .set_next_event = jh7110_timer_set_next_event, +}; + +static int jh7110_timer_dying_cpu(unsigned int cpu) +{ + struct jh7110_timer_priv *priv = &jh7110_timer_info; + + if (!priv->clkevt[cpu].timer_enabled) + return 0; + + writel(JH7110_TIMER_DIS, priv->clkevt[cpu].base + JH7110_TIMER_ENABLE); + jh7110_timer_int_clear(&priv->clkevt[cpu]); + reset_control_assert(priv->clkevt[cpu].rst); + clk_disable_unprepare(priv->clkevt[cpu].clk); + + return 0; +} + +static int jh7110_timer_starting_cpu(unsigned int cpu) +{ + struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, cpu); + struct jh7110_timer_priv *priv = &jh7110_timer_info; + int err; + u32 rate; + + if (cpu >= JH7110_TIMER_CH_MAX) + return -ENOMEM; + + err = clk_prepare_enable(priv->clkevt[cpu].clk); + if (err) + goto err_starting_cpu; + + err = reset_control_deassert(priv->clkevt[cpu].rst); + if (err) + goto err_soft_reset; + + rate = clk_get_rate(priv->clkevt[cpu].clk); + evt->cpumask = cpumask_of(cpu); + evt->irq = priv->clkevt[cpu].irq; + + err = irq_force_affinity(evt->irq, cpumask_of(cpu)); + if (err) + goto err_affinity; + + clockevents_config_and_register(evt, rate, JH7110_TIMER_MIN_TICKS, + JH7110_TIMER_MAX_TICKS); + + /* Use one-shot mode */ + writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + JH7110_TIMER_CTL)); + + priv->clkevt[cpu].timer_enabled = true; + + err = jh7110_timer_start(&priv->clkevt[cpu]); + if (err) + goto err_affinity; + return 0; + +err_affinity: + reset_control_assert(priv->clkevt[cpu].rst); +err_soft_reset: + clk_disable_unprepare(priv->clkevt[cpu].clk); +err_starting_cpu: + free_irq(evt->irq, evt); + return err; +} + +static int jh7110_timer_probe(struct platform_device *pdev) +{ + struct jh7110_timer_priv *priv = &jh7110_timer_info; + struct clock_event_device *evt; + struct jh7110_clkevt *clkevt; + char name[sizeof("chX")]; + int ch; + int ret; + void __iomem *base; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(&pdev->dev, PTR_ERR(base), + "failed to map registers\n"); + + priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); + if (IS_ERR(priv->prst)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), + "failed to get apb reset\n"); + + priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); + if (IS_ERR(priv->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), + "failed to get & enable apb clock\n"); + + ret = reset_control_deassert(priv->prst); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to deassert apb reset\n"); + + for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { + evt = per_cpu_ptr(&jh7110_clock_event, ch); + clkevt = &priv->clkevt[ch]; + snprintf(name, sizeof(name), "ch%d", ch); + + clkevt->base = base + JH7110_TIMER_CH_BASE(ch); + /* Ensure timer is disabled */ + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); + ret = jh7110_timer_int_clear(clkevt); + if (ret) + return ret; + + clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name); + if (IS_ERR(clkevt->rst)) + return PTR_ERR(clkevt->rst); + + clkevt->clk = devm_clk_get(&pdev->dev, name); + if (IS_ERR(clkevt->clk)) + return PTR_ERR(clkevt->clk); + + clkevt->irq = platform_get_irq(pdev, ch); + if (clkevt->irq < 0) + return clkevt->irq; + + snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", ch); + ret = devm_request_irq(&pdev->dev, clkevt->irq, jh7110_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, + clkevt->name, evt); + + if (ret) + return ret; + + clkevt->timer_enabled = false; + } + + return cpuhp_setup_state(CPUHP_AP_JH7110_TIMER_STARTING, + "clockevents/jh7110/timer:starting", + jh7110_timer_starting_cpu, jh7110_timer_dying_cpu); +} + +static const struct of_device_id jh7110_timer_match[] = { + { .compatible = "starfive,jh7110-timer", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, jh7110_timer_match); + +static struct platform_driver jh7110_timer_driver = { + .probe = jh7110_timer_probe, + .driver = { + .name = "jh7110-timer", + .of_match_table = jh7110_timer_match, + }, +}; +module_platform_driver(jh7110_timer_driver); + +MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); +MODULE_DESCRIPTION("StarFive JH7110 timer driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 35e78ddb2b37..4a8b487c327e 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -175,6 +175,7 @@ enum cpuhp_state { CPUHP_AP_CSKY_TIMER_STARTING, CPUHP_AP_TI_GP_TIMER_STARTING, CPUHP_AP_HYPERV_TIMER_STARTING, + CPUHP_AP_JH7110_TIMER_STARTING, /* Must be the last timer callback */ CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, -- 2.17.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-04-12 8:45 ` [PATCH v10 2/3] clocksource: Add JH7110 timer driver Ziv Xu @ 2024-04-30 6:21 ` Ziv Xu 2024-04-30 10:18 ` Emil Renner Berthing 0 siblings, 1 reply; 9+ messages in thread From: Ziv Xu @ 2024-04-30 6:21 UTC (permalink / raw) To: Daniel Lezcano, Thomas Gleixner Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel@vger.kernel.org, Conor Dooley > -----邮件原件----- > 发件人: Ziv Xu > 发送时间: 2024年4月12日 16:46 > 收件人: Daniel Lezcano <daniel.lezcano@linaro.org>; Thomas Gleixner > <tglx@linutronix.de>; Emil Renner Berthing > <emil.renner.berthing@canonical.com>; Christophe JAILLET > <christophe.jaillet@wanadoo.fr> > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob Herring > <robh+dt@kernel.org>; Krzysztof Kozlowski > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; Albert > Ou <aou@eecs.berkeley.edu>; Philipp Zabel <p.zabel@pengutronix.de>; Walker > Chen <walker.chen@starfivetech.com>; Xingyu Wu > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor Dooley > <conor@kernel.org> > 主题: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > From: Xingyu Wu <xingyu.wu@starfivetech.com> > > Add timer driver for the StarFive JH7110 SoC. > > This timer has four free-running and independent 32-bit counters. > Each channel(counter) can trigger an interrupt when timeout even CPU is > sleeping. So this timer is used as global timer and register clockevent for each > CPU core after riscv-timer registration on the StarFive JH7110 SoC. > > Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com> > Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> > --- > MAINTAINERS | 7 + > drivers/clocksource/Kconfig | 11 + > drivers/clocksource/Makefile | 1 + > drivers/clocksource/timer-jh7110.c | 345 +++++++++++++++++++++++++++++ > include/linux/cpuhotplug.h | 1 + > 5 files changed, 365 insertions(+) > create mode 100644 drivers/clocksource/timer-jh7110.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 7c121493f43d..ef9b5f5bad9e 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -21043,6 +21043,13 @@ S: Maintained > F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml > F: sound/soc/starfive/jh7110_tdm.c > > +STARFIVE JH7110 TIMER DRIVER > +M: Samin Guo <samin.guo@starfivetech.com> > +M: Xingyu Wu <xingyu.wu@starfivetech.com> > +S: Supported > +F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml > +F: drivers/clocksource/timer-jh7110.c > + > STARFIVE JH71X0 CLOCK DRIVERS > M: Emil Renner Berthing <kernel@esmil.dk> > M: Hal Feng <hal.feng@starfivetech.com> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index > 34faa0320ece..2dc97201dee1 100644 > --- a/drivers/clocksource/Kconfig > +++ b/drivers/clocksource/Kconfig > @@ -641,6 +641,17 @@ config RISCV_TIMER > is accessed via both the SBI and the rdcycle instruction. This is > required for all RISC-V systems. > > +config STARFIVE_JH7110_TIMER > + bool "Timer for the STARFIVE JH7110 SoC" > + depends on ARCH_STARFIVE || COMPILE_TEST > + select TIMER_OF > + select CLKSRC_MMIO > + default ARCH_STARFIVE > + help > + This enables the timer for StarFive JH7110 SoC. On RISC-V platform, > + the system has started RISCV_TIMER, but you can also use this timer > + which can provide four channels to do a lot more things on JH7110 SoC. > + > config CLINT_TIMER > bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST > depends on GENERIC_SCHED_CLOCK && RISCV diff --git > a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index > 4bb856e4df55..8dc2f0ea2d0f 100644 > --- a/drivers/clocksource/Makefile > +++ b/drivers/clocksource/Makefile > @@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o > obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o > obj-$(CONFIG_X86_NUMACHIP) += numachip.o > obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o > +obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o > obj-$(CONFIG_CLINT_TIMER) += timer-clint.o > obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o > obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o > diff --git a/drivers/clocksource/timer-jh7110.c > b/drivers/clocksource/timer-jh7110.c > new file mode 100644 > index 000000000000..dc770507f209 > --- /dev/null > +++ b/drivers/clocksource/timer-jh7110.c > @@ -0,0 +1,345 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Starfive JH7110 Timer driver > + * > + * Copyright (C) 2023 StarFive Technology Co., Ltd. > + * > + * This timer has four free-running and independent 32-bit counters and > +runs in 24MHz > + * clock on the StarFive JH7110 SoC. Each channel(counter) can trigger > +an interrupt > + * when timeout even CPU is sleeping. They support one-shot mode and > continuous-run mode. > + * > + * Each channel is used as a global timer that serves each cpu core: > + * JH7110 Timer Channel 0 -- CPU 0 > + * JH7110 Timer Channel 1 -- CPU 1 > + * JH7110 Timer Channel 2 -- CPU 2 > + * JH7110 Timer Channel 3 -- CPU 3 > + */ > + > +#include <linux/clk.h> > +#include <linux/clockchips.h> > +#include <linux/cpu.h> > +#include <linux/iopoll.h> > +#include <linux/irq.h> > +#include <linux/platform_device.h> > +#include <linux/reset.h> > + > +/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ > +#define JH7110_TIMER_CH_LEN 0x40 > +#define JH7110_TIMER_CH_BASE(x) ((x) * JH7110_TIMER_CH_LEN) > +#define JH7110_TIMER_CH_MAX 4 > + > +#define JH7110_DELAY_US 0 > +#define JH7110_TIMEOUT_US 10000 > +#define JH7110_CLOCKEVENT_RATING 300 > +#define JH7110_TIMER_MAX_TICKS 0xffffffff > +#define JH7110_TIMER_MIN_TICKS 0xf > + > +#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status > for channel0~4 */ > +#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run > */ > +#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter */ > +#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable register */ > +#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both reload > counter */ > +#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ > +#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear > register */ > +#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer interrupt > mask register */ > + > +#define JH7110_TIMER_INT_CLR_ENA BIT(0) > +#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) > + > +#define JH7110_PERCPU_GET_CLKEVT > (&jh7110_timer_info.clkevt[smp_processor_id()]) > + > +/** > + * struct jh7110_clkevt - Description of each timer channel > + * @clk: Clock of each timer channel > + * @rst: Reset of each timer channel > + * @base: Virtual address of each timer channel > + * @irq: Interrupt number of each timer channel > + * @timer_enabled: Enabled flag for each timer channel > + * @name: Name of each timer channel > + */ > +struct jh7110_clkevt { > + struct clk *clk; > + struct reset_control *rst; > + void __iomem *base; > + int irq; > + bool timer_enabled; > + char name[sizeof("jh7110-timer.chX")]; > +}; > + > +struct jh7110_timer_priv { > + struct clk *pclk; > + struct reset_control *prst; > + struct device *dev; > + struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; > +}; > + > +static struct jh7110_timer_priv jh7110_timer_info; > + > +/* 0:continuous-run mode, 1:single-run mode */ enum jh7110_timer_mode { > + JH7110_TIMER_MODE_CONTIN, > + JH7110_TIMER_MODE_SINGLE, > +}; > + > +/* Interrupt Mask, 0:Unmask, 1:Mask */ > +enum jh7110_timer_int_mask { > + JH7110_TIMER_INT_ENA, > + JH7110_TIMER_INT_DIS, > +}; > + > +enum jh7110_timer_enable { > + JH7110_TIMER_DIS, > + JH7110_TIMER_ENA, > +}; > + > +/* > + * BIT(0): Read value represent channel int status. > + * Write 1 to this bit to clear interrupt. Write 0 has no effects. > + * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. > + */ > +static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt) > +{ > + u32 value; > + int ret; > + > + /* Waiting interrupt can be cleared */ > + ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, > value, > + !(value & JH7110_TIMER_INT_CLR_AVA_MASK), > + JH7110_DELAY_US, JH7110_TIMEOUT_US); > + if (!ret) > + writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + > +JH7110_TIMER_INT_CLR); > + > + return ret; > +} > + > +static int jh7110_timer_start(struct jh7110_clkevt *clkevt) { > + int ret; > + > + /* Disable and clear interrupt first */ > + writel(JH7110_TIMER_INT_DIS, clkevt->base + > JH7110_TIMER_INT_MASK); > + ret = jh7110_timer_int_clear(clkevt); > + > + writel(JH7110_TIMER_INT_ENA, clkevt->base + > JH7110_TIMER_INT_MASK); > + writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); > + > + return ret; > +} > + > +static int jh7110_timer_shutdown(struct clock_event_device *evt) { > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > + > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > + return jh7110_timer_int_clear(clkevt); } > + > +/* IRQ handler for the timer */ > +static irqreturn_t jh7110_timer_interrupt(int irq, void *data) { > + struct clock_event_device *evt = (struct clock_event_device *)data; > + struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0]; > + u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS); > + u8 cpu_id = smp_processor_id(); > + > + /* Check interrupt status and channel(cpu) ID */ > + if (!(reg & BIT(cpu_id))) > + return IRQ_NONE; > + > + clkevt = &jh7110_timer_info.clkevt[cpu_id]; > + writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + > +JH7110_TIMER_INT_CLR)); > + > + if (evt->event_handler) > + evt->event_handler(evt); > + > + return IRQ_HANDLED; > +} > + > +static int jh7110_timer_set_periodic(struct clock_event_device *evt) { > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > + > + writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + > JH7110_TIMER_CTL); > + return 0; > +} > + > +static int jh7110_timer_set_oneshot(struct clock_event_device *evt) { > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > + > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > JH7110_TIMER_CTL); > + return 0; > +} > + > +static int jh7110_timer_set_next_event(unsigned long next, > + struct clock_event_device *evt) { > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > + > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > JH7110_TIMER_CTL); > + writel(next, clkevt->base + JH7110_TIMER_LOAD); > + > + return jh7110_timer_start(clkevt); > +} > + > +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = { > + .features = CLOCK_EVT_FEAT_PERIODIC | > + CLOCK_EVT_FEAT_ONESHOT, > + .rating = JH7110_CLOCKEVENT_RATING, > + .set_state_shutdown = jh7110_timer_shutdown, > + .set_state_periodic = jh7110_timer_set_periodic, > + .set_state_oneshot = jh7110_timer_set_oneshot, > + .set_state_oneshot_stopped = jh7110_timer_shutdown, > + .set_next_event = jh7110_timer_set_next_event, > +}; > + > +static int jh7110_timer_dying_cpu(unsigned int cpu) { > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > + > + if (!priv->clkevt[cpu].timer_enabled) > + return 0; > + > + writel(JH7110_TIMER_DIS, priv->clkevt[cpu].base + > JH7110_TIMER_ENABLE); > + jh7110_timer_int_clear(&priv->clkevt[cpu]); > + reset_control_assert(priv->clkevt[cpu].rst); > + clk_disable_unprepare(priv->clkevt[cpu].clk); > + > + return 0; > +} > + > +static int jh7110_timer_starting_cpu(unsigned int cpu) { > + struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, cpu); > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > + int err; > + u32 rate; > + > + if (cpu >= JH7110_TIMER_CH_MAX) > + return -ENOMEM; > + > + err = clk_prepare_enable(priv->clkevt[cpu].clk); > + if (err) > + goto err_starting_cpu; > + > + err = reset_control_deassert(priv->clkevt[cpu].rst); > + if (err) > + goto err_soft_reset; > + > + rate = clk_get_rate(priv->clkevt[cpu].clk); > + evt->cpumask = cpumask_of(cpu); > + evt->irq = priv->clkevt[cpu].irq; > + > + err = irq_force_affinity(evt->irq, cpumask_of(cpu)); > + if (err) > + goto err_affinity; > + > + clockevents_config_and_register(evt, rate, JH7110_TIMER_MIN_TICKS, > + JH7110_TIMER_MAX_TICKS); > + > + /* Use one-shot mode */ > + writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + > +JH7110_TIMER_CTL)); > + > + priv->clkevt[cpu].timer_enabled = true; > + > + err = jh7110_timer_start(&priv->clkevt[cpu]); > + if (err) > + goto err_affinity; > + return 0; > + > +err_affinity: > + reset_control_assert(priv->clkevt[cpu].rst); > +err_soft_reset: > + clk_disable_unprepare(priv->clkevt[cpu].clk); > +err_starting_cpu: > + free_irq(evt->irq, evt); > + return err; > +} > + > +static int jh7110_timer_probe(struct platform_device *pdev) { > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > + struct clock_event_device *evt; > + struct jh7110_clkevt *clkevt; > + char name[sizeof("chX")]; > + int ch; > + int ret; > + void __iomem *base; > + > + base = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(base)) > + return dev_err_probe(&pdev->dev, PTR_ERR(base), > + "failed to map registers\n"); > + > + priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); > + if (IS_ERR(priv->prst)) > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), > + "failed to get apb reset\n"); > + > + priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); > + if (IS_ERR(priv->pclk)) > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), > + "failed to get & enable apb clock\n"); > + > + ret = reset_control_deassert(priv->prst); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, "failed to deassert apb > +reset\n"); > + > + for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { > + evt = per_cpu_ptr(&jh7110_clock_event, ch); > + clkevt = &priv->clkevt[ch]; > + snprintf(name, sizeof(name), "ch%d", ch); > + > + clkevt->base = base + JH7110_TIMER_CH_BASE(ch); > + /* Ensure timer is disabled */ > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > + ret = jh7110_timer_int_clear(clkevt); > + if (ret) > + return ret; > + > + clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name); > + if (IS_ERR(clkevt->rst)) > + return PTR_ERR(clkevt->rst); > + > + clkevt->clk = devm_clk_get(&pdev->dev, name); > + if (IS_ERR(clkevt->clk)) > + return PTR_ERR(clkevt->clk); > + > + clkevt->irq = platform_get_irq(pdev, ch); > + if (clkevt->irq < 0) > + return clkevt->irq; > + > + snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", > ch); > + ret = devm_request_irq(&pdev->dev, clkevt->irq, > jh7110_timer_interrupt, > + IRQF_TIMER | IRQF_IRQPOLL, > + clkevt->name, evt); > + > + if (ret) > + return ret; > + > + clkevt->timer_enabled = false; > + } > + > + return cpuhp_setup_state(CPUHP_AP_JH7110_TIMER_STARTING, > + "clockevents/jh7110/timer:starting", > + jh7110_timer_starting_cpu, jh7110_timer_dying_cpu); } > + > +static const struct of_device_id jh7110_timer_match[] = { > + { .compatible = "starfive,jh7110-timer", }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, jh7110_timer_match); > + > +static struct platform_driver jh7110_timer_driver = { > + .probe = jh7110_timer_probe, > + .driver = { > + .name = "jh7110-timer", > + .of_match_table = jh7110_timer_match, > + }, > +}; > +module_platform_driver(jh7110_timer_driver); > + > +MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); > +MODULE_DESCRIPTION("StarFive JH7110 timer driver"); > +MODULE_LICENSE("GPL"); > diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index > 35e78ddb2b37..4a8b487c327e 100644 > --- a/include/linux/cpuhotplug.h > +++ b/include/linux/cpuhotplug.h > @@ -175,6 +175,7 @@ enum cpuhp_state { > CPUHP_AP_CSKY_TIMER_STARTING, > CPUHP_AP_TI_GP_TIMER_STARTING, > CPUHP_AP_HYPERV_TIMER_STARTING, > + CPUHP_AP_JH7110_TIMER_STARTING, > /* Must be the last timer callback */ > CPUHP_AP_DUMMY_TIMER_STARTING, > CPUHP_AP_ARM_XEN_STARTING, > -- > 2.17.1 Hi Daniel / Thomas I have submitted new version of patch for jh7110 timer driver. Could you please help to review and give your comments? Thanks a lot! Best regards, Ziv.Xu ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-04-30 6:21 ` 回复: " Ziv Xu @ 2024-04-30 10:18 ` Emil Renner Berthing 2024-05-07 8:37 ` 回复: " Ziv Xu 0 siblings, 1 reply; 9+ messages in thread From: Emil Renner Berthing @ 2024-04-30 10:18 UTC (permalink / raw) To: Ziv Xu, Daniel Lezcano, Thomas Gleixner Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel@vger.kernel.org, Conor Dooley Ziv Xu wrote: > > > > -----邮件原件----- > > 发件人: Ziv Xu > > 发送时间: 2024年4月12日 16:46 > > 收件人: Daniel Lezcano <daniel.lezcano@linaro.org>; Thomas Gleixner > > <tglx@linutronix.de>; Emil Renner Berthing > > <emil.renner.berthing@canonical.com>; Christophe JAILLET > > <christophe.jaillet@wanadoo.fr> > > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob Herring > > <robh+dt@kernel.org>; Krzysztof Kozlowski > > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; Albert > > Ou <aou@eecs.berkeley.edu>; Philipp Zabel <p.zabel@pengutronix.de>; Walker > > Chen <walker.chen@starfivetech.com>; Xingyu Wu > > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor Dooley > > <conor@kernel.org> > > 主题: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > > > From: Xingyu Wu <xingyu.wu@starfivetech.com> > > > > Add timer driver for the StarFive JH7110 SoC. > > > > This timer has four free-running and independent 32-bit counters. > > Each channel(counter) can trigger an interrupt when timeout even CPU is > > sleeping. So this timer is used as global timer and register clockevent for each > > CPU core after riscv-timer registration on the StarFive JH7110 SoC. > > > > Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com> > > Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> > > --- > > MAINTAINERS | 7 + > > drivers/clocksource/Kconfig | 11 + > > drivers/clocksource/Makefile | 1 + > > drivers/clocksource/timer-jh7110.c | 345 +++++++++++++++++++++++++++++ > > include/linux/cpuhotplug.h | 1 + > > 5 files changed, 365 insertions(+) > > create mode 100644 drivers/clocksource/timer-jh7110.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 7c121493f43d..ef9b5f5bad9e 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -21043,6 +21043,13 @@ S: Maintained > > F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml > > F: sound/soc/starfive/jh7110_tdm.c > > > > +STARFIVE JH7110 TIMER DRIVER > > +M: Samin Guo <samin.guo@starfivetech.com> > > +M: Xingyu Wu <xingyu.wu@starfivetech.com> > > +S: Supported > > +F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml > > +F: drivers/clocksource/timer-jh7110.c > > + > > STARFIVE JH71X0 CLOCK DRIVERS > > M: Emil Renner Berthing <kernel@esmil.dk> > > M: Hal Feng <hal.feng@starfivetech.com> > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index > > 34faa0320ece..2dc97201dee1 100644 > > --- a/drivers/clocksource/Kconfig > > +++ b/drivers/clocksource/Kconfig > > @@ -641,6 +641,17 @@ config RISCV_TIMER > > is accessed via both the SBI and the rdcycle instruction. This is > > required for all RISC-V systems. > > > > +config STARFIVE_JH7110_TIMER > > + bool "Timer for the STARFIVE JH7110 SoC" > > + depends on ARCH_STARFIVE || COMPILE_TEST > > + select TIMER_OF > > + select CLKSRC_MMIO > > + default ARCH_STARFIVE > > + help > > + This enables the timer for StarFive JH7110 SoC. On RISC-V platform, > > + the system has started RISCV_TIMER, but you can also use this timer > > + which can provide four channels to do a lot more things on JH7110 SoC. > > + > > config CLINT_TIMER > > bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST > > depends on GENERIC_SCHED_CLOCK && RISCV diff --git > > a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index > > 4bb856e4df55..8dc2f0ea2d0f 100644 > > --- a/drivers/clocksource/Makefile > > +++ b/drivers/clocksource/Makefile > > @@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o > > obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o > > obj-$(CONFIG_X86_NUMACHIP) += numachip.o > > obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o > > +obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o > > obj-$(CONFIG_CLINT_TIMER) += timer-clint.o > > obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o > > obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o > > diff --git a/drivers/clocksource/timer-jh7110.c > > b/drivers/clocksource/timer-jh7110.c > > new file mode 100644 > > index 000000000000..dc770507f209 > > --- /dev/null > > +++ b/drivers/clocksource/timer-jh7110.c > > @@ -0,0 +1,345 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Starfive JH7110 Timer driver > > + * > > + * Copyright (C) 2023 StarFive Technology Co., Ltd. > > + * > > + * This timer has four free-running and independent 32-bit counters and > > +runs in 24MHz > > + * clock on the StarFive JH7110 SoC. Each channel(counter) can trigger > > +an interrupt > > + * when timeout even CPU is sleeping. They support one-shot mode and > > continuous-run mode. > > + * > > + * Each channel is used as a global timer that serves each cpu core: > > + * JH7110 Timer Channel 0 -- CPU 0 > > + * JH7110 Timer Channel 1 -- CPU 1 > > + * JH7110 Timer Channel 2 -- CPU 2 > > + * JH7110 Timer Channel 3 -- CPU 3 > > + */ > > + > > +#include <linux/clk.h> > > +#include <linux/clockchips.h> > > +#include <linux/cpu.h> > > +#include <linux/iopoll.h> > > +#include <linux/irq.h> > > +#include <linux/platform_device.h> > > +#include <linux/reset.h> > > + > > +/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ > > +#define JH7110_TIMER_CH_LEN 0x40 > > +#define JH7110_TIMER_CH_BASE(x) ((x) * JH7110_TIMER_CH_LEN) > > +#define JH7110_TIMER_CH_MAX 4 > > + > > +#define JH7110_DELAY_US 0 > > +#define JH7110_TIMEOUT_US 10000 > > +#define JH7110_CLOCKEVENT_RATING 300 > > +#define JH7110_TIMER_MAX_TICKS 0xffffffff > > +#define JH7110_TIMER_MIN_TICKS 0xf > > + > > +#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status > > for channel0~4 */ > > +#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run > > */ > > +#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter */ > > +#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable register */ > > +#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both reload > > counter */ > > +#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ > > +#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear > > register */ > > +#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer interrupt > > mask register */ > > + > > +#define JH7110_TIMER_INT_CLR_ENA BIT(0) > > +#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) > > + > > +#define JH7110_PERCPU_GET_CLKEVT > > (&jh7110_timer_info.clkevt[smp_processor_id()]) > > + > > +/** > > + * struct jh7110_clkevt - Description of each timer channel > > + * @clk: Clock of each timer channel > > + * @rst: Reset of each timer channel > > + * @base: Virtual address of each timer channel > > + * @irq: Interrupt number of each timer channel > > + * @timer_enabled: Enabled flag for each timer channel > > + * @name: Name of each timer channel > > + */ > > +struct jh7110_clkevt { > > + struct clk *clk; > > + struct reset_control *rst; > > + void __iomem *base; > > + int irq; > > + bool timer_enabled; > > + char name[sizeof("jh7110-timer.chX")]; > > +}; > > + > > +struct jh7110_timer_priv { > > + struct clk *pclk; > > + struct reset_control *prst; > > + struct device *dev; > > + struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; > > +}; > > + > > +static struct jh7110_timer_priv jh7110_timer_info; > > + > > +/* 0:continuous-run mode, 1:single-run mode */ enum jh7110_timer_mode { > > + JH7110_TIMER_MODE_CONTIN, > > + JH7110_TIMER_MODE_SINGLE, > > +}; > > + > > +/* Interrupt Mask, 0:Unmask, 1:Mask */ > > +enum jh7110_timer_int_mask { > > + JH7110_TIMER_INT_ENA, > > + JH7110_TIMER_INT_DIS, > > +}; > > + > > +enum jh7110_timer_enable { > > + JH7110_TIMER_DIS, > > + JH7110_TIMER_ENA, > > +}; > > + > > +/* > > + * BIT(0): Read value represent channel int status. > > + * Write 1 to this bit to clear interrupt. Write 0 has no effects. > > + * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. > > + */ > > +static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt) > > +{ > > + u32 value; > > + int ret; > > + > > + /* Waiting interrupt can be cleared */ > > + ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, > > value, > > + !(value & JH7110_TIMER_INT_CLR_AVA_MASK), > > + JH7110_DELAY_US, JH7110_TIMEOUT_US); > > + if (!ret) > > + writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + > > +JH7110_TIMER_INT_CLR); > > + > > + return ret; > > +} > > + > > +static int jh7110_timer_start(struct jh7110_clkevt *clkevt) { > > + int ret; > > + > > + /* Disable and clear interrupt first */ > > + writel(JH7110_TIMER_INT_DIS, clkevt->base + > > JH7110_TIMER_INT_MASK); > > + ret = jh7110_timer_int_clear(clkevt); > > + > > + writel(JH7110_TIMER_INT_ENA, clkevt->base + > > JH7110_TIMER_INT_MASK); > > + writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); > > + > > + return ret; > > +} > > + > > +static int jh7110_timer_shutdown(struct clock_event_device *evt) { > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > + > > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > > + return jh7110_timer_int_clear(clkevt); } > > + > > +/* IRQ handler for the timer */ > > +static irqreturn_t jh7110_timer_interrupt(int irq, void *data) { > > + struct clock_event_device *evt = (struct clock_event_device *)data; > > + struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0]; > > + u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS); > > + u8 cpu_id = smp_processor_id(); > > + > > + /* Check interrupt status and channel(cpu) ID */ > > + if (!(reg & BIT(cpu_id))) > > + return IRQ_NONE; > > + > > + clkevt = &jh7110_timer_info.clkevt[cpu_id]; > > + writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + > > +JH7110_TIMER_INT_CLR)); > > + > > + if (evt->event_handler) > > + evt->event_handler(evt); > > + > > + return IRQ_HANDLED; > > +} > > + > > +static int jh7110_timer_set_periodic(struct clock_event_device *evt) { > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > + > > + writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + > > JH7110_TIMER_CTL); > > + return 0; > > +} > > + > > +static int jh7110_timer_set_oneshot(struct clock_event_device *evt) { > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > + > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > JH7110_TIMER_CTL); > > + return 0; > > +} > > + > > +static int jh7110_timer_set_next_event(unsigned long next, > > + struct clock_event_device *evt) { > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > + > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > JH7110_TIMER_CTL); > > + writel(next, clkevt->base + JH7110_TIMER_LOAD); > > + > > + return jh7110_timer_start(clkevt); > > +} > > + > > +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = { > > + .features = CLOCK_EVT_FEAT_PERIODIC | > > + CLOCK_EVT_FEAT_ONESHOT, > > + .rating = JH7110_CLOCKEVENT_RATING, > > + .set_state_shutdown = jh7110_timer_shutdown, > > + .set_state_periodic = jh7110_timer_set_periodic, > > + .set_state_oneshot = jh7110_timer_set_oneshot, > > + .set_state_oneshot_stopped = jh7110_timer_shutdown, > > + .set_next_event = jh7110_timer_set_next_event, > > +}; > > + > > +static int jh7110_timer_dying_cpu(unsigned int cpu) { > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > + > > + if (!priv->clkevt[cpu].timer_enabled) > > + return 0; > > + > > + writel(JH7110_TIMER_DIS, priv->clkevt[cpu].base + > > JH7110_TIMER_ENABLE); > > + jh7110_timer_int_clear(&priv->clkevt[cpu]); > > + reset_control_assert(priv->clkevt[cpu].rst); > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > + > > + return 0; > > +} > > + > > +static int jh7110_timer_starting_cpu(unsigned int cpu) { > > + struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, cpu); > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > + int err; > > + u32 rate; > > + > > + if (cpu >= JH7110_TIMER_CH_MAX) > > + return -ENOMEM; > > + > > + err = clk_prepare_enable(priv->clkevt[cpu].clk); > > + if (err) > > + goto err_starting_cpu; > > + > > + err = reset_control_deassert(priv->clkevt[cpu].rst); > > + if (err) > > + goto err_soft_reset; > > + > > + rate = clk_get_rate(priv->clkevt[cpu].clk); > > + evt->cpumask = cpumask_of(cpu); > > + evt->irq = priv->clkevt[cpu].irq; > > + > > + err = irq_force_affinity(evt->irq, cpumask_of(cpu)); > > + if (err) > > + goto err_affinity; > > + > > + clockevents_config_and_register(evt, rate, JH7110_TIMER_MIN_TICKS, > > + JH7110_TIMER_MAX_TICKS); > > + > > + /* Use one-shot mode */ > > + writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + > > +JH7110_TIMER_CTL)); > > + > > + priv->clkevt[cpu].timer_enabled = true; > > + > > + err = jh7110_timer_start(&priv->clkevt[cpu]); > > + if (err) > > + goto err_affinity; > > + return 0; > > + > > +err_affinity: > > + reset_control_assert(priv->clkevt[cpu].rst); > > +err_soft_reset: > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > +err_starting_cpu: > > + free_irq(evt->irq, evt); > > + return err; > > +} > > + > > +static int jh7110_timer_probe(struct platform_device *pdev) { > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > + struct clock_event_device *evt; > > + struct jh7110_clkevt *clkevt; > > + char name[sizeof("chX")]; > > + int ch; > > + int ret; > > + void __iomem *base; > > + > > + base = devm_platform_ioremap_resource(pdev, 0); > > + if (IS_ERR(base)) > > + return dev_err_probe(&pdev->dev, PTR_ERR(base), > > + "failed to map registers\n"); > > + > > + priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); > > + if (IS_ERR(priv->prst)) > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), > > + "failed to get apb reset\n"); > > + > > + priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); > > + if (IS_ERR(priv->pclk)) > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), > > + "failed to get & enable apb clock\n"); > > + > > + ret = reset_control_deassert(priv->prst); > > + if (ret) > > + return dev_err_probe(&pdev->dev, ret, "failed to deassert apb > > +reset\n"); > > + > > + for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { > > + evt = per_cpu_ptr(&jh7110_clock_event, ch); > > + clkevt = &priv->clkevt[ch]; > > + snprintf(name, sizeof(name), "ch%d", ch); > > + > > + clkevt->base = base + JH7110_TIMER_CH_BASE(ch); > > + /* Ensure timer is disabled */ > > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > > + ret = jh7110_timer_int_clear(clkevt); > > + if (ret) > > + return ret; > > + > > + clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name); > > + if (IS_ERR(clkevt->rst)) > > + return PTR_ERR(clkevt->rst); > > + > > + clkevt->clk = devm_clk_get(&pdev->dev, name); > > + if (IS_ERR(clkevt->clk)) > > + return PTR_ERR(clkevt->clk); > > + > > + clkevt->irq = platform_get_irq(pdev, ch); > > + if (clkevt->irq < 0) > > + return clkevt->irq; > > + > > + snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", > > ch); > > + ret = devm_request_irq(&pdev->dev, clkevt->irq, > > jh7110_timer_interrupt, > > + IRQF_TIMER | IRQF_IRQPOLL, > > + clkevt->name, evt); > > + > > + if (ret) > > + return ret; > > + > > + clkevt->timer_enabled = false; > > + } > > + > > + return cpuhp_setup_state(CPUHP_AP_JH7110_TIMER_STARTING, > > + "clockevents/jh7110/timer:starting", > > + jh7110_timer_starting_cpu, jh7110_timer_dying_cpu); } > > + > > +static const struct of_device_id jh7110_timer_match[] = { > > + { .compatible = "starfive,jh7110-timer", }, > > + { /* sentinel */ } > > +}; > > +MODULE_DEVICE_TABLE(of, jh7110_timer_match); > > + > > +static struct platform_driver jh7110_timer_driver = { > > + .probe = jh7110_timer_probe, > > + .driver = { > > + .name = "jh7110-timer", > > + .of_match_table = jh7110_timer_match, > > + }, > > +}; > > +module_platform_driver(jh7110_timer_driver); > > + > > +MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); > > +MODULE_DESCRIPTION("StarFive JH7110 timer driver"); > > +MODULE_LICENSE("GPL"); > > diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index > > 35e78ddb2b37..4a8b487c327e 100644 > > --- a/include/linux/cpuhotplug.h > > +++ b/include/linux/cpuhotplug.h > > @@ -175,6 +175,7 @@ enum cpuhp_state { > > CPUHP_AP_CSKY_TIMER_STARTING, > > CPUHP_AP_TI_GP_TIMER_STARTING, > > CPUHP_AP_HYPERV_TIMER_STARTING, > > + CPUHP_AP_JH7110_TIMER_STARTING, > > /* Must be the last timer callback */ > > CPUHP_AP_DUMMY_TIMER_STARTING, > > CPUHP_AP_ARM_XEN_STARTING, > > -- > > 2.17.1 > > Hi Daniel / Thomas > > I have submitted new version of patch for jh7110 timer driver. Could you please help to review and give your comments? > Thanks a lot! Hi Ziv I tried this on 6.9-rc6 on my VF2. It boots, but very slowly and "choppy". That is it repeatedly runs for <1s and then hangs for about 4s. Does this patch work for you? /Emil ^ permalink raw reply [flat|nested] 9+ messages in thread
* 回复: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-04-30 10:18 ` Emil Renner Berthing @ 2024-05-07 8:37 ` Ziv Xu 2024-05-07 9:54 ` Emil Renner Berthing 0 siblings, 1 reply; 9+ messages in thread From: Ziv Xu @ 2024-05-07 8:37 UTC (permalink / raw) To: Emil Renner Berthing Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel@vger.kernel.org, Conor Dooley, Daniel Lezcano, Thomas Gleixner [-- Attachment #1: Type: text/plain, Size: 19619 bytes --] > -----邮件原件----- > 发件人: Emil Renner Berthing <emil.renner.berthing@canonical.com> > 发送时间: 2024年4月30日 18:19 > 收件人: Ziv Xu <ziv.xu@starfivetech.com>; Daniel Lezcano > <daniel.lezcano@linaro.org>; Thomas Gleixner <tglx@linutronix.de> > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob Herring > <robh+dt@kernel.org>; Krzysztof Kozlowski > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; Albert > Ou <aou@eecs.berkeley.edu>; Philipp Zabel <p.zabel@pengutronix.de>; Walker > Chen <walker.chen@starfivetech.com>; Xingyu Wu > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor Dooley > <conor@kernel.org> > 主题: Re: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > Ziv Xu wrote: > > > > > > > -----邮件原件----- > > > 发件人: Ziv Xu > > > 发送时间: 2024年4月12日 16:46 > > > 收件人: Daniel Lezcano <daniel.lezcano@linaro.org>; Thomas Gleixner > > > <tglx@linutronix.de>; Emil Renner Berthing > > > <emil.renner.berthing@canonical.com>; Christophe JAILLET > > > <christophe.jaillet@wanadoo.fr> > > > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob > > > Herring <robh+dt@kernel.org>; Krzysztof Kozlowski > > > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > > > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; > > > Albert Ou <aou@eecs.berkeley.edu>; Philipp Zabel > > > <p.zabel@pengutronix.de>; Walker Chen > > > <walker.chen@starfivetech.com>; Xingyu Wu > > > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor > > > Dooley <conor@kernel.org> > > > 主题: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > > > > > From: Xingyu Wu <xingyu.wu@starfivetech.com> > > > > > > Add timer driver for the StarFive JH7110 SoC. > > > > > > This timer has four free-running and independent 32-bit counters. > > > Each channel(counter) can trigger an interrupt when timeout even CPU > > > is sleeping. So this timer is used as global timer and register > > > clockevent for each CPU core after riscv-timer registration on the StarFive > JH7110 SoC. > > > > > > Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com> > > > Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> > > > --- > > > MAINTAINERS | 7 + > > > drivers/clocksource/Kconfig | 11 + > > > drivers/clocksource/Makefile | 1 + > > > drivers/clocksource/timer-jh7110.c | 345 > +++++++++++++++++++++++++++++ > > > include/linux/cpuhotplug.h | 1 + > > > 5 files changed, 365 insertions(+) > > > create mode 100644 drivers/clocksource/timer-jh7110.c > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index > > > 7c121493f43d..ef9b5f5bad9e 100644 > > > --- a/MAINTAINERS > > > +++ b/MAINTAINERS > > > @@ -21043,6 +21043,13 @@ S: Maintained > > > F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml > > > F: sound/soc/starfive/jh7110_tdm.c > > > > > > +STARFIVE JH7110 TIMER DRIVER > > > +M: Samin Guo <samin.guo@starfivetech.com> > > > +M: Xingyu Wu <xingyu.wu@starfivetech.com> > > > +S: Supported > > > +F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml > > > +F: drivers/clocksource/timer-jh7110.c > > > + > > > STARFIVE JH71X0 CLOCK DRIVERS > > > M: Emil Renner Berthing <kernel@esmil.dk> > > > M: Hal Feng <hal.feng@starfivetech.com> > > > diff --git a/drivers/clocksource/Kconfig > > > b/drivers/clocksource/Kconfig index > > > 34faa0320ece..2dc97201dee1 100644 > > > --- a/drivers/clocksource/Kconfig > > > +++ b/drivers/clocksource/Kconfig > > > @@ -641,6 +641,17 @@ config RISCV_TIMER > > > is accessed via both the SBI and the rdcycle instruction. This is > > > required for all RISC-V systems. > > > > > > +config STARFIVE_JH7110_TIMER > > > + bool "Timer for the STARFIVE JH7110 SoC" > > > + depends on ARCH_STARFIVE || COMPILE_TEST > > > + select TIMER_OF > > > + select CLKSRC_MMIO > > > + default ARCH_STARFIVE > > > + help > > > + This enables the timer for StarFive JH7110 SoC. On RISC-V platform, > > > + the system has started RISCV_TIMER, but you can also use this > timer > > > + which can provide four channels to do a lot more things on JH7110 > SoC. > > > + > > > config CLINT_TIMER > > > bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST > > > depends on GENERIC_SCHED_CLOCK && RISCV diff --git > > > a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index > > > 4bb856e4df55..8dc2f0ea2d0f 100644 > > > --- a/drivers/clocksource/Makefile > > > +++ b/drivers/clocksource/Makefile > > > @@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += > ingenic-timer.o > > > obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o > > > obj-$(CONFIG_X86_NUMACHIP) += numachip.o > > > obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o > > > +obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o > > > obj-$(CONFIG_CLINT_TIMER) += timer-clint.o > > > obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o > > > obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o > > > diff --git a/drivers/clocksource/timer-jh7110.c > > > b/drivers/clocksource/timer-jh7110.c > > > new file mode 100644 > > > index 000000000000..dc770507f209 > > > --- /dev/null > > > +++ b/drivers/clocksource/timer-jh7110.c > > > @@ -0,0 +1,345 @@ > > > +// SPDX-License-Identifier: GPL-2.0 > > > +/* > > > + * Starfive JH7110 Timer driver > > > + * > > > + * Copyright (C) 2023 StarFive Technology Co., Ltd. > > > + * > > > + * This timer has four free-running and independent 32-bit counters > > > +and runs in 24MHz > > > + * clock on the StarFive JH7110 SoC. Each channel(counter) can > > > +trigger an interrupt > > > + * when timeout even CPU is sleeping. They support one-shot mode > > > +and > > > continuous-run mode. > > > + * > > > + * Each channel is used as a global timer that serves each cpu core: > > > + * JH7110 Timer Channel 0 -- CPU 0 > > > + * JH7110 Timer Channel 1 -- CPU 1 > > > + * JH7110 Timer Channel 2 -- CPU 2 > > > + * JH7110 Timer Channel 3 -- CPU 3 > > > + */ > > > + > > > +#include <linux/clk.h> > > > +#include <linux/clockchips.h> > > > +#include <linux/cpu.h> > > > +#include <linux/iopoll.h> > > > +#include <linux/irq.h> > > > +#include <linux/platform_device.h> > > > +#include <linux/reset.h> > > > + > > > +/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ > > > +#define JH7110_TIMER_CH_LEN 0x40 > > > +#define JH7110_TIMER_CH_BASE(x) ((x) * > JH7110_TIMER_CH_LEN) > > > +#define JH7110_TIMER_CH_MAX 4 > > > + > > > +#define JH7110_DELAY_US 0 > > > +#define JH7110_TIMEOUT_US 10000 > > > +#define JH7110_CLOCKEVENT_RATING 300 > > > +#define JH7110_TIMER_MAX_TICKS 0xffffffff > > > +#define JH7110_TIMER_MIN_TICKS 0xf > > > + > > > +#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt > Status > > > for channel0~4 */ > > > +#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, > 1-single run > > > */ > > > +#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter > */ > > > +#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable > register */ > > > +#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both > reload > > > counter */ > > > +#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ > > > +#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear > > > register */ > > > +#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer > interrupt > > > mask register */ > > > + > > > +#define JH7110_TIMER_INT_CLR_ENA BIT(0) > > > +#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) > > > + > > > +#define JH7110_PERCPU_GET_CLKEVT > > > (&jh7110_timer_info.clkevt[smp_processor_id()]) > > > + > > > +/** > > > + * struct jh7110_clkevt - Description of each timer channel > > > + * @clk: Clock of each timer channel > > > + * @rst: Reset of each timer channel > > > + * @base: Virtual address of each timer channel > > > + * @irq: Interrupt number of each timer channel > > > + * @timer_enabled: Enabled flag for each timer channel > > > + * @name: Name of each timer channel > > > + */ > > > +struct jh7110_clkevt { > > > + struct clk *clk; > > > + struct reset_control *rst; > > > + void __iomem *base; > > > + int irq; > > > + bool timer_enabled; > > > + char name[sizeof("jh7110-timer.chX")]; > > > +}; > > > + > > > +struct jh7110_timer_priv { > > > + struct clk *pclk; > > > + struct reset_control *prst; > > > + struct device *dev; > > > + struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; > > > +}; > > > + > > > +static struct jh7110_timer_priv jh7110_timer_info; > > > + > > > +/* 0:continuous-run mode, 1:single-run mode */ enum jh7110_timer_mode > { > > > + JH7110_TIMER_MODE_CONTIN, > > > + JH7110_TIMER_MODE_SINGLE, > > > +}; > > > + > > > +/* Interrupt Mask, 0:Unmask, 1:Mask */ enum jh7110_timer_int_mask { > > > + JH7110_TIMER_INT_ENA, > > > + JH7110_TIMER_INT_DIS, > > > +}; > > > + > > > +enum jh7110_timer_enable { > > > + JH7110_TIMER_DIS, > > > + JH7110_TIMER_ENA, > > > +}; > > > + > > > +/* > > > + * BIT(0): Read value represent channel int status. > > > + * Write 1 to this bit to clear interrupt. Write 0 has no effects. > > > + * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. > > > + */ > > > +static inline int jh7110_timer_int_clear(struct jh7110_clkevt > > > +*clkevt) { > > > + u32 value; > > > + int ret; > > > + > > > + /* Waiting interrupt can be cleared */ > > > + ret = readl_poll_timeout_atomic(clkevt->base + > > > +JH7110_TIMER_INT_CLR, > > > value, > > > + !(value & JH7110_TIMER_INT_CLR_AVA_MASK), > > > + JH7110_DELAY_US, JH7110_TIMEOUT_US); > > > + if (!ret) > > > + writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + > > > +JH7110_TIMER_INT_CLR); > > > + > > > + return ret; > > > +} > > > + > > > +static int jh7110_timer_start(struct jh7110_clkevt *clkevt) { > > > + int ret; > > > + > > > + /* Disable and clear interrupt first */ > > > + writel(JH7110_TIMER_INT_DIS, clkevt->base + > > > JH7110_TIMER_INT_MASK); > > > + ret = jh7110_timer_int_clear(clkevt); > > > + > > > + writel(JH7110_TIMER_INT_ENA, clkevt->base + > > > JH7110_TIMER_INT_MASK); > > > + writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); > > > + > > > + return ret; > > > +} > > > + > > > +static int jh7110_timer_shutdown(struct clock_event_device *evt) { > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > + > > > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > > > + return jh7110_timer_int_clear(clkevt); } > > > + > > > +/* IRQ handler for the timer */ > > > +static irqreturn_t jh7110_timer_interrupt(int irq, void *data) { > > > + struct clock_event_device *evt = (struct clock_event_device *)data; > > > + struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0]; > > > + u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS); > > > + u8 cpu_id = smp_processor_id(); > > > + > > > + /* Check interrupt status and channel(cpu) ID */ > > > + if (!(reg & BIT(cpu_id))) > > > + return IRQ_NONE; > > > + > > > + clkevt = &jh7110_timer_info.clkevt[cpu_id]; > > > + writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + > > > +JH7110_TIMER_INT_CLR)); > > > + > > > + if (evt->event_handler) > > > + evt->event_handler(evt); > > > + > > > + return IRQ_HANDLED; > > > +} > > > + > > > +static int jh7110_timer_set_periodic(struct clock_event_device *evt) { > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > + > > > + writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + > > > JH7110_TIMER_CTL); > > > + return 0; > > > +} > > > + > > > +static int jh7110_timer_set_oneshot(struct clock_event_device *evt) { > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > + > > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > > JH7110_TIMER_CTL); > > > + return 0; > > > +} > > > + > > > +static int jh7110_timer_set_next_event(unsigned long next, > > > + struct clock_event_device *evt) { > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > + > > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > > JH7110_TIMER_CTL); > > > + writel(next, clkevt->base + JH7110_TIMER_LOAD); > > > + > > > + return jh7110_timer_start(clkevt); } > > > + > > > +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = > { > > > + .features = CLOCK_EVT_FEAT_PERIODIC | > > > + CLOCK_EVT_FEAT_ONESHOT, > > > + .rating = JH7110_CLOCKEVENT_RATING, > > > + .set_state_shutdown = jh7110_timer_shutdown, > > > + .set_state_periodic = jh7110_timer_set_periodic, > > > + .set_state_oneshot = jh7110_timer_set_oneshot, > > > + .set_state_oneshot_stopped = jh7110_timer_shutdown, > > > + .set_next_event = jh7110_timer_set_next_event, > > > +}; > > > + > > > +static int jh7110_timer_dying_cpu(unsigned int cpu) { > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > + > > > + if (!priv->clkevt[cpu].timer_enabled) > > > + return 0; > > > + > > > + writel(JH7110_TIMER_DIS, priv->clkevt[cpu].base + > > > JH7110_TIMER_ENABLE); > > > + jh7110_timer_int_clear(&priv->clkevt[cpu]); > > > + reset_control_assert(priv->clkevt[cpu].rst); > > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > > + > > > + return 0; > > > +} > > > + > > > +static int jh7110_timer_starting_cpu(unsigned int cpu) { > > > + struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, > cpu); > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > + int err; > > > + u32 rate; > > > + > > > + if (cpu >= JH7110_TIMER_CH_MAX) > > > + return -ENOMEM; > > > + > > > + err = clk_prepare_enable(priv->clkevt[cpu].clk); > > > + if (err) > > > + goto err_starting_cpu; > > > + > > > + err = reset_control_deassert(priv->clkevt[cpu].rst); > > > + if (err) > > > + goto err_soft_reset; > > > + > > > + rate = clk_get_rate(priv->clkevt[cpu].clk); > > > + evt->cpumask = cpumask_of(cpu); > > > + evt->irq = priv->clkevt[cpu].irq; > > > + > > > + err = irq_force_affinity(evt->irq, cpumask_of(cpu)); > > > + if (err) > > > + goto err_affinity; > > > + > > > + clockevents_config_and_register(evt, rate, > JH7110_TIMER_MIN_TICKS, > > > + JH7110_TIMER_MAX_TICKS); > > > + > > > + /* Use one-shot mode */ > > > + writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + > > > +JH7110_TIMER_CTL)); > > > + > > > + priv->clkevt[cpu].timer_enabled = true; > > > + > > > + err = jh7110_timer_start(&priv->clkevt[cpu]); > > > + if (err) > > > + goto err_affinity; > > > + return 0; > > > + > > > +err_affinity: > > > + reset_control_assert(priv->clkevt[cpu].rst); > > > +err_soft_reset: > > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > > +err_starting_cpu: > > > + free_irq(evt->irq, evt); > > > + return err; > > > +} > > > + > > > +static int jh7110_timer_probe(struct platform_device *pdev) { > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > + struct clock_event_device *evt; > > > + struct jh7110_clkevt *clkevt; > > > + char name[sizeof("chX")]; > > > + int ch; > > > + int ret; > > > + void __iomem *base; > > > + > > > + base = devm_platform_ioremap_resource(pdev, 0); > > > + if (IS_ERR(base)) > > > + return dev_err_probe(&pdev->dev, PTR_ERR(base), > > > + "failed to map registers\n"); > > > + > > > + priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); > > > + if (IS_ERR(priv->prst)) > > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), > > > + "failed to get apb reset\n"); > > > + > > > + priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); > > > + if (IS_ERR(priv->pclk)) > > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), > > > + "failed to get & enable apb clock\n"); > > > + > > > + ret = reset_control_deassert(priv->prst); > > > + if (ret) > > > + return dev_err_probe(&pdev->dev, ret, "failed to deassert apb > > > +reset\n"); > > > + > > > + for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { > > > + evt = per_cpu_ptr(&jh7110_clock_event, ch); > > > + clkevt = &priv->clkevt[ch]; > > > + snprintf(name, sizeof(name), "ch%d", ch); > > > + > > > + clkevt->base = base + JH7110_TIMER_CH_BASE(ch); > > > + /* Ensure timer is disabled */ > > > + writel(JH7110_TIMER_DIS, clkevt->base + > JH7110_TIMER_ENABLE); > > > + ret = jh7110_timer_int_clear(clkevt); > > > + if (ret) > > > + return ret; > > > + > > > + clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, > name); > > > + if (IS_ERR(clkevt->rst)) > > > + return PTR_ERR(clkevt->rst); > > > + > > > + clkevt->clk = devm_clk_get(&pdev->dev, name); > > > + if (IS_ERR(clkevt->clk)) > > > + return PTR_ERR(clkevt->clk); > > > + > > > + clkevt->irq = platform_get_irq(pdev, ch); > > > + if (clkevt->irq < 0) > > > + return clkevt->irq; > > > + > > > + snprintf(clkevt->name, sizeof(clkevt->name), > "jh7110-timer.ch%d", > > > ch); > > > + ret = devm_request_irq(&pdev->dev, clkevt->irq, > > > jh7110_timer_interrupt, > > > + IRQF_TIMER | IRQF_IRQPOLL, > > > + clkevt->name, evt); > > > + > > > + if (ret) > > > + return ret; > > > + > > > + clkevt->timer_enabled = false; > > > + } > > > + > > > + return cpuhp_setup_state(CPUHP_AP_JH7110_TIMER_STARTING, > > > + "clockevents/jh7110/timer:starting", > > > + jh7110_timer_starting_cpu, > jh7110_timer_dying_cpu); } > > > + > > > +static const struct of_device_id jh7110_timer_match[] = { > > > + { .compatible = "starfive,jh7110-timer", }, > > > + { /* sentinel */ } > > > +}; > > > +MODULE_DEVICE_TABLE(of, jh7110_timer_match); > > > + > > > +static struct platform_driver jh7110_timer_driver = { > > > + .probe = jh7110_timer_probe, > > > + .driver = { > > > + .name = "jh7110-timer", > > > + .of_match_table = jh7110_timer_match, > > > + }, > > > +}; > > > +module_platform_driver(jh7110_timer_driver); > > > + > > > +MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); > > > +MODULE_DESCRIPTION("StarFive JH7110 timer driver"); > > > +MODULE_LICENSE("GPL"); > > > diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h > > > index 35e78ddb2b37..4a8b487c327e 100644 > > > --- a/include/linux/cpuhotplug.h > > > +++ b/include/linux/cpuhotplug.h > > > @@ -175,6 +175,7 @@ enum cpuhp_state { > > > CPUHP_AP_CSKY_TIMER_STARTING, > > > CPUHP_AP_TI_GP_TIMER_STARTING, > > > CPUHP_AP_HYPERV_TIMER_STARTING, > > > + CPUHP_AP_JH7110_TIMER_STARTING, > > > /* Must be the last timer callback */ > > > CPUHP_AP_DUMMY_TIMER_STARTING, > > > CPUHP_AP_ARM_XEN_STARTING, > > > -- > > > 2.17.1 > > > > Hi Daniel / Thomas > > > > I have submitted new version of patch for jh7110 timer driver. Could you please > help to review and give your comments? > > Thanks a lot! > > Hi Ziv > > I tried this on 6.9-rc6 on my VF2. It boots, but very slowly and "choppy". That is > it repeatedly runs for <1s and then hangs for about 4s. > > Does this patch work for you? > > /Emil Hi, Emil I tried this on 6.9-rc7 and 6.9-rc7, but it doesn't reproduce the phenomenon you said. The attachment is the log for 6.9-rc6. Could you please share your config file (starfive_visionfive2_defconfig or .config) with me? Best Regards Ziv Xu [-- Attachment #2: log for 6.9-rc6.txt --] [-- Type: text/plain, Size: 31050 bytes --] StarFive # setenv bootfile vmlinuz; setenv fdt_addr_r 0x48000000; setenv fdt_high 0xffffffffffffffff; setenv fdtcontroladdr 0xffffffffffffffff; setenv initrd_high 0xffffffffffffffff; setenv kernel_addr_r 0x44000000; setenv fileaddr a0000000;setenv kernel_comp_addr_r 0xb0000000; setenv kernel_comp_size 0x10000000;setenv ipaddr 192.168.125.96; setenv serverip 192.168.125.171;setenv ramdisk_addr_r 0x48100000;setenv kernel_comp_addr_r 0xb0000000;setenv kernel_comp_size 0x10000000; StarFive # tftpboot ${fdt_addr_r} ziv/upstream/linux/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb; tftpboot ${kernel_addr_r} ziv/upstream/linux/arch/riscv/boot/Image.gz; tftpboot ${ramdisk_addr_r} ziv/visionfive/initramfs.cpio.gz;booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}; ethernet@16030000 Waiting for PHY auto negotiation to complete...... done Using ethernet@16030000 device TFTP from server 192.168.125.171; our IP address is 192.168.125.96 Filename 'ziv/upstream/linux/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb'. Load address: 0x48000000 Loading: ### 66.4 KiB/s done Bytes transferred = 36396 (8e2c hex) Using ethernet@16030000 device TFTP from server 192.168.125.171; our IP address is 192.168.125.96 Filename 'ziv/upstream/linux/arch/riscv/boot/Image.gz'. Load address: 0x44000000 Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ########## 5.9 MiB/s done Bytes transferred = 6819280 (680dd0 hex) Using ethernet@16030000 device TFTP from server 192.168.125.171; our IP address is 192.168.125.96 Filename 'ziv/visionfive/initramfs.cpio.gz'. Load address: 0x48100000 Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ############################################## 7.2 MiB/s done Bytes transferred = 114215585 (6cecaa1 hex) Uncompressing Kernel Image Moving Image from 0x44000000 to 0x40200000, end=41727000 ## Flattened Device Tree blob at 48000000 Booting using the fdt blob at 0x48000000 Using Device Tree in place at 0000000048000000, end 000000004800be2b Starting kernel ... clk u2_dw_i2c_clk_core already disabled clk u2_dw_i2c_clk_apb already disabled clk u5_dw_i2c_clk_core already disabled clk u5_dw_i2c_clk_apb already disabled Linux version 6.9.0-rc6-00003-g9385b82135ff (ziv@SD-Server) (riscv64-linux-gnu-gcc (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0, GNU ld (GNU Binutils for Ubuntu) 2.30) #17 SMP Tue May 7 16:29:45 CST 2024 Machine model: StarFive VisionFive 2 v1.3B SBI specification v1.0 detected SBI implementation ID=0x1 Version=0x10002 SBI TIME extension detected SBI IPI extension detected SBI RFENCE extension detected SBI SRST extension detected efi: UEFI not found. OF: reserved mem: 0x0000000040000000..0x000000004007ffff (512 KiB) nomap non-reusable opensbi@40000000 Zone ranges: DMA32 [mem 0x0000000040000000-0x00000000ffffffff] Normal [mem 0x0000000100000000-0x000000013fffffff] Movable zone start for each node Early memory node ranges node 0: [mem 0x0000000040000000-0x000000004007ffff] node 0: [mem 0x0000000040080000-0x000000013fffffff] Initmem setup node 0 [mem 0x0000000040000000-0x000000013fffffff] SBI HSM extension detected CPU with hartid=0 is not available riscv: base ISA extensions acdfim riscv: ELF capabilities acdfim percpu: Embedded 20 pages/cpu s42664 r8192 d31064 u81920 pcpu-alloc: s42664 r8192 d31064 u81920 alloc=20*4096 pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3 Kernel command line: console=tty1 console=ttyS0,115200 debug rootwait earlycon=sbi Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes, linear) Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes, linear) Built 1 zonelists, mobility grouping on. Total pages: 1034240 mem auto-init: stack:off, heap alloc:off, heap free:off software IO TLB: area num 4. software IO TLB: mapped [mem 0x00000000fbfff000-0x00000000fffff000] (64MB) Memory: 3929352K/4194304K available (8442K kernel code, 4781K rwdata, 4096K rodata, 2199K init, 339K bss, 264952K reserved, 0K cma-reserved) SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 rcu: Hierarchical RCU implementation. rcu: RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=4. rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies. rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4 NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0 riscv-intc: 64 local interrupts mapped riscv: providing IPIs using SBI IPI extension rcu: srcu_init: Setting srcu_struct sizes based on contention. clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 881590404240 ns sched_clock: 64 bits at 4MHz, resolution 250ns, wraps every 2199023255500ns Calibrating delay loop (skipped), value calculated using timer frequency.. 8.00 BogoMIPS (lpj=16000) pid_max: default: 32768 minimum: 301 Mount-cache hash table entries: 8192 (order: 4, 65536 bytes, linear) Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes, linear) CPU node for /cpus/cpu@0 exist but the possible cpu range is :0-3 ASID allocator disabled (0 bits) rcu: Hierarchical SRCU implementation. rcu: Max phase no-delay instances is 1000. EFI services will not be available. smp: Bringing up secondary CPUs ... smp: Brought up 1 node, 4 CPUs devtmpfs: initialized clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns futex hash table entries: 1024 (order: 4, 65536 bytes, linear) pinctrl core: initialized pinctrl subsystem NET: Registered PF_NETLINK/PF_ROUTE protocol family DMA: preallocated 512 KiB GFP_KERNEL pool for atomic allocations DMA: preallocated 512 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations thermal_sys: Registered thermal governor 'step_wise' cpuidle: using governor menu cpu3: Ratio of byte access time to unaligned word access is 0.01, unaligned accesses are slow cpu1: Ratio of byte access time to unaligned word access is 0.01, unaligned accesses are slow cpu2: Ratio of byte access time to unaligned word access is 0.01, unaligned accesses are slow cpu0: Ratio of byte access time to unaligned word access is 0.01, unaligned accesses are slow CCACHE: 8 banks, 16 ways, sets/bank=256, bytes/block=64 CCACHE: Index of the largest way enabled: 15 platform soc: Fixed dependency cycle(s) with /soc/interrupt-controller@c000000 platform soc: Fixed dependency cycle(s) with /soc/interrupt-controller@c000000 platform 19800000.csi: Fixed dependency cycle(s) with /soc/isp@19840000 platform 19800000.csi: Fixed dependency cycle(s) with /soc/isp@19840000 platform 19840000.isp: Fixed dependency cycle(s) with /soc/csi@19800000 raid6: skipped pq benchmark and selected int64x8 raid6: using intx1 recovery algorithm SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb mc: Linux media interface: v0.10 videodev: Linux video capture interface: v2.00 Advanced Linux Sound Architecture Driver Initialized. vgaarb: loaded clocksource: Switched to clocksource riscv_clocksource NET: Registered PF_INET protocol family IP idents hash table entries: 65536 (order: 7, 524288 bytes, linear) tcp_listen_portaddr_hash hash table entries: 2048 (order: 3, 32768 bytes, linear) Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear) TCP established hash table entries: 32768 (order: 6, 262144 bytes, linear) TCP bind hash table entries: 32768 (order: 8, 1048576 bytes, linear) TCP: Hash tables configured (established 32768 bind 32768) UDP hash table entries: 2048 (order: 4, 65536 bytes, linear) UDP-Lite hash table entries: 2048 (order: 4, 65536 bytes, linear) NET: Registered PF_UNIX/PF_LOCAL protocol family RPC: Registered named UNIX socket transport module. RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp-with-tls transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. PCI: CLS 0 bytes, default 64 Unpacking initramfs... workingset: timestamp_bits=62 max_order=20 bucket_order=0 NFS: Registering the id_resolver key type Key type id_resolver registered Key type id_legacy registered nfs4filelayout_init: NFSv4 File Layout Driver Registering... nfs4flexfilelayout_init: NFSv4 Flexfile Layout Driver Registering... ntfs3: Max link count 4000 jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc. xor: measuring software checksum speed 8regs : 2340 MB/sec 8regs_prefetch : 2336 MB/sec 32regs : 2340 MB/sec 32regs_prefetch : 2333 MB/sec xor: using function: 32regs (2340 MB/sec) Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251) io scheduler bfq registered riscv-plic c000000.interrupt-controller: mapped 136 interrupts with 4 handlers for 9 contexts. Serial: 8250/16550 driver, 6 ports, IRQ sharing disabled random: crng init done loop: module loaded zram: Added device: zram0 Freeing initrd memory: 111536K 4 fixed-partitions partitions found on MTD device 13010000.spi.0 Creating 4 MTD partitions on "13010000.spi.0": 0x000000000000-0x000000080000 : "spl" 0x0000000f0000-0x000000100000 : "uboot-env" 0x000000100000-0x000000500000 : "uboot" 0x000000600000-0x000001000000 : "reserved-data" starfive-dwmac 16030000.ethernet: IRQ sfty not found starfive-dwmac 16030000.ethernet: User ID: 0x41, Synopsys ID: 0x52 starfive-dwmac 16030000.ethernet: DWMAC4/5 starfive-dwmac 16030000.ethernet: DMA HW capability register supported starfive-dwmac 16030000.ethernet: RX Checksum Offload Engine supported starfive-dwmac 16030000.ethernet: Wake-Up On Lan supported starfive-dwmac 16030000.ethernet: TSO supported starfive-dwmac 16030000.ethernet: Enable RX Mitigation via HW Watchdog Timer starfive-dwmac 16030000.ethernet: Enabled L3L4 Flow TC (entries=1) starfive-dwmac 16030000.ethernet: Enabled RFS Flow TC (entries=10) starfive-dwmac 16030000.ethernet: TSO feature enabled starfive-dwmac 16030000.ethernet: Using 40/40 bits DMA host/device width starfive-dwmac 16040000.ethernet: IRQ sfty not found starfive-dwmac 16040000.ethernet: User ID: 0x41, Synopsys ID: 0x52 starfive-dwmac 16040000.ethernet: DWMAC4/5 starfive-dwmac 16040000.ethernet: DMA HW capability register supported starfive-dwmac 16040000.ethernet: RX Checksum Offload Engine supported starfive-dwmac 16040000.ethernet: Wake-Up On Lan supported starfive-dwmac 16040000.ethernet: TSO supported starfive-dwmac 16040000.ethernet: Enable RX Mitigation via HW Watchdog Timer starfive-dwmac 16040000.ethernet: Enabled L3L4 Flow TC (entries=1) starfive-dwmac 16040000.ethernet: Enabled RFS Flow TC (entries=10) starfive-dwmac 16040000.ethernet: TSO feature enabled starfive-dwmac 16040000.ethernet: Using 40/40 bits DMA host/device width usbcore: registered new interface driver uas usbcore: registered new interface driver usb-storage i2c_dev: i2c /dev entries driver sdhci: Secure Digital Host Controller Interface driver sdhci: Copyright(c) Pierre Ossman Synopsys Designware Multimedia Card Interface Driver sdhci-pltfm: SDHCI platform and OF driver helper usbcore: registered new interface driver usbhid usbhid: USB HID core driver riscv-pmu-sbi: SBI PMU extension is available riscv-pmu-sbi: 16 firmware and 4 hardware counters riscv-pmu-sbi: Perf sampling/filtering is not supported as sscof extension is not available NET: Registered PF_INET6 protocol family Segment Routing with IPv6 In-situ OAM (IOAM) with IPv6 NET: Registered PF_PACKET protocol family Key type dns_resolver registered Timer migration: 1 hierarchy levels; 8 children per group; 1 crossnode level Btrfs loaded, zoned=no, fsverity=no CCACHE: DataError @ 0x00000000.08040270 CCACHE: DataFail @ 0x00000000.08040074 pl08xdmac 16008000.dma-controller: initialized 8 virtual memcpy channels pl08xdmac 16008000.dma-controller: initialized 16 virtual slave channels debugfs: Directory '16008000.dma-controller' with parent 'dmaengine' already present! pl08xdmac 16008000.dma-controller: DMA: PL080 rev0 at 0x16008000 irq 30 gpio gpiochip0: Static allocation of GPIO base is deprecated, use dynamic allocation. starfive-jh7110-sys-pinctrl 13040000.pinctrl: StarFive GPIO chip registered 64 GPIOs gpio gpiochip1: Static allocation of GPIO base is deprecated, use dynamic allocation. starfive-jh7110-aon-pinctrl 17020000.pinctrl: StarFive GPIO chip registered 4 GPIOs dw_axi_dmac_platform 16050000.dma-controller: DesignWare AXI DMA Controller, 4 channels printk: legacy console [ttyS0] disabled 10000000.serial: ttyS0 at MMIO 0x10000000 (irq = 33, base_baud = 1500000) is a 16550A printk: legacy console [ttyS0] enabled dwmmc_starfive 16020000.mmc: IDMAC supports 32-bit address mode. designware-i2s 100e0000.i2s: probe with driver designware-i2s failed with error -110 dwmmc_starfive 16020000.mmc: Using internal DMA controller. dwmmc_starfive 16020000.mmc: Version ID is 290a dwmmc_starfive 16020000.mmc: DW MMC controller at irq 40,32 bit host data width,32 deep fifo mmc_host mmc1: card is polling. mmc_host mmc1: Bus speed (slot 0) = 49500000Hz (slot req 400000Hz, actual 399193HZ div = 62) designware-i2s 120c0000.i2s: probe with driver designware-i2s failed with error -110 ssp-pl022 10060000.spi: ARM PL022 driver, device ID: 0x00041022 ssp-pl022 10060000.spi: mapped registers from 0x0000000010060000 to 00000000c0024811 axp20x-i2c 5-0036: AXP20x variant AXP15060 found axp20x-i2c 5-0036: AXP20X driver loaded starfive-dphy-rx 19820000.phy: supply mipi_0p9 not found, using dummy regulator cdns-csi2rx 19800000.csi: probe with driver cdns-csi2rx failed with error -22 cpufreq: cpufreq_online: CPU0: Running at unlisted initial frequency: 1000000 KHz, changing to: 1500000 KHz clk: Disabling unused clocks PM: genpd: Disabling unused power domains ALSA device list: #0: StarFive-PWMDAC-Sound-Card dwmmc_starfive 16010000.mmc: IDMAC supports 32-bit address mode. dwmmc_starfive 16010000.mmc: Using internal DMA controller. dwmmc_starfive 16010000.mmc: Version ID is 290a dwmmc_starfive 16010000.mmc: DW MMC controller at irq 62,32 bit host data width,32 deep fifo mmc_host mmc0: card is non-removable. mmc_host mmc1: Bus speed (slot 0) = 49500000Hz (slot req 300000Hz, actual 298192HZ div = 83) mmc_host mmc1: Bus speed (slot 0) = 49500000Hz (slot req 200000Hz, actual 199596HZ div = 124) mmc_host mmc1: Bus speed (slot 0) = 49500000Hz (slot req 100000Hz, actual 99798HZ div = 248) mmc_host mmc0: Bus speed (slot 0) = 49500000Hz (slot req 400000Hz, actual 399193HZ div = 62) Freeing unused kernel image (initmem) memory: 2196K Checked W+X mappings: passed, no W+X pages found rodata_test: all tests were successful Run /init as init process with arguments: /init with environment: HOME=/ TERM=linux Starting syslogd: OK Starting klogd: OK Running sysctl: OK Populating /dev using udev: udevd[125]: starting version 3.2.10 udevd[126]: starting eudev-3.2.10 mmc_host mmc0: Bus speed (slot 0) = 49500000Hz (slot req 52000000Hz, actual 49500000HZ div = 0) mmc_host mmc0: Bus speed (slot 0) = 49500000Hz (slot req 100000000Hz, actual 49500000HZ div = 0) mmc0: new HS200 MMC card at address 0001 mmcblk0: mmc0:0001 DG4032 29.1 GiB GPT:Primary header thinks Alt. header is not at the end of the disk. GPT:8191999 != 61071359 GPT:Alternate GPT header not at the end of the disk. GPT:8191999 != 61071359 GPT: Use GNU Parted to correct GPT errors. mmcblk0: p1 p2 p3 p4 mmcblk0boot0: mmc0:0001 DG4032 4.00 MiB mmcblk0boot1: mmc0:0001 DG4032 4.00 MiB mmcblk0rpmb: mmc0:0001 DG4032 4.00 MiB, chardev (248:0) done Saving random seed: OK Starting rngd: OK Starting system message bus: dbus[171]: Unknown username "pulse" in message bus configuration file done Starting rpcbind: OK Starting iptables: OK Starting bluetoothd: OK Starting network: OK Starting Network Interface Plugging Daemon:starfive-dwmac 16030000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0 starfive-dwmac 16030000.ethernet eth0: PHY [stmmac-0:00] driver [YT8531 Gigabit Ethernet] (irq=POLL) dwmac4: Master AXI performs fixed burst length starfive-dwmac 16030000.ethernet eth0: No Safety Features support found starfive-dwmac 16030000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported eth0starfive-dwmac 16030000.ethernet eth0: configuring for phy/rgmii-id link mode eth1. Starting ofono ... done. Starting ntpd: starfive-dwmac 16040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-0 starfive-dwmac 16040000.ethernet eth1: PHY [stmmac-1:00] driver [YT8531 Gigabit Ethernet] (irq=POLL) starfive-dwmac 16040000.ethernet: Failed to reset the dma starfive-dwmac 16040000.ethernet eth1: stmmac_hw_setup: DMA engine initialization failed starfive-dwmac 16040000.ethernet eth1: __stmmac_open: Hw setup failed starfive-dwmac 16040000.ethernet eth1: Register MEM_TYPE_PAGE_POOL RxQ-0 starfive-dwmac 16040000.ethernet eth1: PHY [stmmac-1:00] driver [YT8531 Gigabit Ethernet] (irq=POLL) dwmac4: Master AXI performs fixed burst length starfive-dwmac 16040000.ethernet eth1: No Safety Features support found starfive-dwmac 16040000.ethernet eth1: IEEE 1588-2008 Advanced Timestamp supported starfive-dwmac 16040000.ethernet eth1: configuring for phy/rgmii-id link mode OK Starting dropbear sshd: OK Starting multipastarfive-dwmac 16030000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx thd: OK Starting NFS statd: OK Starting NFS services: OK Starting NFS daemon: rpc.nfsd: Unable to access /proc/fs/nfsd errno 2 (No such file or directory). Please try, as root, 'mount -t nfsd nfsd /proc/fs/nfsd' and then restart rpc.nfsd to correct the problem FAIL Starting NFS mountd: OK Starting isp_ctrl_daemon.sh: OK Starting DHCP server: FAIL No PARTLABEL=hibernation! Welcome to Buildroot buildroot login: Welcome to Buildroot buildroot login: root Password: # cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 10: 1049 87 28 619 RISC-V INTC 5 Edge riscv-timer 12: 0 0 0 0 SiFive PLIC 73 Edge dw_axi_dmac_platform 13: 3 0 0 0 SiFive PLIC 111 Edge 17030000.power-controller 14: 90 0 0 0 SiFive PLIC 30 Edge 1600c000.rng 15: 6 0 0 0 SiFive PLIC 25 Edge 13010000.spi 16: 17 0 0 0 SiFive PLIC 7 Edge eth0 17: 0 0 0 0 SiFive PLIC 6 Edge eth0 18: 0 0 0 0 SiFive PLIC 5 Edge eth0 19: 0 0 0 0 SiFive PLIC 78 Edge eth1 20: 0 0 0 0 SiFive PLIC 77 Edge eth1 21: 0 0 0 0 SiFive PLIC 76 Edge eth1 22: 4664 0 0 0 SiFive PLIC 69 Edge jh7110-timer.ch0 23: 0 5602 0 0 SiFive PLIC 70 Edge jh7110-timer.ch1 24: 0 0 5717 0 SiFive PLIC 71 Edge jh7110-timer.ch2 25: 0 0 0 5385 SiFive PLIC 72 Edge jh7110-timer.ch3 26: 0 0 0 0 SiFive PLIC 1 Edge ccache_ecc 27: 1 0 0 0 SiFive PLIC 3 Edge ccache_ecc 28: 1 0 0 0 SiFive PLIC 4 Edge ccache_ecc 29: 0 0 0 0 SiFive PLIC 2 Edge ccache_ecc 30: 0 0 0 0 SiFive PLIC 29 Edge pl08xdmac 33: 164 0 0 0 SiFive PLIC 32 Edge ttyS0 35: 0 0 0 0 SiFive PLIC 108 Edge 10100000.usb 36: 0 0 0 0 SiFive PLIC 110 Edge 10100000.usb 37: 0 0 0 0 SiFive PLIC 92 Edge wr_irq 38: 0 0 0 0 SiFive PLIC 87 Edge isp_irq 39: 0 0 0 0 SiFive PLIC 90 Edge line_irq 40: 383 0 0 0 SiFive PLIC 75 Edge dw-mci 41: 0 0 0 0 SiFive PLIC 38 Edge pl022 42: 0 0 0 0 SiFive PLIC 35 Edge 10030000.i2c 43: 1 0 0 0 SiFive PLIC 37 Edge 10050000.i2c 44: 90 0 0 0 SiFive PLIC 50 Edge 12050000.i2c 45: 0 0 0 0 SiFive PLIC 0 Edge axp15060 61: 0 0 0 0 SiFive PLIC 51 Edge 12060000.i2c 62: 1009 0 0 0 SiFive PLIC 74 Edge dw-mci IPI0: 49 59 73 82 Rescheduling interrupts IPI1: 623 743 810 952 Function call interrupts IPI2: 0 0 0 0 CPU stop interrupts IPI3: 0 0 0 0 CPU stop (for crash dump) interrupts IPI4: 39 61 40 27 IRQ work interrupts IPI5: 0 0 0 0 Timer broadcast interrupts # ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 回复: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-05-07 8:37 ` 回复: " Ziv Xu @ 2024-05-07 9:54 ` Emil Renner Berthing 2024-05-22 9:37 ` 回复: " Ziv Xu 0 siblings, 1 reply; 9+ messages in thread From: Emil Renner Berthing @ 2024-05-07 9:54 UTC (permalink / raw) To: Ziv Xu, Emil Renner Berthing Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel@vger.kernel.org, Conor Dooley, Daniel Lezcano, Thomas Gleixner Ziv Xu wrote: > > > > -----邮件原件----- > > 发件人: Emil Renner Berthing <emil.renner.berthing@canonical.com> > > 发送时间: 2024年4月30日 18:19 > > 收件人: Ziv Xu <ziv.xu@starfivetech.com>; Daniel Lezcano > > <daniel.lezcano@linaro.org>; Thomas Gleixner <tglx@linutronix.de> > > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob Herring > > <robh+dt@kernel.org>; Krzysztof Kozlowski > > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; Albert > > Ou <aou@eecs.berkeley.edu>; Philipp Zabel <p.zabel@pengutronix.de>; Walker > > Chen <walker.chen@starfivetech.com>; Xingyu Wu > > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor Dooley > > <conor@kernel.org> > > 主题: Re: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > > > Ziv Xu wrote: > > > > > > > > > > -----邮件原件----- > > > > 发件人: Ziv Xu > > > > 发送时间: 2024年4月12日 16:46 > > > > 收件人: Daniel Lezcano <daniel.lezcano@linaro.org>; Thomas Gleixner > > > > <tglx@linutronix.de>; Emil Renner Berthing > > > > <emil.renner.berthing@canonical.com>; Christophe JAILLET > > > > <christophe.jaillet@wanadoo.fr> > > > > 抄送: linux-riscv@lists.infradead.org; devicetree@vger.kernel.org; Rob > > > > Herring <robh+dt@kernel.org>; Krzysztof Kozlowski > > > > <krzysztof.kozlowski+dt@linaro.org>; Paul Walmsley > > > > <paul.walmsley@sifive.com>; Palmer Dabbelt <palmer@dabbelt.com>; > > > > Albert Ou <aou@eecs.berkeley.edu>; Philipp Zabel > > > > <p.zabel@pengutronix.de>; Walker Chen > > > > <walker.chen@starfivetech.com>; Xingyu Wu > > > > <xingyu.wu@starfivetech.com>; linux-kernel@vger.kernel.org; Conor > > > > Dooley <conor@kernel.org> > > > > 主题: [PATCH v10 2/3] clocksource: Add JH7110 timer driver > > > > > > > > From: Xingyu Wu <xingyu.wu@starfivetech.com> > > > > > > > > Add timer driver for the StarFive JH7110 SoC. > > > > > > > > This timer has four free-running and independent 32-bit counters. > > > > Each channel(counter) can trigger an interrupt when timeout even CPU > > > > is sleeping. So this timer is used as global timer and register > > > > clockevent for each CPU core after riscv-timer registration on the StarFive > > JH7110 SoC. > > > > > > > > Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com> > > > > Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> > > > > --- > > > > MAINTAINERS | 7 + > > > > drivers/clocksource/Kconfig | 11 + > > > > drivers/clocksource/Makefile | 1 + > > > > drivers/clocksource/timer-jh7110.c | 345 > > +++++++++++++++++++++++++++++ > > > > include/linux/cpuhotplug.h | 1 + > > > > 5 files changed, 365 insertions(+) > > > > create mode 100644 drivers/clocksource/timer-jh7110.c > > > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index > > > > 7c121493f43d..ef9b5f5bad9e 100644 > > > > --- a/MAINTAINERS > > > > +++ b/MAINTAINERS > > > > @@ -21043,6 +21043,13 @@ S: Maintained > > > > F: Documentation/devicetree/bindings/sound/starfive,jh7110-tdm.yaml > > > > F: sound/soc/starfive/jh7110_tdm.c > > > > > > > > +STARFIVE JH7110 TIMER DRIVER > > > > +M: Samin Guo <samin.guo@starfivetech.com> > > > > +M: Xingyu Wu <xingyu.wu@starfivetech.com> > > > > +S: Supported > > > > +F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml > > > > +F: drivers/clocksource/timer-jh7110.c > > > > + > > > > STARFIVE JH71X0 CLOCK DRIVERS > > > > M: Emil Renner Berthing <kernel@esmil.dk> > > > > M: Hal Feng <hal.feng@starfivetech.com> > > > > diff --git a/drivers/clocksource/Kconfig > > > > b/drivers/clocksource/Kconfig index > > > > 34faa0320ece..2dc97201dee1 100644 > > > > --- a/drivers/clocksource/Kconfig > > > > +++ b/drivers/clocksource/Kconfig > > > > @@ -641,6 +641,17 @@ config RISCV_TIMER > > > > is accessed via both the SBI and the rdcycle instruction. This is > > > > required for all RISC-V systems. > > > > > > > > +config STARFIVE_JH7110_TIMER > > > > + bool "Timer for the STARFIVE JH7110 SoC" > > > > + depends on ARCH_STARFIVE || COMPILE_TEST > > > > + select TIMER_OF > > > > + select CLKSRC_MMIO > > > > + default ARCH_STARFIVE > > > > + help > > > > + This enables the timer for StarFive JH7110 SoC. On RISC-V platform, > > > > + the system has started RISCV_TIMER, but you can also use this > > timer > > > > + which can provide four channels to do a lot more things on JH7110 > > SoC. > > > > + > > > > config CLINT_TIMER > > > > bool "CLINT Timer for the RISC-V platform" if COMPILE_TEST > > > > depends on GENERIC_SCHED_CLOCK && RISCV diff --git > > > > a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index > > > > 4bb856e4df55..8dc2f0ea2d0f 100644 > > > > --- a/drivers/clocksource/Makefile > > > > +++ b/drivers/clocksource/Makefile > > > > @@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += > > ingenic-timer.o > > > > obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o > > > > obj-$(CONFIG_X86_NUMACHIP) += numachip.o > > > > obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o > > > > +obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o > > > > obj-$(CONFIG_CLINT_TIMER) += timer-clint.o > > > > obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o > > > > obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o > > > > diff --git a/drivers/clocksource/timer-jh7110.c > > > > b/drivers/clocksource/timer-jh7110.c > > > > new file mode 100644 > > > > index 000000000000..dc770507f209 > > > > --- /dev/null > > > > +++ b/drivers/clocksource/timer-jh7110.c > > > > @@ -0,0 +1,345 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* > > > > + * Starfive JH7110 Timer driver > > > > + * > > > > + * Copyright (C) 2023 StarFive Technology Co., Ltd. > > > > + * > > > > + * This timer has four free-running and independent 32-bit counters > > > > +and runs in 24MHz > > > > + * clock on the StarFive JH7110 SoC. Each channel(counter) can > > > > +trigger an interrupt > > > > + * when timeout even CPU is sleeping. They support one-shot mode > > > > +and > > > > continuous-run mode. > > > > + * > > > > + * Each channel is used as a global timer that serves each cpu core: > > > > + * JH7110 Timer Channel 0 -- CPU 0 > > > > + * JH7110 Timer Channel 1 -- CPU 1 > > > > + * JH7110 Timer Channel 2 -- CPU 2 > > > > + * JH7110 Timer Channel 3 -- CPU 3 > > > > + */ > > > > + > > > > +#include <linux/clk.h> > > > > +#include <linux/clockchips.h> > > > > +#include <linux/cpu.h> > > > > +#include <linux/iopoll.h> > > > > +#include <linux/irq.h> > > > > +#include <linux/platform_device.h> > > > > +#include <linux/reset.h> > > > > + > > > > +/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */ > > > > +#define JH7110_TIMER_CH_LEN 0x40 > > > > +#define JH7110_TIMER_CH_BASE(x) ((x) * > > JH7110_TIMER_CH_LEN) > > > > +#define JH7110_TIMER_CH_MAX 4 > > > > + > > > > +#define JH7110_DELAY_US 0 > > > > +#define JH7110_TIMEOUT_US 10000 > > > > +#define JH7110_CLOCKEVENT_RATING 300 > > > > +#define JH7110_TIMER_MAX_TICKS 0xffffffff > > > > +#define JH7110_TIMER_MIN_TICKS 0xf > > > > + > > > > +#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt > > Status > > > > for channel0~4 */ > > > > +#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, > > 1-single run > > > > */ > > > > +#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter > > */ > > > > +#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable > > register */ > > > > +#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both > > reload > > > > counter */ > > > > +#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */ > > > > +#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear > > > > register */ > > > > +#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer > > interrupt > > > > mask register */ > > > > + > > > > +#define JH7110_TIMER_INT_CLR_ENA BIT(0) > > > > +#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1) > > > > + > > > > +#define JH7110_PERCPU_GET_CLKEVT > > > > (&jh7110_timer_info.clkevt[smp_processor_id()]) > > > > + > > > > +/** > > > > + * struct jh7110_clkevt - Description of each timer channel > > > > + * @clk: Clock of each timer channel > > > > + * @rst: Reset of each timer channel > > > > + * @base: Virtual address of each timer channel > > > > + * @irq: Interrupt number of each timer channel > > > > + * @timer_enabled: Enabled flag for each timer channel > > > > + * @name: Name of each timer channel > > > > + */ > > > > +struct jh7110_clkevt { > > > > + struct clk *clk; > > > > + struct reset_control *rst; > > > > + void __iomem *base; > > > > + int irq; > > > > + bool timer_enabled; > > > > + char name[sizeof("jh7110-timer.chX")]; > > > > +}; > > > > + > > > > +struct jh7110_timer_priv { > > > > + struct clk *pclk; > > > > + struct reset_control *prst; > > > > + struct device *dev; > > > > + struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX]; > > > > +}; > > > > + > > > > +static struct jh7110_timer_priv jh7110_timer_info; > > > > + > > > > +/* 0:continuous-run mode, 1:single-run mode */ enum jh7110_timer_mode > > { > > > > + JH7110_TIMER_MODE_CONTIN, > > > > + JH7110_TIMER_MODE_SINGLE, > > > > +}; > > > > + > > > > +/* Interrupt Mask, 0:Unmask, 1:Mask */ enum jh7110_timer_int_mask { > > > > + JH7110_TIMER_INT_ENA, > > > > + JH7110_TIMER_INT_DIS, > > > > +}; > > > > + > > > > +enum jh7110_timer_enable { > > > > + JH7110_TIMER_DIS, > > > > + JH7110_TIMER_ENA, > > > > +}; > > > > + > > > > +/* > > > > + * BIT(0): Read value represent channel int status. > > > > + * Write 1 to this bit to clear interrupt. Write 0 has no effects. > > > > + * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written. > > > > + */ > > > > +static inline int jh7110_timer_int_clear(struct jh7110_clkevt > > > > +*clkevt) { > > > > + u32 value; > > > > + int ret; > > > > + > > > > + /* Waiting interrupt can be cleared */ > > > > + ret = readl_poll_timeout_atomic(clkevt->base + > > > > +JH7110_TIMER_INT_CLR, > > > > value, > > > > + !(value & JH7110_TIMER_INT_CLR_AVA_MASK), > > > > + JH7110_DELAY_US, JH7110_TIMEOUT_US); > > > > + if (!ret) > > > > + writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + > > > > +JH7110_TIMER_INT_CLR); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int jh7110_timer_start(struct jh7110_clkevt *clkevt) { > > > > + int ret; > > > > + > > > > + /* Disable and clear interrupt first */ > > > > + writel(JH7110_TIMER_INT_DIS, clkevt->base + > > > > JH7110_TIMER_INT_MASK); > > > > + ret = jh7110_timer_int_clear(clkevt); > > > > + > > > > + writel(JH7110_TIMER_INT_ENA, clkevt->base + > > > > JH7110_TIMER_INT_MASK); > > > > + writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int jh7110_timer_shutdown(struct clock_event_device *evt) { > > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > > + > > > > + writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE); > > > > + return jh7110_timer_int_clear(clkevt); } > > > > + > > > > +/* IRQ handler for the timer */ > > > > +static irqreturn_t jh7110_timer_interrupt(int irq, void *data) { > > > > + struct clock_event_device *evt = (struct clock_event_device *)data; > > > > + struct jh7110_clkevt *clkevt = &jh7110_timer_info.clkevt[0]; > > > > + u32 reg = readl(clkevt->base + JH7110_TIMER_INT_STATUS); > > > > + u8 cpu_id = smp_processor_id(); > > > > + > > > > + /* Check interrupt status and channel(cpu) ID */ > > > > + if (!(reg & BIT(cpu_id))) > > > > + return IRQ_NONE; > > > > + > > > > + clkevt = &jh7110_timer_info.clkevt[cpu_id]; > > > > + writel(JH7110_TIMER_INT_CLR_ENA, (clkevt->base + > > > > +JH7110_TIMER_INT_CLR)); > > > > + > > > > + if (evt->event_handler) > > > > + evt->event_handler(evt); > > > > + > > > > + return IRQ_HANDLED; > > > > +} > > > > + > > > > +static int jh7110_timer_set_periodic(struct clock_event_device *evt) { > > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > > + > > > > + writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + > > > > JH7110_TIMER_CTL); > > > > + return 0; > > > > +} > > > > + > > > > +static int jh7110_timer_set_oneshot(struct clock_event_device *evt) { > > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > > + > > > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > > > JH7110_TIMER_CTL); > > > > + return 0; > > > > +} > > > > + > > > > +static int jh7110_timer_set_next_event(unsigned long next, > > > > + struct clock_event_device *evt) { > > > > + struct jh7110_clkevt *clkevt = JH7110_PERCPU_GET_CLKEVT; > > > > + > > > > + writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + > > > > JH7110_TIMER_CTL); > > > > + writel(next, clkevt->base + JH7110_TIMER_LOAD); > > > > + > > > > + return jh7110_timer_start(clkevt); } > > > > + > > > > +static DEFINE_PER_CPU(struct clock_event_device, jh7110_clock_event) = > > { > > > > + .features = CLOCK_EVT_FEAT_PERIODIC | > > > > + CLOCK_EVT_FEAT_ONESHOT, > > > > + .rating = JH7110_CLOCKEVENT_RATING, > > > > + .set_state_shutdown = jh7110_timer_shutdown, > > > > + .set_state_periodic = jh7110_timer_set_periodic, > > > > + .set_state_oneshot = jh7110_timer_set_oneshot, > > > > + .set_state_oneshot_stopped = jh7110_timer_shutdown, > > > > + .set_next_event = jh7110_timer_set_next_event, > > > > +}; > > > > + > > > > +static int jh7110_timer_dying_cpu(unsigned int cpu) { > > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > > + > > > > + if (!priv->clkevt[cpu].timer_enabled) > > > > + return 0; > > > > + > > > > + writel(JH7110_TIMER_DIS, priv->clkevt[cpu].base + > > > > JH7110_TIMER_ENABLE); > > > > + jh7110_timer_int_clear(&priv->clkevt[cpu]); > > > > + reset_control_assert(priv->clkevt[cpu].rst); > > > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int jh7110_timer_starting_cpu(unsigned int cpu) { > > > > + struct clock_event_device *evt = per_cpu_ptr(&jh7110_clock_event, > > cpu); > > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > > + int err; > > > > + u32 rate; > > > > + > > > > + if (cpu >= JH7110_TIMER_CH_MAX) > > > > + return -ENOMEM; > > > > + > > > > + err = clk_prepare_enable(priv->clkevt[cpu].clk); > > > > + if (err) > > > > + goto err_starting_cpu; > > > > + > > > > + err = reset_control_deassert(priv->clkevt[cpu].rst); > > > > + if (err) > > > > + goto err_soft_reset; > > > > + > > > > + rate = clk_get_rate(priv->clkevt[cpu].clk); > > > > + evt->cpumask = cpumask_of(cpu); > > > > + evt->irq = priv->clkevt[cpu].irq; > > > > + > > > > + err = irq_force_affinity(evt->irq, cpumask_of(cpu)); > > > > + if (err) > > > > + goto err_affinity; > > > > + > > > > + clockevents_config_and_register(evt, rate, > > JH7110_TIMER_MIN_TICKS, > > > > + JH7110_TIMER_MAX_TICKS); > > > > + > > > > + /* Use one-shot mode */ > > > > + writel(JH7110_TIMER_MODE_SINGLE, (priv->clkevt[cpu].base + > > > > +JH7110_TIMER_CTL)); > > > > + > > > > + priv->clkevt[cpu].timer_enabled = true; > > > > + > > > > + err = jh7110_timer_start(&priv->clkevt[cpu]); > > > > + if (err) > > > > + goto err_affinity; > > > > + return 0; > > > > + > > > > +err_affinity: > > > > + reset_control_assert(priv->clkevt[cpu].rst); > > > > +err_soft_reset: > > > > + clk_disable_unprepare(priv->clkevt[cpu].clk); > > > > +err_starting_cpu: > > > > + free_irq(evt->irq, evt); > > > > + return err; > > > > +} > > > > + > > > > +static int jh7110_timer_probe(struct platform_device *pdev) { > > > > + struct jh7110_timer_priv *priv = &jh7110_timer_info; > > > > + struct clock_event_device *evt; > > > > + struct jh7110_clkevt *clkevt; > > > > + char name[sizeof("chX")]; > > > > + int ch; > > > > + int ret; > > > > + void __iomem *base; > > > > + > > > > + base = devm_platform_ioremap_resource(pdev, 0); > > > > + if (IS_ERR(base)) > > > > + return dev_err_probe(&pdev->dev, PTR_ERR(base), > > > > + "failed to map registers\n"); > > > > + > > > > + priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb"); > > > > + if (IS_ERR(priv->prst)) > > > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst), > > > > + "failed to get apb reset\n"); > > > > + > > > > + priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb"); > > > > + if (IS_ERR(priv->pclk)) > > > > + return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), > > > > + "failed to get & enable apb clock\n"); > > > > + > > > > + ret = reset_control_deassert(priv->prst); > > > > + if (ret) > > > > + return dev_err_probe(&pdev->dev, ret, "failed to deassert apb > > > > +reset\n"); > > > > + > > > > + for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) { > > > > + evt = per_cpu_ptr(&jh7110_clock_event, ch); > > > > + clkevt = &priv->clkevt[ch]; > > > > + snprintf(name, sizeof(name), "ch%d", ch); > > > > + > > > > + clkevt->base = base + JH7110_TIMER_CH_BASE(ch); > > > > + /* Ensure timer is disabled */ > > > > + writel(JH7110_TIMER_DIS, clkevt->base + > > JH7110_TIMER_ENABLE); > > > > + ret = jh7110_timer_int_clear(clkevt); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, > > name); > > > > + if (IS_ERR(clkevt->rst)) > > > > + return PTR_ERR(clkevt->rst); > > > > + > > > > + clkevt->clk = devm_clk_get(&pdev->dev, name); > > > > + if (IS_ERR(clkevt->clk)) > > > > + return PTR_ERR(clkevt->clk); > > > > + > > > > + clkevt->irq = platform_get_irq(pdev, ch); > > > > + if (clkevt->irq < 0) > > > > + return clkevt->irq; > > > > + > > > > + snprintf(clkevt->name, sizeof(clkevt->name), > > "jh7110-timer.ch%d", > > > > ch); > > > > + ret = devm_request_irq(&pdev->dev, clkevt->irq, > > > > jh7110_timer_interrupt, > > > > + IRQF_TIMER | IRQF_IRQPOLL, > > > > + clkevt->name, evt); > > > > + > > > > + if (ret) > > > > + return ret; > > > > + > > > > + clkevt->timer_enabled = false; > > > > + } > > > > + > > > > + return cpuhp_setup_state(CPUHP_AP_JH7110_TIMER_STARTING, > > > > + "clockevents/jh7110/timer:starting", > > > > + jh7110_timer_starting_cpu, > > jh7110_timer_dying_cpu); } > > > > + > > > > +static const struct of_device_id jh7110_timer_match[] = { > > > > + { .compatible = "starfive,jh7110-timer", }, > > > > + { /* sentinel */ } > > > > +}; > > > > +MODULE_DEVICE_TABLE(of, jh7110_timer_match); > > > > + > > > > +static struct platform_driver jh7110_timer_driver = { > > > > + .probe = jh7110_timer_probe, > > > > + .driver = { > > > > + .name = "jh7110-timer", > > > > + .of_match_table = jh7110_timer_match, > > > > + }, > > > > +}; > > > > +module_platform_driver(jh7110_timer_driver); > > > > + > > > > +MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>"); > > > > +MODULE_DESCRIPTION("StarFive JH7110 timer driver"); > > > > +MODULE_LICENSE("GPL"); > > > > diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h > > > > index 35e78ddb2b37..4a8b487c327e 100644 > > > > --- a/include/linux/cpuhotplug.h > > > > +++ b/include/linux/cpuhotplug.h > > > > @@ -175,6 +175,7 @@ enum cpuhp_state { > > > > CPUHP_AP_CSKY_TIMER_STARTING, > > > > CPUHP_AP_TI_GP_TIMER_STARTING, > > > > CPUHP_AP_HYPERV_TIMER_STARTING, > > > > + CPUHP_AP_JH7110_TIMER_STARTING, > > > > /* Must be the last timer callback */ > > > > CPUHP_AP_DUMMY_TIMER_STARTING, > > > > CPUHP_AP_ARM_XEN_STARTING, > > > > -- > > > > 2.17.1 > > > > > > Hi Daniel / Thomas > > > > > > I have submitted new version of patch for jh7110 timer driver. Could you please > > help to review and give your comments? > > > Thanks a lot! > > > > Hi Ziv > > > > I tried this on 6.9-rc6 on my VF2. It boots, but very slowly and "choppy". That is > > it repeatedly runs for <1s and then hangs for about 4s. > > > > Does this patch work for you? > > > > /Emil > > Hi, Emil > > I tried this on 6.9-rc7 and 6.9-rc7, but it doesn't reproduce the phenomenon you said. > The attachment is the log for 6.9-rc6. Could you please share your config file (starfive_visionfive2_defconfig or .config) with me? Yeah, I just tried again on 6.9-rc7 (+ Conor's riscv-dt-for-next, Minda's PCIe patches and the PWM driver) with this config: https://sprunge.us/kiXXba I don't know if it makes a difference but my also board boots via EFI. /Emil ^ permalink raw reply [flat|nested] 9+ messages in thread
* 回复: 回复: 回复: [PATCH v10 2/3] clocksource: Add JH7110 timer driver 2024-05-07 9:54 ` Emil Renner Berthing @ 2024-05-22 9:37 ` Ziv Xu 0 siblings, 0 replies; 9+ messages in thread From: Ziv Xu @ 2024-05-22 9:37 UTC (permalink / raw) To: Emil Renner Berthing Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel@vger.kernel.org, Conor Dooley, Daniel Lezcano, Thomas Gleixner Emil wrote: > > > > > Hi Daniel / Thomas > > > > > > > > I have submitted new version of patch for jh7110 timer driver. > > > > Could you please > > > help to review and give your comments? > > > > Thanks a lot! > > > > > > Hi Ziv > > > > > > I tried this on 6.9-rc6 on my VF2. It boots, but very slowly and > > > "choppy". That is it repeatedly runs for <1s and then hangs for about 4s. > > > > > > Does this patch work for you? > > > > > > /Emil > > > > Hi, Emil > > > > I tried this on 6.9-rc7 and 6.9-rc7, but it doesn't reproduce the phenomenon > you said. > > The attachment is the log for 6.9-rc6. Could you please share your config file > (starfive_visionfive2_defconfig or .config) with me? > > Yeah, I just tried again on 6.9-rc7 (+ Conor's riscv-dt-for-next, Minda's PCIe > patches and the PWM driver) with this config: > > https://sprunge.us/kiXXba > > I don't know if it makes a difference but my also board boots via EFI. > > /Emil Hi, Emil The cause of booting slowly is that when JH7110-Timer is registered as clockevent device, the soft timer will be pending while the crng tries to generate entropy(try_to_generate_entropy funcition in linux/driver/char/random.c). This can be avoided with setting CONFIG_HW_RANDOM and CONFIG_HW_RANDOM_JH7110 as "y". But I can't find a root casue. Could you please give me some advice? Best Regards Ziv.Xu ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v10 3/3] riscv: dts: jh7110: starfive: Add timer node 2024-04-12 8:45 [PATCH v10 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Ziv Xu 2024-04-12 8:45 ` [PATCH v10 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC Ziv Xu 2024-04-12 8:45 ` [PATCH v10 2/3] clocksource: Add JH7110 timer driver Ziv Xu @ 2024-04-12 8:45 ` Ziv Xu 2 siblings, 0 replies; 9+ messages in thread From: Ziv Xu @ 2024-04-12 8:45 UTC (permalink / raw) To: Daniel Lezcano, Thomas Gleixner, Emil Renner Berthing, Christophe JAILLET Cc: linux-riscv, devicetree, Rob Herring, Krzysztof Kozlowski, Paul Walmsley, Palmer Dabbelt, Albert Ou, Philipp Zabel, Walker Chen, Xingyu Wu, linux-kernel, Conor Dooley From: Xingyu Wu <xingyu.wu@starfivetech.com> Add the timer node for the Starfive JH7110 SoC. Reviewed-by: Emil Renner Berthing <emil.renner.berthing@canonical.com> Reviewed-by: Walker Chen <walker.chen@starfivetech.com> Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> --- arch/riscv/boot/dts/starfive/jh7110.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 4a5708f7fcf7..0854be18d922 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -913,6 +913,26 @@ #gpio-cells = <2>; }; + timer@13050000 { + compatible = "starfive,jh7110-timer"; + reg = <0x0 0x13050000 0x0 0x10000>; + interrupts = <69>, <70>, <71>, <72>; + clocks = <&syscrg JH7110_SYSCLK_TIMER_APB>, + <&syscrg JH7110_SYSCLK_TIMER0>, + <&syscrg JH7110_SYSCLK_TIMER1>, + <&syscrg JH7110_SYSCLK_TIMER2>, + <&syscrg JH7110_SYSCLK_TIMER3>; + clock-names = "apb", "ch0", "ch1", + "ch2", "ch3"; + resets = <&syscrg JH7110_SYSRST_TIMER_APB>, + <&syscrg JH7110_SYSRST_TIMER0>, + <&syscrg JH7110_SYSRST_TIMER1>, + <&syscrg JH7110_SYSRST_TIMER2>, + <&syscrg JH7110_SYSRST_TIMER3>; + reset-names = "apb", "ch0", "ch1", + "ch2", "ch3"; + }; + watchdog@13070000 { compatible = "starfive,jh7110-wdt"; reg = <0x0 0x13070000 0x0 0x10000>; -- 2.17.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-05-22 9:52 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-04-12 8:45 [PATCH v10 0/3] Add timer driver for StarFive JH7110 RISC-V SoC Ziv Xu 2024-04-12 8:45 ` [PATCH v10 1/3] dt-bindings: timer: Add timer for StarFive JH7110 SoC Ziv Xu 2024-04-12 8:45 ` [PATCH v10 2/3] clocksource: Add JH7110 timer driver Ziv Xu 2024-04-30 6:21 ` 回复: " Ziv Xu 2024-04-30 10:18 ` Emil Renner Berthing 2024-05-07 8:37 ` 回复: " Ziv Xu 2024-05-07 9:54 ` Emil Renner Berthing 2024-05-22 9:37 ` 回复: " Ziv Xu 2024-04-12 8:45 ` [PATCH v10 3/3] riscv: dts: jh7110: starfive: Add timer node Ziv Xu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).