Merge tag 'timers-core-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timers and timekeeping updates from Thomas Gleixner:
 "Core:

   - Robustness improvements for the NOHZ tick management

   - Fixes and consolidation of the NTP/RTC synchronization code

   - Small fixes and improvements in various places

   - A set of function documentation udpates and fixes

   Drivers:

   - Cleanups and improvements in various clocksoure/event drivers

   - Removal of the EZChip NPS clocksource driver as the platfrom
     support was removed from ARC

   - The usual set of new device tree binding and json conversions

   - The RTC driver which have been acked by the RTC maintainer:

       * fix a long standing bug in the MC146818 library code which can
         cause reading garbage during the RTC internal update.

       * changes related to the NTP/RTC consolidation work"

* tag 'timers-core-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (46 commits)
  ntp: Fix prototype in the !CONFIG_GENERIC_CMOS_UPDATE case
  tick/sched: Make jiffies update quick check more robust
  ntp: Consolidate the RTC update implementation
  ntp: Make the RTC sync offset less obscure
  ntp, rtc: Move rtc_set_ntp_time() to ntp code
  ntp: Make the RTC synchronization more reliable
  rtc: core: Make the sync offset default more realistic
  rtc: cmos: Make rtc_cmos sync offset correct
  rtc: mc146818: Reduce spinlock section in mc146818_set_time()
  rtc: mc146818: Prevent reading garbage
  clocksource/drivers/sh_cmt: Fix potential deadlock when calling runtime PM
  clocksource/drivers/arm_arch_timer: Correct fault programming of CNTKCTL_EL1.EVNTI
  clocksource/drivers/arm_arch_timer: Use stable count reader in erratum sne
  clocksource/drivers/dw_apb_timer_of: Add error handling if no clock available
  clocksource/drivers/riscv: Make RISCV_TIMER depends on RISCV_SBI
  clocksource/drivers/ingenic: Fix section mismatch
  clocksource/drivers/cadence_ttc: Fix memory leak in ttc_setup_clockevent()
  dt-bindings: timer: renesas: tmu: Convert to json-schema
  dt-bindings: timer: renesas: tmu: Document r8a774e1 bindings
  clocksource/drivers/orion: Add missing clk_disable_unprepare() on error path
  ...
This commit is contained in:
Linus Torvalds
2020-12-14 18:21:14 -08:00
36 changed files with 674 additions and 819 deletions

View File

@@ -1,49 +0,0 @@
* Renesas R-Mobile/R-Car Timer Unit (TMU)
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
Required Properties:
- compatible: must contain one or more of the following:
- "renesas,tmu-r8a7740" for the r8a7740 TMU
- "renesas,tmu-r8a774a1" for the r8a774A1 TMU
- "renesas,tmu-r8a774b1" for the r8a774B1 TMU
- "renesas,tmu-r8a774c0" for the r8a774C0 TMU
- "renesas,tmu-r8a7778" for the r8a7778 TMU
- "renesas,tmu-r8a7779" for the r8a7779 TMU
- "renesas,tmu-r8a77970" for the r8a77970 TMU
- "renesas,tmu-r8a77980" for the r8a77980 TMU
- "renesas,tmu" for any TMU.
This is a fallback for the above renesas,tmu-* entries
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Optional Properties:
- #renesas,channels: number of channels implemented by the timer, must be 2
or 3 (if not specified the value defaults to 3).
Example: R8A7779 (R-Car H1) TMU0 node
tmu0: timer@ffd80000 {
compatible = "renesas,tmu-r8a7779", "renesas,tmu";
reg = <0xffd80000 0x30>;
interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>,
<0 33 IRQ_TYPE_LEVEL_HIGH>,
<0 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
#renesas,channels = <3>;
};

View File

@@ -0,0 +1,99 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/renesas,tmu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Mobile/R-Car Timer Unit (TMU)
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
description:
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
properties:
compatible:
items:
- enum:
- renesas,tmu-r8a7740 # R-Mobile A1
- renesas,tmu-r8a774a1 # RZ/G2M
- renesas,tmu-r8a774b1 # RZ/G2N
- renesas,tmu-r8a774c0 # RZ/G2E
- renesas,tmu-r8a774e1 # RZ/G2H
- renesas,tmu-r8a7778 # R-Car M1A
- renesas,tmu-r8a7779 # R-Car H1
- renesas,tmu-r8a77970 # R-Car V3M
- renesas,tmu-r8a77980 # R-Car V3H
- const: renesas,tmu
reg:
maxItems: 1
interrupts:
minItems: 2
maxItems: 3
clocks:
maxItems: 1
clock-names:
const: fck
power-domains:
maxItems: 1
resets:
maxItems: 1
'#renesas,channels':
description:
Number of channels implemented by the timer.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 2, 3 ]
default: 3
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
if:
not:
properties:
compatible:
contains:
enum:
- renesas,tmu-r8a7740
- renesas,tmu-r8a7778
- renesas,tmu-r8a7779
then:
required:
- resets
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7779-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7779-sysc.h>
tmu0: timer@ffd80000 {
compatible = "renesas,tmu-r8a7779", "renesas,tmu";
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>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
#renesas,channels = <3>;
};

