Commit 00164f47 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'timers-core-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull more clocksource updates from Thomas Gleixner:
 "A set of updates for clocksource and clockevent drivers:

   - A fix for the prescaler of the ARM global timer where the prescaler
     mask define only covered 4 bits while it is actully 8 bits wide.
     This obviously restricted the possible range of prescaler
     adjustments

   - A fix for the RISC-V timer which prevents a timer interrupt being
     raised while the timer is initialized

   - A set of device tree updates to support new system on chips in
     various drivers

   - Kernel-doc and other cleanups all over the place"

* tag 'timers-core-2024-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  clocksource/drivers/timer-riscv: Clear timer interrupt on timer initialization
  dt-bindings: timer: Add support for cadence TTC PWM
  clocksource/drivers/arm_global_timer: Simplify prescaler register access
  clocksource/drivers/arm_global_timer: Guard against division by zero
  clocksource/drivers/arm_global_timer: Make gt_target_rate unsigned long
  dt-bindings: timer: add Ralink SoCs system tick counter
  clocksource: arm_global_timer: fix non-kernel-doc comment
  clocksource/drivers/arm_global_timer: Remove stray tab
  clocksource/drivers/arm_global_timer: Fix maximum prescaler value
  clocksource/drivers/imx-sysctr: Add i.MX95 support
  clocksource/drivers/imx-sysctr: Drop use global variables
  dt-bindings: timer: nxp,sysctr-timer: support i.MX95
  dt-bindings: timer: renesas: ostm: Document RZ/Five SoC
  dt-bindings: timer: renesas,tmu: Document input capture interrupt
  clocksource/drivers/ti-32K: Fix misuse of "/**" comment
  clocksource/drivers/stm32: Fix all kernel-doc warnings
  dt-bindings: timer: exynos4210-mct: Add google,gs101-mct compatible
  clocksource/drivers/imx: Fix -Wunused-but-set-variable warning