View File

@@ -275,16 +275,6 @@ config CLKSRC_TI_32K
This option enables support for Texas Instruments 32.768 Hz clocksource
available on many OMAP-like platforms.
config CLKSRC_NPS
bool "NPS400 clocksource driver" if COMPILE_TEST
depends on !PHYS_ADDR_T_64BIT
select CLKSRC_MMIO
select TIMER_OF if OF
help
NPS400 clocksource support.
It has a 64-bit counter with update rate up to 1000MHz.
This counter is accessed via couple of 32-bit memory-mapped registers.
config CLKSRC_STM32
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
@@ -654,7 +644,7 @@ config ATCPIT100_TIMER
config RISCV_TIMER
bool "Timer for the RISC-V platform" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK && RISCV
depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI
select TIMER_PROBE
select TIMER_OF
help

View File

@@ -56,7 +56,6 @@ obj-$(CONFIG_CLKSRC_QCOM) += timer-qcom.o
obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o
obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o
obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += timer-owl.o
obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o

View File

@@ -396,10 +396,10 @@ static void erratum_set_next_event_tval_generic(const int access, unsigned long
ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
if (access == ARCH_TIMER_PHYS_ACCESS) {
cval = evt + arch_counter_get_cntpct();
cval = evt + arch_counter_get_cntpct_stable();
write_sysreg(cval, cntp_cval_el0);
} else {
cval = evt + arch_counter_get_cntvct();
cval = evt + arch_counter_get_cntvct_stable();
write_sysreg(cval, cntv_cval_el0);
}
@@ -822,15 +822,24 @@ static void arch_timer_evtstrm_enable(int divider)
static void arch_timer_configure_evtstream(void)
{
int evt_stream_div, pos;
int evt_stream_div, lsb;
/*
* As the event stream can at most be generated at half the frequency
* of the counter, use half the frequency when computing the divider.
*/
evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ / 2;
/*
* Find the closest power of two to the divisor. If the adjacent bit
* of lsb (last set bit, starts from 0) is set, then we use (lsb + 1).
*/
lsb = fls(evt_stream_div) - 1;
if (lsb > 0 && (evt_stream_div & BIT(lsb - 1)))
lsb++;
/* Find the closest power of two to the divisor */
evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ;
pos = fls(evt_stream_div);
if (pos > 1 && !(evt_stream_div & (1 << (pos - 2))))
pos--;
/* enable event stream */
arch_timer_evtstrm_enable(min(pos, 15));
arch_timer_evtstrm_enable(max(0, min(lsb, 15)));
}
static void arch_counter_set_user_access(void)

View File

@@ -14,12 +14,13 @@
#include <linux/reset.h>
#include <linux/sched_clock.h>
static void __init timer_get_base_and_rate(struct device_node *np,
static int __init timer_get_base_and_rate(struct device_node *np,
void __iomem **base, u32 *rate)
{
struct clk *timer_clk;
struct clk *pclk;
struct reset_control *rstc;
int ret;
*base = of_iomap(np, 0);
@@ -46,55 +47,67 @@ static void __init timer_get_base_and_rate(struct device_node *np,
pr_warn("pclk for %pOFn is present, but could not be activated\n",
np);
if (!of_property_read_u32(np, "clock-freq", rate) &&
!of_property_read_u32(np, "clock-frequency", rate))
return 0;
timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer_clk))
goto try_clock_freq;
return PTR_ERR(timer_clk);
if (!clk_prepare_enable(timer_clk)) {
*rate = clk_get_rate(timer_clk);
return;
}
ret = clk_prepare_enable(timer_clk);
if (ret)
return ret;
try_clock_freq:
if (of_property_read_u32(np, "clock-freq", rate) &&
of_property_read_u32(np, "clock-frequency", rate))
panic("No clock nor clock-frequency property for %pOFn", np);
*rate = clk_get_rate(timer_clk);
if (!(*rate))
return -EINVAL;
return 0;
}
static void __init add_clockevent(struct device_node *event_timer)
static int __init add_clockevent(struct device_node *event_timer)
{
void __iomem *iobase;
struct dw_apb_clock_event_device *ced;
u32 irq, rate;
int ret = 0;
irq = irq_of_parse_and_map(event_timer, 0);
if (irq == 0)
panic("No IRQ for clock event timer");
timer_get_base_and_rate(event_timer, &iobase, &rate);
ret = timer_get_base_and_rate(event_timer, &iobase, &rate);
if (ret)
return ret;
ced = dw_apb_clockevent_init(-1, event_timer->name, 300, iobase, irq,
rate);
if (!ced)
panic("Unable to initialise clockevent device");
return -EINVAL;
dw_apb_clockevent_register(ced);
return 0;
}
static void __iomem *sched_io_base;
static u32 sched_rate;
static void __init add_clocksource(struct device_node *source_timer)
static int __init add_clocksource(struct device_node *source_timer)
{
void __iomem *iobase;
struct dw_apb_clocksource *cs;
u32 rate;
int ret;
timer_get_base_and_rate(source_timer, &iobase, &rate);
ret = timer_get_base_and_rate(source_timer, &iobase, &rate);
if (ret)
return ret;
cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate);
if (!cs)
panic("Unable to initialise clocksource device");
return -EINVAL;
dw_apb_clocksource_start(cs);
dw_apb_clocksource_register(cs);
@@ -106,6 +119,8 @@ static void __init add_clocksource(struct device_node *source_timer)
*/
sched_io_base = iobase + 0x04;
sched_rate = rate;
return 0;
}
static u64 notrace read_sched_clock(void)
@@ -146,10 +161,14 @@ static struct delay_timer dw_apb_delay_timer = {
static int num_called;
static int __init dw_apb_timer_init(struct device_node *timer)
{
int ret = 0;
switch (num_called) {
case 1:
pr_debug("%s: found clocksource timer\n", __func__);
add_clocksource(timer);
ret = add_clocksource(timer);
if (ret)
return ret;
init_sched_clock();
#ifdef CONFIG_ARM
dw_apb_delay_timer.freq = sched_rate;
@@ -158,7 +177,9 @@ static int __init dw_apb_timer_init(struct device_node *timer)
break;
default:
pr_debug("%s: found clockevent timer\n", __func__);
add_clockevent(timer);
ret = add_clockevent(timer);
if (ret)
return ret;
break;
}

View File

@@ -127,7 +127,7 @@ static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id)
return IRQ_HANDLED;
}
static struct clk * __init ingenic_tcu_get_clock(struct device_node *np, int id)
static struct clk *ingenic_tcu_get_clock(struct device_node *np, int id)
{
struct of_phandle_args args;

View File

@@ -319,7 +319,6 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch)
{
int k, ret;
pm_runtime_get_sync(&ch->cmt->pdev->dev);
dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
/* enable clock */
@@ -394,7 +393,6 @@ static void sh_cmt_disable(struct sh_cmt_channel *ch)
clk_disable(ch->cmt->clk);
dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
pm_runtime_put(&ch->cmt->pdev->dev);
}
/* private flags */
@@ -562,10 +560,16 @@ static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
int ret = 0;
unsigned long flags;
if (flag & FLAG_CLOCKSOURCE)
pm_runtime_get_sync(&ch->cmt->pdev->dev);
raw_spin_lock_irqsave(&ch->lock, flags);
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
if (flag & FLAG_CLOCKEVENT)
pm_runtime_get_sync(&ch->cmt->pdev->dev);
ret = sh_cmt_enable(ch);
}
if (ret)
goto out;
@@ -590,14 +594,20 @@ static void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag)
f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
ch->flags &= ~flag;
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
sh_cmt_disable(ch);
if (flag & FLAG_CLOCKEVENT)
pm_runtime_put(&ch->cmt->pdev->dev);
}
/* adjust the timeout to maximum if only clocksource left */
if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE))
__sh_cmt_set_next(ch, ch->max_match_value);
raw_spin_unlock_irqrestore(&ch->lock, flags);
if (flag & FLAG_CLOCKSOURCE)
pm_runtime_put(&ch->cmt->pdev->dev);
}
static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)

View File

@@ -413,10 +413,8 @@ static int __init ttc_setup_clockevent(struct clk *clk,
ttcce->ttc.clk = clk;
err = clk_prepare_enable(ttcce->ttc.clk);
if (err) {
kfree(ttcce);
return err;
}
if (err)
goto out_kfree;
ttcce->ttc.clk_rate_change_nb.notifier_call =
ttc_rate_change_clockevent_cb;
@@ -426,7 +424,7 @@ static int __init ttc_setup_clockevent(struct clk *clk,
&ttcce->ttc.clk_rate_change_nb);
if (err) {
pr_warn("Unable to register clock notifier.\n");
return err;
goto out_kfree;
}
ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk);
@@ -455,15 +453,17 @@ static int __init ttc_setup_clockevent(struct clk *clk,
err = request_irq(irq, ttc_clock_event_interrupt,
IRQF_TIMER, ttcce->ce.name, ttcce);
if (err) {
kfree(ttcce);
return err;
}
if (err)
goto out_kfree;
clockevents_config_and_register(&ttcce->ce,
ttcce->ttc.freq / PRESCALE, 1, 0xfffe);
return 0;
out_kfree:
kfree(ttcce);
return err;
}
static int __init ttc_timer_probe(struct platform_device *pdev)

View File

@@ -1,284 +0,0 @@
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/cpu.h>
#include <soc/nps/common.h>
#define NPS_MSU_TICK_LOW 0xC8
#define NPS_CLUSTER_OFFSET 8
#define NPS_CLUSTER_NUM 16
/* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */
static void *nps_msu_reg_low_addr[NPS_CLUSTER_NUM] __read_mostly;
static int __init nps_get_timer_clk(struct device_node *node,
unsigned long *timer_freq,
struct clk **clk)
{
int ret;
*clk = of_clk_get(node, 0);
ret = PTR_ERR_OR_ZERO(*clk);
if (ret) {
pr_err("timer missing clk\n");
return ret;
}
ret = clk_prepare_enable(*clk);
if (ret) {
pr_err("Couldn't enable parent clk\n");
clk_put(*clk);
return ret;
}
*timer_freq = clk_get_rate(*clk);
if (!(*timer_freq)) {
pr_err("Couldn't get clk rate\n");
clk_disable_unprepare(*clk);
clk_put(*clk);
return -EINVAL;
}
return 0;
}
static u64 nps_clksrc_read(struct clocksource *clksrc)
{
int cluster = raw_smp_processor_id() >> NPS_CLUSTER_OFFSET;
return (u64)ioread32be(nps_msu_reg_low_addr[cluster]);
}
static int __init nps_setup_clocksource(struct device_node *node)
{
int ret, cluster;
struct clk *clk;
unsigned long nps_timer1_freq;
for (cluster = 0; cluster < NPS_CLUSTER_NUM; cluster++)
nps_msu_reg_low_addr[cluster] =
nps_host_reg((cluster << NPS_CLUSTER_OFFSET),
NPS_MSU_BLKID, NPS_MSU_TICK_LOW);
ret = nps_get_timer_clk(node, &nps_timer1_freq, &clk);
if (ret)
return ret;
ret = clocksource_mmio_init(nps_msu_reg_low_addr, "nps-tick",
nps_timer1_freq, 300, 32, nps_clksrc_read);
if (ret) {
pr_err("Couldn't register clock source.\n");
clk_disable_unprepare(clk);
}
return ret;
}
TIMER_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer",
nps_setup_clocksource);
TIMER_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1",
nps_setup_clocksource);
#ifdef CONFIG_EZNPS_MTM_EXT
#include <soc/nps/mtm.h>
/* Timer related Aux registers */
#define NPS_REG_TIMER0_TSI 0xFFFFF850
#define NPS_REG_TIMER0_LIMIT 0x23
#define NPS_REG_TIMER0_CTRL 0x22
#define NPS_REG_TIMER0_CNT 0x21
/*
* Interrupt Enabled (IE) - re-arm the timer
* Not Halted (NH) - is cleared when working with JTAG (for debug)
*/
#define TIMER0_CTRL_IE BIT(0)
#define TIMER0_CTRL_NH BIT(1)
static unsigned long nps_timer0_freq;
static unsigned long nps_timer0_irq;
static void nps_clkevent_rm_thread(void)
{
int thread;
unsigned int cflags, enabled_threads;
hw_schd_save(&cflags);
enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI);
/* remove thread from TSI1 */
thread = read_aux_reg(CTOP_AUX_THREAD_ID);
enabled_threads &= ~(1 << thread);
write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads);
/* Acknowledge and if needed re-arm the timer */
if (!enabled_threads)
write_aux_reg(NPS_REG_TIMER0_CTRL, TIMER0_CTRL_NH);
else
write_aux_reg(NPS_REG_TIMER0_CTRL,
TIMER0_CTRL_IE | TIMER0_CTRL_NH);
hw_schd_restore(cflags);
}
static void nps_clkevent_add_thread(unsigned long delta)
{
int thread;
unsigned int cflags, enabled_threads;
hw_schd_save(&cflags);
/* add thread to TSI1 */
thread = read_aux_reg(CTOP_AUX_THREAD_ID);
enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI);
enabled_threads |= (1 << thread);
write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads);
/* set next timer event */
write_aux_reg(NPS_REG_TIMER0_LIMIT, delta);
write_aux_reg(NPS_REG_TIMER0_CNT, 0);
write_aux_reg(NPS_REG_TIMER0_CTRL,
TIMER0_CTRL_IE | TIMER0_CTRL_NH);
hw_schd_restore(cflags);
}
/*
* Whenever anyone tries to change modes, we just mask interrupts
* and wait for the next event to get set.
*/
static int nps_clkevent_set_state(struct clock_event_device *dev)
{
nps_clkevent_rm_thread();
disable_percpu_irq(nps_timer0_irq);
return 0;
}
static int nps_clkevent_set_next_event(unsigned long delta,
struct clock_event_device *dev)
{
nps_clkevent_add_thread(delta);
enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE);
return 0;
}
static DEFINE_PER_CPU(struct clock_event_device, nps_clockevent_device) = {
.name = "NPS Timer0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 300,
.set_next_event = nps_clkevent_set_next_event,
.set_state_oneshot = nps_clkevent_set_state,
.set_state_oneshot_stopped = nps_clkevent_set_state,
.set_state_shutdown = nps_clkevent_set_state,
.tick_resume = nps_clkevent_set_state,
};
static irqreturn_t timer_irq_handler(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
nps_clkevent_rm_thread();
evt->event_handler(evt);
return IRQ_HANDLED;
}
static int nps_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *evt = this_cpu_ptr(&nps_clockevent_device);
evt->cpumask = cpumask_of(smp_processor_id());
clockevents_config_and_register(evt, nps_timer0_freq, 0, ULONG_MAX);
enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE);
return 0;
}
static int nps_timer_dying_cpu(unsigned int cpu)
{
disable_percpu_irq(nps_timer0_irq);
return 0;
}
static int __init nps_setup_clockevent(struct device_node *node)
{
struct clk *clk;
int ret;
nps_timer0_irq = irq_of_parse_and_map(node, 0);
if (nps_timer0_irq <= 0) {
pr_err("clockevent: missing irq\n");
return -EINVAL;
}
ret = nps_get_timer_clk(node, &nps_timer0_freq, &clk);
if (ret)
return ret;
/* Needs apriori irq_set_percpu_devid() done in intc map function */
ret = request_percpu_irq(nps_timer0_irq, timer_irq_handler,
"Timer0 (per-cpu-tick)",
&nps_clockevent_device);
if (ret) {
pr_err("Couldn't request irq\n");
clk_disable_unprepare(clk);
return ret;
}
ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING,
"clockevents/nps:starting",
nps_timer_starting_cpu,
nps_timer_dying_cpu);
if (ret) {
pr_err("Failed to setup hotplug state\n");
clk_disable_unprepare(clk);
free_percpu_irq(nps_timer0_irq, &nps_clockevent_device);
return ret;
}
return 0;
}
TIMER_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0",
nps_setup_clockevent);
#endif /* CONFIG_EZNPS_MTM_EXT */

View File

@@ -143,7 +143,8 @@ static int __init orion_timer_init(struct device_node *np)
irq = irq_of_parse_and_map(np, 1);
if (irq <= 0) {
pr_err("%pOFn: unable to parse timer1 irq\n", np);
return -EINVAL;
ret = -EINVAL;
goto out_unprep_clk;
}
rate = clk_get_rate(clk);
@@ -160,7 +161,7 @@ static int __init orion_timer_init(struct device_node *np)
clocksource_mmio_readl_down);
if (ret) {
pr_err("Failed to initialize mmio timer\n");
return ret;
goto out_unprep_clk;
}
sched_clock_register(orion_read_sched_clock, 32, rate);
@@ -170,7 +171,7 @@ static int __init orion_timer_init(struct device_node *np)
"orion_event", NULL);
if (ret) {
pr_err("%pOFn: unable to setup irq\n", np);
return ret;
goto out_unprep_clk;
}
ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ;
@@ -183,5 +184,9 @@ static int __init orion_timer_init(struct device_node *np)
orion_delay_timer_init(rate);
return 0;
out_unprep_clk:
clk_disable_unprepare(clk);
return ret;
}
TIMER_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init);

View File

@@ -5,6 +5,9 @@
* Copyright (C) 1999 - 2003 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
@@ -34,8 +37,7 @@
#define HISI_TIMER_BGLOAD 0x20
#define HISI_TIMER_BGLOAD_H 0x24
struct sp804_timer __initdata arm_sp804_timer = {
static struct sp804_timer arm_sp804_timer __initdata = {
.load = TIMER_LOAD,
.value = TIMER_VALUE,
.ctrl = TIMER_CTRL,
@@ -44,7 +46,7 @@ struct sp804_timer __initdata arm_sp804_timer = {
.width = 32,
};
struct sp804_timer __initdata hisi_sp804_timer = {
static struct sp804_timer hisi_sp804_timer __initdata = {
.load = HISI_TIMER_LOAD,
.load_h = HISI_TIMER_LOAD_H,
.value = HISI_TIMER_VALUE,
@@ -59,40 +61,23 @@ static struct sp804_clkevt sp804_clkevt[NR_TIMERS];
static long __init sp804_get_clock_rate(struct clk *clk, const char *name)
{
long rate;
int err;
if (!clk)
clk = clk_get_sys("sp804", name);
if (IS_ERR(clk)) {
pr_err("sp804: %s clock not found: %ld\n", name, PTR_ERR(clk));
pr_err("%s clock not found: %ld\n", name, PTR_ERR(clk));
return PTR_ERR(clk);
}
err = clk_prepare(clk);
err = clk_prepare_enable(clk);
if (err) {
pr_err("sp804: clock failed to prepare: %d\n", err);
pr_err("clock failed to enable: %d\n", err);
clk_put(clk);
return err;
}
err = clk_enable(clk);
if (err) {
pr_err("sp804: clock failed to enable: %d\n", err);
clk_unprepare(clk);
clk_put(clk);
return err;
}
rate = clk_get_rate(clk);
if (rate < 0) {
pr_err("sp804: clock failed to get rate: %ld\n", rate);
clk_disable(clk);
clk_unprepare(clk);
clk_put(clk);
}
return rate;
return clk_get_rate(clk);
}
static struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base)
@@ -117,10 +102,10 @@ static u64 notrace sp804_read(void)
return ~readl_relaxed(sched_clkevt->value);
}
int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name,
struct clk *clk,
int use_sched_clock)
static int __init sp804_clocksource_and_sched_clock_init(void __iomem *base,
const char *name,
struct clk *clk,
int use_sched_clock)
{
long rate;
struct sp804_clkevt *clkevt;
@@ -216,8 +201,8 @@ static struct clock_event_device sp804_clockevent = {
.rating = 300,
};
int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
struct clk *clk, const char *name)
static int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
struct clk *clk, const char *name)
{
struct clock_event_device *evt = &sp804_clockevent;
long rate;
@@ -236,7 +221,7 @@ int __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
"timer", &sp804_clockevent))
pr_err("%s: request_irq() failed\n", "timer");
pr_err("request_irq() failed\n");
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
return 0;
@@ -298,7 +283,7 @@ static int __init sp804_of_init(struct device_node *np, struct sp804_timer *time
if (of_clk_get_parent_count(np) == 3) {
clk2 = of_clk_get(np, 1);
if (IS_ERR(clk2)) {
pr_err("sp804: %pOFn clock not found: %d\n", np,
pr_err("%pOFn clock not found: %d\n", np,
(int)PTR_ERR(clk2));
clk2 = NULL;
}

View File

@@ -6,7 +6,6 @@
ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG
obj-$(CONFIG_RTC_LIB) += lib.o
obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
rtc-core-y := class.o interface.o

View File

@@ -200,8 +200,13 @@ static struct rtc_device *rtc_allocate_device(void)
device_initialize(&rtc->dev);
/* Drivers can revise this default after allocating the device. */
rtc->set_offset_nsec = NSEC_PER_SEC / 2;
/*
* Drivers can revise this default after allocating the device.
* The default is what most RTCs do: Increment seconds exactly one
* second after the write happened. This adds a default transport
* time of 5ms which is at least halfways close to reality.
*/
rtc->set_offset_nsec = NSEC_PER_SEC + 5 * NSEC_PER_MSEC;
rtc->irq_freq = 1;
rtc->max_user_freq = 64;

View File

@@ -868,6 +868,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
if (retval)
goto cleanup2;
/* Set the sync offset for the periodic 11min update correct */
cmos_rtc.rtc->set_offset_nsec = NSEC_PER_SEC / 2;
/* export at least the first block of NVRAM */
nvmem_cfg.size = address_space - NVRAM_OFFSET;
if (rtc_nvmem_register(cmos_rtc.rtc, &nvmem_cfg))

View File

@@ -8,41 +8,41 @@
#include <linux/acpi.h>
#endif
/*
* Returns true if a clock update is in progress
*/
static inline unsigned char mc146818_is_updating(void)
{
unsigned char uip;
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
spin_unlock_irqrestore(&rtc_lock, flags);
return uip;
}
unsigned int mc146818_get_time(struct rtc_time *time)
{
unsigned char ctrl;
unsigned long flags;
unsigned char century = 0;
bool retry;
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
#endif
again:
spin_lock_irqsave(&rtc_lock, flags);
/*
* read RTC once any update in progress is done. The update
* can take just over 2ms. We wait 20ms. There is no need to
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
* If you need to know *exactly* when a second has started, enable
* periodic update complete interrupts, (via ioctl) and then
* immediately read /dev/rtc which will block until you get the IRQ.
* Once the read clears, read the RTC time (again via ioctl). Easy.
* Check whether there is an update in progress during which the
* readout is unspecified. The maximum update time is ~2ms. Poll
* every msec for completion.
*
* Store the second value before checking UIP so a long lasting NMI
* which happens to hit after the UIP check cannot make an update
* cycle invisible.
*/
if (mc146818_is_updating())
mdelay(20);
time->tm_sec = CMOS_READ(RTC_SECONDS);
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
mdelay(1);
goto again;
}
/* Revalidate the above readout */
if (time->tm_sec != CMOS_READ(RTC_SECONDS)) {
spin_unlock_irqrestore(&rtc_lock, flags);
goto again;
}
/*
* Only the values that we read from the RTC are set. We leave
@@ -50,8 +50,6 @@ unsigned int mc146818_get_time(struct rtc_time *time)
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value.
*/
spin_lock_irqsave(&rtc_lock, flags);
time->tm_sec = CMOS_READ(RTC_SECONDS);
time->tm_min = CMOS_READ(RTC_MINUTES);
time->tm_hour = CMOS_READ(RTC_HOURS);
time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
@@ -66,8 +64,24 @@ unsigned int mc146818_get_time(struct rtc_time *time)
century = CMOS_READ(acpi_gbl_FADT.century);
#endif
ctrl = CMOS_READ(RTC_CONTROL);
/*
* Check for the UIP bit again. If it is set now then
* the above values may contain garbage.
*/
retry = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
/*
* A NMI might have interrupted the above sequence so check whether
* the seconds value has changed which indicates that the NMI took
* longer than the UIP bit was set. Unlikely, but possible and
* there is also virt...
*/
retry |= time->tm_sec != CMOS_READ(RTC_SECONDS);
spin_unlock_irqrestore(&rtc_lock, flags);
if (retry)
goto again;
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
time->tm_sec = bcd2bin(time->tm_sec);
@@ -121,7 +135,6 @@ int mc146818_set_time(struct rtc_time *time)
if (yrs > 255) /* They are unsigned */
return -EINVAL;
spin_lock_irqsave(&rtc_lock, flags);
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
@@ -150,10 +163,8 @@ int mc146818_set_time(struct rtc_time *time)
/* These limits and adjustments are independent of
* whether the chip is in binary mode or not.
*/
if (yrs > 169) {
spin_unlock_irqrestore(&rtc_lock, flags);
if (yrs > 169)
return -EINVAL;
}
if (yrs >= 100)
yrs -= 100;
@@ -169,6 +180,7 @@ int mc146818_set_time(struct rtc_time *time)
century = bin2bcd(century);
}
spin_lock_irqsave(&rtc_lock, flags);
save_control = CMOS_READ(RTC_CONTROL);
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
save_freq_select = CMOS_READ(RTC_FREQ_SELECT);

View File

@@ -1,61 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/rtc.h>
#include <linux/time.h>
/**
* rtc_set_ntp_time - Save NTP synchronized time to the RTC
* @now: Current time of day
* @target_nsec: pointer for desired now->tv_nsec value
*
* Replacement for the NTP platform function update_persistent_clock64
* that stores time for later retrieval by rtc_hctosys.
*
* Returns 0 on successful RTC update, -ENODEV if a RTC update is not
* possible at all, and various other -errno for specific temporary failure
* cases.
*
* -EPROTO is returned if now.tv_nsec is not close enough to *target_nsec.
*
* If temporary failure is indicated the caller should try again 'soon'
*/
int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec)
{
struct rtc_device *rtc;
struct rtc_time tm;
struct timespec64 to_set;
int err = -ENODEV;
bool ok;
rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
if (!rtc)
goto out_err;
if (!rtc->ops || !rtc->ops->set_time)
goto out_close;
/* Compute the value of tv_nsec we require the caller to supply in
* now.tv_nsec. This is the value such that (now +
* set_offset_nsec).tv_nsec == 0.
*/
set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec);
*target_nsec = to_set.tv_nsec;
/* The ntp code must call this with the correct value in tv_nsec, if
* it does not we update target_nsec and return EPROTO to make the ntp
* code try again later.
*/
ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now);
if (!ok) {
err = -EPROTO;
goto out_close;
}
rtc_time64_to_tm(to_set.tv_sec, &tm);
err = rtc_set_time(rtc, &tm);
out_close:
rtc_class_close(rtc);
out_err:
return err;
}

View File

@@ -1,12 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides clock numbers for the ingenic,tcu DT binding.
* This header provides clock numbers for the Ingenic OST DT binding.
*/
#ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define __DT_BINDINGS_CLOCK_INGENIC_OST_H__
#define OST_CLK_PERCPU_TIMER 0
#define OST_CLK_GLOBAL_TIMER 1
#define OST_CLK_PERCPU_TIMER 1
#define OST_CLK_GLOBAL_TIMER 0
#define OST_CLK_PERCPU_TIMER0 1
#define OST_CLK_PERCPU_TIMER1 2
#define OST_CLK_PERCPU_TIMER2 3
#define OST_CLK_PERCPU_TIMER3 4
#endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */

View File

@@ -447,6 +447,10 @@ static inline void hrtimer_restart(struct hrtimer *timer)
/* Query timers: */
extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust);
/**
* hrtimer_get_remaining - get remaining time for the timer
* @timer: the timer to read
*/
static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer)
{
return __hrtimer_get_remaining(timer, false);
@@ -458,7 +462,7 @@ extern u64 hrtimer_next_event_without(const struct hrtimer *exclude);
extern bool hrtimer_active(const struct hrtimer *timer);
/**
* hrtimer_is_queued = check, whether the timer is on one of the queues
* hrtimer_is_queued - check, whether the timer is on one of the queues
* @timer: Timer to check
*
* Returns: True if the timer is queued, false otherwise

View File

@@ -110,13 +110,36 @@ struct rtc_device {
/* Some hardware can't support UIE mode */
int uie_unsupported;
/* Number of nsec it takes to set the RTC clock. This influences when
* the set ops are called. An offset:
* - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s
* - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s
* - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s
/*
* This offset specifies the update timing of the RTC.
*
* tsched t1 write(t2.tv_sec - 1sec)) t2 RTC increments seconds
*
* The offset defines how tsched is computed so that the write to
* the RTC (t2.tv_sec - 1sec) is correct versus the time required
* for the transport of the write and the time which the RTC needs
* to increment seconds the first time after the write (t2).
*
* For direct accessible RTCs tsched ~= t1 because the write time
* is negligible. For RTCs behind slow busses the transport time is
* significant and has to be taken into account.
*
* The time between the write (t1) and the first increment after
* the write (t2) is RTC specific. For a MC146818 RTC it's 500ms,
* for many others it's exactly 1 second. Consult the datasheet.
*
* The value of this offset is also used to calculate the to be
* written value (t2.tv_sec - 1sec) at tsched.
*
* The default value for this is NSEC_PER_SEC + 10 msec default
* transport time. The offset can be adjusted by drivers so the
* calculation for the to be written value at tsched becomes
* correct:
*
* newval = tsched + set_offset_nsec - NSEC_PER_SEC
* and (tsched + set_offset_nsec) % NSEC_PER_SEC == 0
*/
long set_offset_nsec;
unsigned long set_offset_nsec;
bool registered;
@@ -165,7 +188,6 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc);
extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
@@ -205,39 +227,6 @@ static inline bool is_leap_year(unsigned int year)
return (!(year % 4) && (year % 100)) || !(year % 400);
}
/* Determine if we can call to driver to set the time. Drivers can only be
* called to set a second aligned time value, and the field set_offset_nsec
* specifies how far away from the second aligned time to call the driver.
*
* This also computes 'to_set' which is the time we are trying to set, and has
* a zero in tv_nsecs, such that:
* to_set - set_delay_nsec == now +/- FUZZ
*
*/
static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec,
struct timespec64 *to_set,
const struct timespec64 *now)
{
/* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */
const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5;
struct timespec64 delay = {.tv_sec = 0,
.tv_nsec = set_offset_nsec};
*to_set = timespec64_add(*now, delay);
if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) {
to_set->tv_nsec = 0;
return true;
}
if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) {
to_set->tv_sec++;
to_set->tv_nsec = 0;
return true;
}
return false;
}
#define rtc_register_device(device) \
__rtc_register_device(THIS_MODULE, device)

Some files were not shown because too many files have changed in this diff Show More