parents 1a391931 86c54c84
......@@ -32,12 +32,23 @@ properties:
description: |
Bit width of the timer, necessary if not 16.
"#pwm-cells":
const: 3
required:
- compatible
- reg
- interrupts
- clocks
allOf:
- if:
not:
required:
- "#pwm-cells"
then:
required:
- interrupts
additionalProperties: false
examples:
......@@ -50,3 +61,12 @@ examples:
clocks = <&cpu_clk 3>;
timer-width = <32>;
};
- |
pwm: pwm@f8002000 {
compatible = "cdns,ttc";
reg = <0xf8002000 0x1000>;
clocks = <&cpu_clk 3>;
timer-width = <32>;
#pwm-cells = <3>;
};
......@@ -18,7 +18,9 @@ description: |
properties:
compatible:
const: nxp,sysctr-timer
enum:
- nxp,imx95-sysctr-timer
- nxp,sysctr-timer
reg:
maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/ralink,cevt-systick.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: System tick counter present in Ralink family SoCs
maintainers:
- Sergio Paracuellos <sergio.paracuellos@gmail.com>
properties:
compatible:
const: ralink,cevt-systick
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
systick@d00 {
compatible = "ralink,cevt-systick";
reg = <0xd00 0x10>;
interrupt-parent = <&cpuintc>;
interrupts = <7>;
};
...
......@@ -23,7 +23,7 @@ properties:
- enum:
- renesas,r7s72100-ostm # RZ/A1H
- renesas,r7s9210-ostm # RZ/A2M
- renesas,r9a07g043-ostm # RZ/G2UL
- renesas,r9a07g043-ostm # RZ/G2UL and RZ/Five
- renesas,r9a07g044-ostm # RZ/G2{L,LC}
- renesas,r9a07g054-ostm # RZ/V2L
- const: renesas,ostm # Generic
......
......@@ -46,7 +46,19 @@ properties:
interrupts:
minItems: 2
maxItems: 3
items:
- description: Underflow interrupt, channel 0
- description: Underflow interrupt, channel 1
- description: Underflow interrupt, channel 2
- description: Input capture interrupt, channel 2
interrupt-names:
minItems: 2
items:
- const: tuni0
- const: tuni1
- const: tuni2
- const: ticpi2
clocks:
maxItems: 1
......@@ -100,7 +112,9 @@ examples:
reg = <0xffd80000 0x30>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
......
......@@ -26,6 +26,7 @@ properties:
- items:
- enum:
- axis,artpec8-mct
- google,gs101-mct
- samsung,exynos3250-mct
- samsung,exynos5250-mct
- samsung,exynos5260-mct
......@@ -127,6 +128,7 @@ allOf:
contains:
enum:
- axis,artpec8-mct
- google,gs101-mct
- samsung,exynos5260-mct
- samsung,exynos5420-mct
- samsung,exynos5433-mct
......
......@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/bitfield.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
......@@ -31,10 +32,7 @@
#define GT_CONTROL_COMP_ENABLE BIT(1) /* banked */
#define GT_CONTROL_IRQ_ENABLE BIT(2) /* banked */
#define GT_CONTROL_AUTO_INC BIT(3) /* banked */
#define GT_CONTROL_PRESCALER_SHIFT 8
#define GT_CONTROL_PRESCALER_MAX 0xF
#define GT_CONTROL_PRESCALER_MASK (GT_CONTROL_PRESCALER_MAX << \
GT_CONTROL_PRESCALER_SHIFT)
#define GT_CONTROL_PRESCALER_MASK GENMASK(15, 8)
#define GT_INT_STATUS 0x0c
#define GT_INT_STATUS_EVENT_FLAG BIT(0)
......@@ -52,7 +50,8 @@
*/
static void __iomem *gt_base;
static struct notifier_block gt_clk_rate_change_nb;
static u32 gt_psv_new, gt_psv_bck, gt_target_rate;
static u32 gt_psv_new, gt_psv_bck;
static unsigned long gt_target_rate;
static int gt_ppi;
static struct clock_event_device __percpu *gt_evt;
......@@ -88,7 +87,7 @@ static u64 gt_counter_read(void)
return _gt_counter_read();
}
/**
/*
* To ensure that updates to comparator value register do not set the
* Interrupt Status Register proceed as follows:
* 1. Clear the Comp Enable bit in the Timer Control Register.
......@@ -247,7 +246,7 @@ static void gt_write_presc(u32 psv)
reg = readl(gt_base + GT_CONTROL);
reg &= ~GT_CONTROL_PRESCALER_MASK;
reg |= psv << GT_CONTROL_PRESCALER_SHIFT;
reg |= FIELD_PREP(GT_CONTROL_PRESCALER_MASK, psv);
writel(reg, gt_base + GT_CONTROL);
}
......@@ -256,8 +255,7 @@ static u32 gt_read_presc(void)
u32 reg;
reg = readl(gt_base + GT_CONTROL);
reg &= GT_CONTROL_PRESCALER_MASK;
return reg >> GT_CONTROL_PRESCALER_SHIFT;
return FIELD_GET(GT_CONTROL_PRESCALER_MASK, reg);
}
static void __init gt_delay_timer_init(void)
......@@ -272,9 +270,9 @@ static int __init gt_clocksource_init(void)
writel(0, gt_base + GT_COUNTER0);
writel(0, gt_base + GT_COUNTER1);
/* set prescaler and enable timer on all the cores */
writel(((CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) <<
GT_CONTROL_PRESCALER_SHIFT)
| GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
writel(FIELD_PREP(GT_CONTROL_PRESCALER_MASK,
CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) |
GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
sched_clock_register(gt_sched_clock_read, 64, gt_target_rate);
......@@ -290,18 +288,17 @@ static int gt_clk_rate_change_cb(struct notifier_block *nb,
switch (event) {
case PRE_RATE_CHANGE:
{
int psv;
psv = DIV_ROUND_CLOSEST(ndata->new_rate,
gt_target_rate);
unsigned long psv;
if (abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
psv = DIV_ROUND_CLOSEST(ndata->new_rate, gt_target_rate);
if (!psv ||
abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
return NOTIFY_BAD;
psv--;
/* prescaler within legal range? */
if (psv < 0 || psv > GT_CONTROL_PRESCALER_MAX)
if (!FIELD_FIT(GT_CONTROL_PRESCALER_MASK, psv))
return NOTIFY_BAD;
/*
......@@ -411,7 +408,7 @@ static int __init global_timer_of_register(struct device_node *np)
err = gt_clocksource_init();
if (err)
goto out_irq;
err = cpuhp_setup_state(CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
"clockevents/arm/global_timer:starting",
gt_starting_cpu, gt_dying_cpu);
......
......@@ -258,9 +258,8 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *ced = dev_id;
struct imx_timer *imxtm = to_imx_timer(ced);
uint32_t tstat;
tstat = readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
imxtm->gpt->gpt_irq_acknowledge(imxtm);
......
......@@ -4,48 +4,62 @@
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/slab.h>
#include "timer-of.h"
#define CMP_OFFSET 0x10000
#define RD_OFFSET 0x20000
#define CNTCV_LO 0x8
#define CNTCV_HI 0xc
#define CMPCV_LO (CMP_OFFSET + 0x20)
#define CMPCV_HI (CMP_OFFSET + 0x24)
#define CMPCR (CMP_OFFSET + 0x2c)
#define CNTCV_LO_IMX95 (RD_OFFSET + 0x8)
#define CNTCV_HI_IMX95 (RD_OFFSET + 0xc)
#define SYS_CTR_EN 0x1
#define SYS_CTR_IRQ_MASK 0x2
#define SYS_CTR_CLK_DIV 0x3
static void __iomem *sys_ctr_base __ro_after_init;
static u32 cmpcr __ro_after_init;
struct sysctr_private {
u32 cmpcr;
u32 lo_off;
u32 hi_off;
};
static void sysctr_timer_enable(bool enable)
static void sysctr_timer_enable(struct clock_event_device *evt, bool enable)
{
writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
struct timer_of *to = to_timer_of(evt);
struct sysctr_private *priv = to->private_data;
void __iomem *base = timer_of_base(to);
writel(enable ? priv->cmpcr | SYS_CTR_EN : priv->cmpcr, base + CMPCR);
}
static void sysctr_irq_acknowledge(void)
static void sysctr_irq_acknowledge(struct clock_event_device *evt)
{
/*
* clear the enable bit(EN =0) will clear
* the status bit(ISTAT = 0), then the interrupt
* signal will be negated(acknowledged).
*/
sysctr_timer_enable(false);
sysctr_timer_enable(evt, false);
}
static inline u64 sysctr_read_counter(void)
static inline u64 sysctr_read_counter(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
struct sysctr_private *priv = to->private_data;
void __iomem *base = timer_of_base(to);
u32 cnt_hi, tmp_hi, cnt_lo;
do {
cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
cnt_hi = readl_relaxed(base + priv->hi_off);
cnt_lo = readl_relaxed(base + priv->lo_off);
tmp_hi = readl_relaxed(base + priv->hi_off);
} while (tmp_hi != cnt_hi);
return ((u64) cnt_hi << 32) | cnt_lo;
......@@ -54,22 +68,24 @@ static inline u64 sysctr_read_counter(void)
static int sysctr_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
void __iomem *base = timer_of_base(to);
u32 cmp_hi, cmp_lo;
u64 next;
sysctr_timer_enable(false);
sysctr_timer_enable(evt, false);
next = sysctr_read_counter();
next = sysctr_read_counter(evt);
next += delta;
cmp_hi = (next >> 32) & 0x00fffff;
cmp_lo = next & 0xffffffff;
writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
writel_relaxed(cmp_hi, base + CMPCV_HI);
writel_relaxed(cmp_lo, base + CMPCV_LO);
sysctr_timer_enable(true);
sysctr_timer_enable(evt, true);
return 0;
}
......@@ -81,7 +97,7 @@ static int sysctr_set_state_oneshot(struct clock_event_device *evt)
static int sysctr_set_state_shutdown(struct clock_event_device *evt)
{
sysctr_timer_enable(false);
sysctr_timer_enable(evt, false);
return 0;
}
......@@ -90,7 +106,7 @@ static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
sysctr_irq_acknowledge();
sysctr_irq_acknowledge(evt);
evt->event_handler(evt);
......@@ -117,34 +133,75 @@ static struct timer_of to_sysctr = {
},
};
static void __init sysctr_clockevent_init(void)
static int __init __sysctr_timer_init(struct device_node *np)
{
struct sysctr_private *priv;
void __iomem *base;
int ret;
priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
ret = timer_of_init(np, &to_sysctr);
if (ret) {
kfree(priv);
return ret;
}
if (!of_property_read_bool(np, "nxp,no-divider")) {
/* system counter clock is divided by 3 internally */
to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
}
to_sysctr.clkevt.cpumask = cpu_possible_mask;
to_sysctr.private_data = priv;
base = timer_of_base(&to_sysctr);
priv->cmpcr = readl(base + CMPCR) & ~SYS_CTR_EN;
return 0;
}
static int __init sysctr_timer_init(struct device_node *np)
{
struct sysctr_private *priv;
int ret;
ret = __sysctr_timer_init(np);
if (ret)
return ret;
priv = to_sysctr.private_data;
priv->lo_off = CNTCV_LO;
priv->hi_off = CNTCV_HI;
clockevents_config_and_register(&to_sysctr.clkevt,
timer_of_rate(&to_sysctr),
0xff, 0x7fffffff);
return 0;
}
static int __init sysctr_timer_init(struct device_node *np)
static int __init sysctr_timer_imx95_init(struct device_node *np)
{
int ret = 0;
struct sysctr_private *priv;
int ret;
ret = timer_of_init(np, &to_sysctr);
ret = __sysctr_timer_init(np);
if (ret)
return ret;
if (!of_property_read_bool(np, "nxp,no-divider")) {
/* system counter clock is divided by 3 internally */
to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
}
sys_ctr_base = timer_of_base(&to_sysctr);
cmpcr = readl(sys_ctr_base + CMPCR);
cmpcr &= ~SYS_CTR_EN;
priv = to_sysctr.private_data;
priv->lo_off = CNTCV_LO_IMX95;
priv->hi_off = CNTCV_HI_IMX95;
sysctr_clockevent_init();
clockevents_config_and_register(&to_sysctr.clkevt,
timer_of_rate(&to_sysctr),
0xff, 0x7fffffff);
return 0;
}
TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);
TIMER_OF_DECLARE(sysctr_timer_imx95, "nxp,imx95-sysctr-timer", sysctr_timer_imx95_init);
......@@ -108,6 +108,9 @@ static int riscv_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu);
/* Clear timer interrupt */
riscv_clock_event_stop();
ce->cpumask = cpumask_of(cpu);
ce->irq = riscv_clock_event_irq;
if (riscv_timer_cannot_wake_cpu)
......
......@@ -73,7 +73,7 @@ static void stm32_timer_of_bits_set(struct timer_of *to, int bits)
* Accessor helper to get the number of bits in the timer-of private
* structure.
*
* Returns an integer corresponding to the number of bits.
* Returns: an integer corresponding to the number of bits.
*/
static int stm32_timer_of_bits_get(struct timer_of *to)
{
......@@ -177,7 +177,7 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
}
/**
* stm32_timer_width - Sort out the timer width (32/16)
* stm32_timer_set_width - Sort out the timer width (32/16)
* @to: a pointer to a timer-of structure
*
* Write the 32-bit max value and read/return the result. If the timer
......
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* timer-ti-32k.c - OMAP2 32k Timer Support
*
* Copyright (C) 2009 Nokia Corporation
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment