Commit 615740fd authored by Thomas Gleixner's avatar Thomas Gleixner

Merge branch 'clockevents/4.21' of...

Merge branch 'clockevents/4.21' of http://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clocksource/event changes from Daniel Lezcano:

 - Add the sched_clock for the arc timer (Alexey Brodkin)

 - Change the file timer names for riscv, rockchip, tegra20, sun4i and
   meson6 (Daniel Lezcano)

 - Add the DT bindings for r8a7796, r8a77470 and r8a774a1 (Biju Das)

 - Remove the early platform driver registration for timer-ti-dm (Bartosz
   Golaszewski)

 - Provide the sched_clock for the riscv timer (Anup Patel)

 - Add support for ARM64 for the imx-gpt and convert the imx-tpm to the
   timer-of API (Anson Huang)

 - Remove useless irq protection for the imx-gpt (Clément Péron)

 - Remove a duplicate function name for the vt8500 (Dan Carpenter)

 - Remove obsolete inclusion of <asm/smp_twd.h> for the tegra20 (Geert
   Uytterhoeven)

 - Demote the prcmu and the custom sched_clock for the dbx500 and the ux500
   (Linus Walleij)

 - Add a new timer clock for the RDA8810PL (Manivannan Sadhasivam)

 - Rename the macro to stick to the register name and add the delay timer
   (Martin Blumenstingl)

 - Switch the bcm2835 to the SPDX identifier (Stefan Wahren)

 - Fix the interrupt register access on the fttmr010 (Tao Ren)

 - Add missing of_node_put in the initialization path on the
   integrator-ap (Yangtao Li)
parents 07daef8b 7f83a132
......@@ -28,6 +28,10 @@ Required Properties:
- "renesas,r8a7744-cmt1" for the 48-bit CMT1 device included in r8a7744.
- "renesas,r8a7745-cmt0" for the 32-bit CMT0 device included in r8a7745.
- "renesas,r8a7745-cmt1" for the 48-bit CMT1 device included in r8a7745.
- "renesas,r8a77470-cmt0" for the 32-bit CMT0 device included in r8a77470.
- "renesas,r8a77470-cmt1" for the 48-bit CMT1 device included in r8a77470.
- "renesas,r8a774a1-cmt0" for the 32-bit CMT0 device included in r8a774a1.
- "renesas,r8a774a1-cmt1" for the 48-bit CMT1 device included in r8a774a1.
- "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790.
- "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790.
- "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791.
......@@ -36,6 +40,8 @@ Required Properties:
- "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793.
- "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794.
- "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794.
- "renesas,r8a7796-cmt0" for the 32-bit CMT0 device included in r8a7796.
- "renesas,r8a7796-cmt1" for the 48-bit CMT1 device included in r8a7796.
- "renesas,r8a77970-cmt0" for the 32-bit CMT0 device included in r8a77970.
- "renesas,r8a77970-cmt1" for the 48-bit CMT1 device included in r8a77970.
- "renesas,r8a77980-cmt0" for the 32-bit CMT0 device included in r8a77980.
......@@ -47,9 +53,12 @@ Required Properties:
and RZ/G1.
These are fallbacks for r8a73a4, R-Car Gen2 and RZ/G1 entries
listed above.
- "renesas,rcar-gen3-cmt0" for 32-bit CMT0 devices included in R-Car Gen3.
- "renesas,rcar-gen3-cmt1" for 48-bit CMT1 devices included in R-Car Gen3.
These are fallbacks for R-Car Gen3 entries listed above.
- "renesas,rcar-gen3-cmt0" for 32-bit CMT0 devices included in R-Car Gen3
and RZ/G2.
- "renesas,rcar-gen3-cmt1" for 48-bit CMT1 devices included in R-Car Gen3
and RZ/G2.
These are fallbacks for R-Car Gen3 and RZ/G2 entries listed
above.
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
......
......@@ -26,6 +26,7 @@ config ARC
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_PENDING_IRQ if SMP
select GENERIC_SCHED_CLOCK
select GENERIC_SMP_IDLE_THREAD
select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
......
......@@ -105,6 +105,14 @@ config OWL_TIMER
help
Enables the support for the Actions Semi Owl timer driver.
config RDA_TIMER
bool "RDA timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
select TIMER_OF
help
Enables the support for the RDA Micro timer driver.
config SUN4I_TIMER
bool "Sun4i timer driver" if COMPILE_TEST
depends on HAS_IOMEM
......@@ -163,12 +171,6 @@ config CLKSRC_NOMADIK_MTU
to multiple interrupt generating programmable
32-bit free running decrementing counters.
config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
bool
depends on CLKSRC_NOMADIK_MTU
help
Use the Multi Timer Unit as the sched_clock.
config CLKSRC_DBX500_PRCMU
bool "Clocksource PRCMU Timer" if COMPILE_TEST
depends on HAS_IOMEM
......@@ -226,13 +228,6 @@ config INTEGRATOR_AP_TIMER
help
Enables support for the Integrator-ap timer.
config CLKSRC_DBX500_PRCMU_SCHED_CLOCK
bool "Clocksource PRCMU Timer sched_clock"
depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK)
default y
help
Use the always on PRCMU Timer as sched_clock
config CLKSRC_EFM32
bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32
depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
......@@ -290,6 +285,7 @@ config CLKSRC_MPS2
config ARC_TIMERS
bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK
select TIMER_OF
help
These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores
......@@ -580,7 +576,7 @@ config H8300_TPU
config CLKSRC_IMX_GPT
bool "Clocksource using i.MX GPT" if COMPILE_TEST
depends on ARM && CLKDEV_LOOKUP
depends on (ARM || ARM64) && CLKDEV_LOOKUP
select CLKSRC_MMIO
config CLKSRC_IMX_TPM
......@@ -611,7 +607,7 @@ config ATCPIT100_TIMER
config RISCV_TIMER
bool "Timer for the RISC-V platform"
depends on RISCV
depends on GENERIC_SCHED_CLOCK && RISCV
default y
select TIMER_PROBE
select TIMER_OF
......
......@@ -20,7 +20,7 @@ obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o
obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_ROCKCHIP_TIMER) += timer-rockchip.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += timer-armada-370-xp.o
......@@ -32,10 +32,10 @@ obj-$(CONFIG_MXS_TIMER) += mxs_timer.o
obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o
obj-$(CONFIG_U300_TIMER) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN4I_TIMER) += timer-sun4i.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o
obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o
obj-$(CONFIG_MESON6_TIMER) += timer-meson6.o
obj-$(CONFIG_TEGRA_TIMER) += timer-tegra20.o
obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o
obj-$(CONFIG_NSPIRE_TIMER) += timer-zevio.o
obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o
......@@ -57,6 +57,7 @@ obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o
obj-$(CONFIG_OWL_TIMER) += timer-owl.o
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
......@@ -78,6 +79,6 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
......@@ -23,6 +23,7 @@
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <soc/arc/timers.h>
#include <soc/arc/mcip.h>
......@@ -88,6 +89,11 @@ static u64 arc_read_gfrc(struct clocksource *cs)
return (((u64)h) << 32) | l;
}
static notrace u64 arc_gfrc_clock_read(void)
{
return arc_read_gfrc(NULL);
}
static struct clocksource arc_counter_gfrc = {
.name = "ARConnect GFRC",
.rating = 400,
......@@ -111,6 +117,8 @@ static int __init arc_cs_setup_gfrc(struct device_node *node)
if (ret)
return ret;
sched_clock_register(arc_gfrc_clock_read, 64, arc_timer_freq);
return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
}
TIMER_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
......@@ -139,6 +147,11 @@ static u64 arc_read_rtc(struct clocksource *cs)
return (((u64)h) << 32) | l;
}
static notrace u64 arc_rtc_clock_read(void)
{
return arc_read_rtc(NULL);
}
static struct clocksource arc_counter_rtc = {
.name = "ARCv2 RTC",
.rating = 350,
......@@ -170,6 +183,8 @@ static int __init arc_cs_setup_rtc(struct device_node *node)
write_aux_reg(AUX_RTC_CTRL, 1);
sched_clock_register(arc_rtc_clock_read, 64, arc_timer_freq);
return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
}
TIMER_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
......@@ -185,6 +200,11 @@ static u64 arc_read_timer1(struct clocksource *cs)
return (u64) read_aux_reg(ARC_REG_TIMER1_CNT);
}
static notrace u64 arc_timer1_clock_read(void)
{
return arc_read_timer1(NULL);
}
static struct clocksource arc_counter_timer1 = {
.name = "ARC Timer1",
.rating = 300,
......@@ -209,6 +229,8 @@ static int __init arc_cs_setup_timer1(struct device_node *node)
write_aux_reg(ARC_REG_TIMER1_CNT, 0);
write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
sched_clock_register(arc_timer1_clock_read, 32, arc_timer_freq);
return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq);
}
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012 Simon Arlott
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/bitops.h>
......
......@@ -15,7 +15,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clockchips.h>
#include <linux/sched_clock.h>
#define RATE_32K 32768
......@@ -26,8 +25,6 @@
#define PRCMU_TIMER_DOWNCOUNT 0x4
#define PRCMU_TIMER_MODE 0x8
#define SCHED_CLOCK_MIN_WRAP 131072 /* 2^32 / 32768 */
static void __iomem *clksrc_dbx500_timer_base;
static u64 notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
......@@ -46,24 +43,12 @@ static u64 notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
static struct clocksource clocksource_dbx500_prcmu = {
.name = "dbx500-prcmu-timer",
.rating = 300,
.rating = 100,
.read = clksrc_dbx500_prcmu_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
};
#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
static u64 notrace dbx500_prcmu_sched_clock_read(void)
{
if (unlikely(!clksrc_dbx500_timer_base))
return 0;
return clksrc_dbx500_prcmu_read(&clocksource_dbx500_prcmu);
}
#endif
static int __init clksrc_dbx500_prcmu_init(struct device_node *node)
{
clksrc_dbx500_timer_base = of_iomap(node, 0);
......@@ -81,9 +66,6 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node)
writel(TIMER_DOWNCOUNT_VAL,
clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
}
#ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK
sched_clock_register(dbx500_prcmu_sched_clock_read, 32, RATE_32K);
#endif
return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
}
TIMER_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
......
......@@ -69,7 +69,6 @@ static u32 clk_prescale;
static u32 nmdk_cycle; /* write-once */
static struct delay_timer mtu_delay_timer;
#ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
......@@ -82,7 +81,6 @@ static u64 notrace nomadik_read_sched_clock(void)
return -readl(mtu_base + MTU_VAL(0));
}
#endif
static unsigned long nmdk_timer_read_current_timer(void)
{
......@@ -234,9 +232,7 @@ static int __init nmdk_timer_init(void __iomem *base, int irq,
return ret;
}
#ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK
sched_clock_register(nomadik_read_sched_clock, 32, rate);
#endif
/* Timer 1 is used for events, register irq and clockevents */
setup_irq(irq, &nmdk_timer_irq);
......
......@@ -21,7 +21,7 @@
#include <linux/delay.h>
/*
* Register definitions for the timers
* Register definitions common for all the timer variants.
*/
#define TIMER1_COUNT (0x00)
#define TIMER1_LOAD (0x04)
......@@ -36,9 +36,10 @@
#define TIMER3_MATCH1 (0x28)
#define TIMER3_MATCH2 (0x2c)
#define TIMER_CR (0x30)
#define TIMER_INTR_STATE (0x34)
#define TIMER_INTR_MASK (0x38)
/*
* Control register (TMC30) bit fields for fttmr010/gemini/moxart timers.
*/
#define TIMER_1_CR_ENABLE BIT(0)
#define TIMER_1_CR_CLOCK BIT(1)
#define TIMER_1_CR_INT BIT(2)
......@@ -53,8 +54,9 @@
#define TIMER_3_CR_UPDOWN BIT(11)
/*
* The Aspeed AST2400 moves bits around in the control register
* and lacks bits for setting the timer to count upwards.
* Control register (TMC30) bit fields for aspeed ast2400/ast2500 timers.
* The aspeed timers move bits around in the control register and lacks
* bits for setting the timer to count upwards.
*/
#define TIMER_1_CR_ASPEED_ENABLE BIT(0)
#define TIMER_1_CR_ASPEED_CLOCK BIT(1)
......@@ -66,6 +68,18 @@
#define TIMER_3_CR_ASPEED_CLOCK BIT(9)
#define TIMER_3_CR_ASPEED_INT BIT(10)
/*
* Interrupt status/mask register definitions for fttmr010/gemini/moxart
* timers.
* The registers don't exist and they are not needed on aspeed timers
* because:
* - aspeed timer overflow interrupt is controlled by bits in Control
* Register (TMC30).
* - aspeed timers always generate interrupt when either one of the
* Match registers equals to Status register.
*/
#define TIMER_INTR_STATE (0x34)
#define TIMER_INTR_MASK (0x38)
#define TIMER_1_INT_MATCH1 BIT(0)
#define TIMER_1_INT_MATCH2 BIT(1)
#define TIMER_1_INT_OVERFLOW BIT(2)
......@@ -80,7 +94,7 @@
struct fttmr010 {
void __iomem *base;
unsigned int tick_rate;
bool count_down;
bool is_aspeed;
u32 t1_enable_val;
struct clock_event_device clkevt;
#ifdef CONFIG_ARM
......@@ -130,7 +144,7 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
cr &= ~fttmr010->t1_enable_val;
writel(cr, fttmr010->base + TIMER_CR);
if (fttmr010->count_down) {
if (fttmr010->is_aspeed) {
/*
* ASPEED Timer Controller will load TIMER1_LOAD register
* into TIMER1_COUNT register when the timer is re-enabled.
......@@ -175,16 +189,17 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
/* Setup counter start from 0 or ~0 */
writel(0, fttmr010->base + TIMER1_COUNT);
if (fttmr010->count_down)
if (fttmr010->is_aspeed) {
writel(~0, fttmr010->base + TIMER1_LOAD);
else
} else {
writel(0, fttmr010->base + TIMER1_LOAD);
/* Enable interrupt */
cr = readl(fttmr010->base + TIMER_INTR_MASK);
cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
cr |= TIMER_1_INT_MATCH1;
writel(cr, fttmr010->base + TIMER_INTR_MASK);
/* Enable interrupt */
cr = readl(fttmr010->base + TIMER_INTR_MASK);
cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2);
cr |= TIMER_1_INT_MATCH1;
writel(cr, fttmr010->base + TIMER_INTR_MASK);
}
return 0;
}
......@@ -201,9 +216,8 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
writel(cr, fttmr010->base + TIMER_CR);
/* Setup timer to fire at 1/HZ intervals. */
if (fttmr010->count_down) {
if (fttmr010->is_aspeed) {
writel(period, fttmr010->base + TIMER1_LOAD);
writel(0, fttmr010->base + TIMER1_MATCH1);
} else {
cr = 0xffffffff - (period - 1);
writel(cr, fttmr010->base + TIMER1_COUNT);
......@@ -281,23 +295,21 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
}
/*
* The Aspeed AST2400 moves bits around in the control register,
* otherwise it works the same.
* The Aspeed timers move bits around in the control register.
*/
if (is_aspeed) {
fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE |
TIMER_1_CR_ASPEED_INT;
/* Downward not available */
fttmr010->count_down = true;
fttmr010->is_aspeed = true;
} else {
fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT;
}
/*
* Reset the interrupt mask and status
*/
writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
writel(0, fttmr010->base + TIMER_INTR_STATE);
/*
* Reset the interrupt mask and status
*/
writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK);
writel(0, fttmr010->base + TIMER_INTR_STATE);
}
/*
* Enable timer 1 count up, timer 2 count up, except on Aspeed,
......@@ -306,9 +318,8 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
if (is_aspeed)
val = TIMER_2_CR_ASPEED_ENABLE;
else {
val = TIMER_2_CR_ENABLE;
if (!fttmr010->count_down)
val |= TIMER_1_CR_UPDOWN | TIMER_2_CR_UPDOWN;
val = TIMER_2_CR_ENABLE | TIMER_1_CR_UPDOWN |
TIMER_2_CR_UPDOWN;
}
writel(val, fttmr010->base + TIMER_CR);
......@@ -321,7 +332,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
writel(0, fttmr010->base + TIMER2_MATCH1);
writel(0, fttmr010->base + TIMER2_MATCH2);
if (fttmr010->count_down) {
if (fttmr010->is_aspeed) {
writel(~0, fttmr010->base + TIMER2_LOAD);
clocksource_mmio_init(fttmr010->base + TIMER2_COUNT,
"FTTMR010-TIMER2",
......@@ -371,7 +382,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
#ifdef CONFIG_ARM
/* Also use this timer for delays */
if (fttmr010->count_down)
if (fttmr010->is_aspeed)
fttmr010->delay_timer.read_current_timer =
fttmr010_read_current_timer_down;
else
......
......@@ -141,21 +141,25 @@ static u64 notrace mxc_read_sched_clock(void)
return sched_clock_reg ? readl_relaxed(sched_clock_reg) : 0;
}
#if defined(CONFIG_ARM)
static struct delay_timer imx_delay_timer;
static unsigned long imx_read_current_timer(void)
{
return readl_relaxed(sched_clock_reg);
}
#endif
static int __init mxc_clocksource_init(struct imx_timer *imxtm)
{
unsigned int c = clk_get_rate(imxtm->clk_per);
void __iomem *reg = imxtm->base + imxtm->gpt->reg_tcn;
#if defined(CONFIG_ARM)
imx_delay_timer.read_current_timer = &imx_read_current_timer;
imx_delay_timer.freq = c;
register_current_timer_delay(&imx_delay_timer);
#endif
sched_clock_reg = reg;
......@@ -198,15 +202,8 @@ static int v2_set_next_event(unsigned long evt,
static int mxc_shutdown(struct clock_event_device *ced)
{
struct imx_timer *imxtm = to_imx_timer(ced);
unsigned long flags;
u32 tcn;
/*
* The timer interrupt generation is disabled at least
* for enough time to call mxc_set_next_event()
*/
local_irq_save(flags);
/* Disable interrupt in GPT module */
imxtm->gpt->gpt_irq_disable(imxtm);
......@@ -221,21 +218,12 @@ static int mxc_shutdown(struct clock_event_device *ced)
printk(KERN_INFO "%s: changing mode\n", __func__);
#endif /* DEBUG */
local_irq_restore(flags);
return 0;
}
static int mxc_set_oneshot(struct clock_event_device *ced)
{
struct imx_timer *imxtm = to_imx_timer(ced);
unsigned long flags;
/*
* The timer interrupt generation is disabled at least
* for enough time to call mxc_set_next_event()
*/
local_irq_save(flags);
/* Disable interrupt in GPT module */
imxtm->gpt->gpt_irq_disable(imxtm);
......@@ -260,7 +248,6 @@ static int mxc_set_oneshot(struct clock_event_device *ced)
* mode switching
*/
imxtm->gpt->gpt_irq_enable(imxtm);
local_irq_restore(flags);
return 0;
}
......
......@@ -12,6 +12,8 @@
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include "timer-of.h"
#define TPM_PARAM 0x4
#define TPM_PARAM_WIDTH_SHIFT 16
#define TPM_PARAM_WIDTH_MASK (0xff << 16)
......@@ -33,9 +35,7 @@
#define TPM_C0V 0x24
static int counter_width;
static int rating;
static void __iomem *timer_base;
static struct clock_event_device clockevent_tpm;
static inline void tpm_timer_disable(void)
{
......@@ -80,19 +80,6 @@ static u64 notrace tpm_read_sched_clock(void)
return tpm_read_counter();
}
static int __init tpm_clocksource_init(unsigned long rate)
{
tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
tpm_delay_timer.freq = rate;
register_current_timer_delay(&tpm_delay_timer);
sched_clock_register(tpm_read_sched_clock, counter_width, rate);
return clocksource_mmio_init(timer_base + TPM_CNT, "imx-tpm",
rate, rating, counter_width,
clocksource_mmio_readl_up);
}
static int tpm_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
......@@ -137,74 +124,80 @@ static irqreturn_t tpm_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static struct clock_event_device clockevent_tpm = {
.name = "i.MX7ULP TPM Timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_state_oneshot = tpm_set_state_oneshot,
.set_next_event = tpm_set_next_event,
.set_state_shutdown = tpm_set_state_shutdown,
static struct timer_of to_tpm = {
.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
.clkevt = {
.name = "i.MX7ULP TPM Timer",
.rating = 200,
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_state_shutdown = tpm_set_state_shutdown,
.set_state_oneshot = tpm_set_state_oneshot,
.set_next_event = tpm_set_next_event,
.cpumask = cpu_possible_mask,
},
.of_irq = {
.handler = tpm_timer_interrupt,
.flags = IRQF_TIMER | IRQF_IRQPOLL,
},
.of_clk = {
.name = "per",
},
};
static int __init tpm_clockevent_init(unsigned long rate, int irq)
static int __init tpm_clocksource_init(void)
{
int ret;
tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
tpm_delay_timer.freq = timer_of_rate(&to_tpm) >> 3;
register_current_timer_delay(&tpm_delay_timer);
ret = request_irq(irq, tpm_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
"i.MX7ULP TPM Timer", &clockevent_tpm);
sched_clock_register(tpm_read_sched_clock, counter_width,
timer_of_rate(&to_tpm) >> 3);
clockevent_tpm.rating = rating;
clockevent_tpm.cpumask = cpumask_of(0);
clockevent_tpm.irq = irq;
clockevents_config_and_register(&clockevent_tpm, rate, 300,
GENMASK(counter_width - 1, 1));
return clocksource_mmio_init(timer_base + TPM_CNT,
"imx-tpm",
timer_of_rate(&to_tpm) >> 3,
to_tpm.clkevt.rating,
counter_width,
clocksource_mmio_readl_up);
}
return ret;
static void __init tpm_clockevent_init(void)
{
clockevents_config_and_register(&to_tpm.clkevt,
timer_of_rate(&to_tpm) >> 3,
300,
GENMASK(counter_width - 1,
1));
}
static int __init tpm_timer_init(struct device_node *np)
{
struct clk *ipg, *per;
int irq, ret;
u32 rate;
timer_base = of_iomap(np, 0);
if (!timer_base) {
pr_err("tpm: failed to get base address\n");
return -ENXIO;
}
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
pr_err("tpm: failed to get irq\n");
ret = -ENOENT;
goto err_iomap;
}
struct clk *ipg;
int ret;
ipg = of_clk_get_by_name(np, "ipg");
per = of_clk_get_by_name(np, "per");
if (IS_ERR(ipg) || IS_ERR(per)) {
pr_err("tpm: failed to get ipg or per clk\n");
ret = -ENODEV;
goto err_clk_get;
if (IS_ERR(ipg)) {
pr_err("tpm: failed to get ipg clk\n");
return -ENODEV;
}
/* enable clk before accessing registers */
ret = clk_prepare_enable(ipg);
if (ret) {
pr_err("tpm: ipg clock enable failed (%d)\n", ret);
goto err_clk_get;
clk_put(ipg);
return ret;
}
ret = clk_prepare_enable(per);
if (ret) {
pr_err("tpm: per clock enable failed (%d)\n", ret);
goto err_per_clk_enable;
}
ret = timer_of_init(np, &to_tpm);
if (ret)
return ret;
timer_base = timer_of_base(&to_tpm);
counter_width = (readl(timer_base + TPM_PARAM) & TPM_PARAM_WIDTH_MASK)
>> TPM_PARAM_WIDTH_SHIFT;
counter_width = (readl(timer_base + TPM_PARAM)
& TPM_PARAM_WIDTH_MASK) >> TPM_PARAM_WIDTH_SHIFT;
/* use rating 200 for 32-bit counter and 150 for 16-bit counter */
rating = counter_width == 0x20 ? 200 : 150;
to_tpm.clkevt.rating = counter_width == 0x20 ? 200 : 150;
/*
* Initialize tpm module to a known state
......@@ -229,29 +222,13 @@ static int __init tpm_timer_init(struct device_node *np)
writel(TPM_SC_CMOD_INC_PER_CNT |
(counter_width == 0x20 ?
TPM_SC_CMOD_DIV_DEFAULT : TPM_SC_CMOD_DIV_MAX),
timer_base + TPM_SC);
timer_base + TPM_SC);
/* set MOD register to maximum for free running mode */
writel(GENMASK(counter_width - 1, 0), timer_base + TPM_MOD);
rate = clk_get_rate(per) >> 3;
ret = tpm_clocksource_init(rate);
if (ret)
goto err_per_clk_enable;
ret = tpm_clockevent_init(rate, irq);
if (ret)
goto err_per_clk_enable;
return 0;
tpm_clockevent_init();
err_per_clk_enable:
clk_disable_unprepare(ipg);
err_clk_get:
clk_put(per);
clk_put(ipg);
err_iomap:
iounmap(timer_base);
return ret;
return tpm_clocksource_init();
}
TIMER_OF_DECLARE(imx7ulp, "fsl,imx7ulp-tpm", tpm_timer_init);
......@@ -181,8 +181,7 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
int irq;
struct clk *clk;
unsigned long rate;
struct device_node *pri_node;
struct device_node *sec_node;
struct device_node *alias_node;
base = of_io_request_and_map(node, 0, "integrator-timer");
if (IS_ERR(base))
......@@ -204,7 +203,18 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
return err;
}
pri_node = of_find_node_by_path(path);
alias_node = of_find_node_by_path(path);
/*
* The pointer is used as an identifier not as a pointer, we
* can drop the refcount on the of__node immediately after
* getting it.
*/
of_node_put(alias_node);
if (node == alias_node)
/* The primary timer lacks IRQ, use as clocksource */
return integrator_clocksource_init(rate, base);
err = of_property_read_string(of_aliases,
"arm,timer-secondary", &path);
......@@ -213,14 +223,11 @@ static int __init integrator_ap_timer_init_of(struct device_node *node)
return err;
}
alias_node = of_find_node_by_path(path);
sec_node = of_find_node_by_path(path);
if (node == pri_node)
/* The primary timer lacks IRQ, use as clocksource */
return integrator_clocksource_init(rate, base);
of_node_put(alias_node);
if (node == sec_node) {
if (node == alias_node) {
/* The secondary timer will drive the clock event */
irq = irq_of_parse_and_map(node, 0);
return integrator_clockevent_init(rate, base, irq);
......
......@@ -10,6 +10,8 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
......@@ -20,80 +22,112 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#define CED_ID 0
#define CSD_ID 4
#ifdef CONFIG_ARM
#include <linux/delay.h>
#endif
#define MESON_ISA_TIMER_MUX 0x00
#define MESON_ISA_TIMER_MUX_TIMERD_EN BIT(19)
#define MESON_ISA_TIMER_MUX_TIMERC_EN BIT(18)
#define MESON_ISA_TIMER_MUX_TIMERB_EN BIT(17)
#define MESON_ISA_TIMER_MUX_TIMERA_EN BIT(16)
#define MESON_ISA_TIMER_MUX_TIMERD_MODE BIT(15)
#define MESON_ISA_TIMER_MUX_TIMERC_MODE BIT(14)
#define MESON_ISA_TIMER_MUX_TIMERB_MODE BIT(13)
#define MESON_ISA_TIMER_MUX_TIMERA_MODE BIT(12)
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK GENMASK(10, 8)
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_SYSTEM_CLOCK 0x0
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US 0x1
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_10US 0x2
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_100US 0x3
#define MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1MS 0x4
#define MESON_ISA_TIMER_MUX_TIMERD_INPUT_CLOCK_MASK GENMASK(7, 6)
#define MESON_ISA_TIMER_MUX_TIMERC_INPUT_CLOCK_MASK GENMASK(5, 4)
#define MESON_ISA_TIMER_MUX_TIMERB_INPUT_CLOCK_MASK GENMASK(3, 2)
#define MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK GENMASK(1, 0)
#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US 0x0
#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_10US 0x1
#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_100US 0x0
#define MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1MS 0x3
#define MESON_ISA_TIMERA 0x04
#define MESON_ISA_TIMERB 0x08
#define MESON_ISA_TIMERC 0x0c
#define MESON_ISA_TIMERD 0x10
#define MESON_ISA_TIMERE 0x14
#define TIMER_ISA_MUX 0
#define TIMER_ISA_VAL(t) (((t) + 1) << 2)
#define TIMER_INPUT_BIT(t) (2 * (t))
#define TIMER_ENABLE_BIT(t) (16 + (t))
#define TIMER_PERIODIC_BIT(t) (12 + (t))
#define TIMER_CED_INPUT_MASK (3UL << TIMER_INPUT_BIT(CED_ID))
#define TIMER_CSD_INPUT_MASK (7UL << TIMER_INPUT_BIT(CSD_ID))
static void __iomem *timer_base;
#define TIMER_CED_UNIT_1US 0
#define TIMER_CSD_UNIT_1US 1
#ifdef CONFIG_ARM
static unsigned long meson6_read_current_timer(void)
{
return readl_relaxed(timer_base + MESON_ISA_TIMERE);
}
static void __iomem *timer_base;
static struct delay_timer meson6_delay_timer = {
.read_current_timer = meson6_read_current_timer,
.freq = 1000 * 1000,
};
#endif
static u64 notrace meson6_timer_sched_read(void)
{
return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID));
return (u64)readl(timer_base + MESON_ISA_TIMERE);
}
static void meson6_clkevt_time_stop(unsigned char timer)
static void meson6_clkevt_time_stop(void)
{
u32 val = readl(timer_base + TIMER_ISA_MUX);
u32 val = readl(timer_base + MESON_ISA_TIMER_MUX);
writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX);
writel(val & ~MESON_ISA_TIMER_MUX_TIMERA_EN,
timer_base + MESON_ISA_TIMER_MUX);
}
static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay)
static void meson6_clkevt_time_setup(unsigned long delay)
{
writel(delay, timer_base + TIMER_ISA_VAL(timer));
writel(delay, timer_base + MESON_ISA_TIMERA);
}
static void meson6_clkevt_time_start(unsigned char timer, bool periodic)
static void meson6_clkevt_time_start(bool periodic)
{
u32 val = readl(timer_base + TIMER_ISA_MUX);
u32 val = readl(timer_base + MESON_ISA_TIMER_MUX);
if (periodic)
val |= TIMER_PERIODIC_BIT(timer);
val |= MESON_ISA_TIMER_MUX_TIMERA_MODE;
else
val &= ~TIMER_PERIODIC_BIT(timer);
val &= ~MESON_ISA_TIMER_MUX_TIMERA_MODE;
writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX);
writel(val | MESON_ISA_TIMER_MUX_TIMERA_EN,
timer_base + MESON_ISA_TIMER_MUX);
}
static int meson6_shutdown(struct clock_event_device *evt)
{
meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_stop();
return 0;
}
static int meson6_set_oneshot(struct clock_event_device *evt)
{
meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_start(CED_ID, false);
meson6_clkevt_time_stop();
meson6_clkevt_time_start(false);
return 0;
}
static int meson6_set_periodic(struct clock_event_device *evt)
{
meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1);
meson6_clkevt_time_start(CED_ID, true);
meson6_clkevt_time_stop();
meson6_clkevt_time_setup(USEC_PER_SEC / HZ - 1);
meson6_clkevt_time_start(true);
return 0;
}
static int meson6_clkevt_next_event(unsigned long evt,
struct clock_event_device *unused)
{
meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_setup(CED_ID, evt);
meson6_clkevt_time_start(CED_ID, false);
meson6_clkevt_time_stop();
meson6_clkevt_time_setup(evt);
meson6_clkevt_time_start(false);
return 0;
}
......@@ -144,22 +178,24 @@ static int __init meson6_timer_init(struct device_node *node)
}
/* Set 1us for timer E */
val = readl(timer_base + TIMER_ISA_MUX);
val &= ~TIMER_CSD_INPUT_MASK;
val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID);
writel(val, timer_base + TIMER_ISA_MUX);
val = readl(timer_base + MESON_ISA_TIMER_MUX);
val &= ~MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK;
val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_MASK,
MESON_ISA_TIMER_MUX_TIMERE_INPUT_CLOCK_1US);
writel(val, timer_base + MESON_ISA_TIMER_MUX);
sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC);
clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name,
clocksource_mmio_init(timer_base + MESON_ISA_TIMERE, node->name,
1000 * 1000, 300, 32, clocksource_mmio_readl_up);
/* Timer A base 1us */
val &= ~TIMER_CED_INPUT_MASK;
val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID);
writel(val, timer_base + TIMER_ISA_MUX);
val &= ~MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK;
val |= FIELD_PREP(MESON_ISA_TIMER_MUX_TIMERA_INPUT_CLOCK_MASK,
MESON_ISA_TIMER_MUX_TIMERABCD_INPUT_CLOCK_1US);
writel(val, timer_base + MESON_ISA_TIMER_MUX);
/* Stop the timer A */
meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_stop();
ret = setup_irq(irq, &meson6_timer_irq);
if (ret) {
......@@ -172,6 +208,12 @@ static int __init meson6_timer_init(struct device_node *node)
clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC,
1, 0xfffe);
#ifdef CONFIG_ARM
/* Also use MESON_ISA_TIMERE for delays */
register_current_timer_delay(&meson6_delay_timer);
#endif
return 0;
}
TIMER_OF_DECLARE(meson6, "amlogic,meson6-timer",
......
// SPDX-License-Identifier: GPL-2.0+
/*
* RDA8810PL SoC timer driver
*
* Copyright RDA Microelectronics Company Limited
* Copyright (c) 2017 Andreas Färber
* Copyright (c) 2018 Manivannan Sadhasivam
*
* RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
* Each timer provides optional interrupt support. In this driver, OSTIMER is
* used for clockevents and HWTIMER is used for clocksource.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include "timer-of.h"
#define RDA_OSTIMER_LOADVAL_L 0x000
#define RDA_OSTIMER_CTRL 0x004
#define RDA_HWTIMER_LOCKVAL_L 0x024
#define RDA_HWTIMER_LOCKVAL_H 0x028
#define RDA_TIMER_IRQ_MASK_SET 0x02c
#define RDA_TIMER_IRQ_MASK_CLR 0x030
#define RDA_TIMER_IRQ_CLR 0x034
#define RDA_OSTIMER_CTRL_ENABLE BIT(24)
#define RDA_OSTIMER_CTRL_REPEAT BIT(28)
#define RDA_OSTIMER_CTRL_LOAD BIT(30)
#define RDA_TIMER_IRQ_MASK_OSTIMER BIT(0)
#define RDA_TIMER_IRQ_CLR_OSTIMER BIT(0)
static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
{
u32 ctrl, load_l;
load_l = (u32)cycles;
ctrl = ((cycles >> 32) & 0xffffff);
ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
if (periodic)
ctrl |= RDA_OSTIMER_CTRL_REPEAT;
/* Enable ostimer interrupt first */
writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
base + RDA_TIMER_IRQ_MASK_SET);
/* Write low 32 bits first, high 24 bits are with ctrl */
writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
return 0;
}
static int rda_ostimer_stop(void __iomem *base)
{
/* Disable ostimer interrupt first */
writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
base + RDA_TIMER_IRQ_MASK_CLR);
writel_relaxed(0, base + RDA_OSTIMER_CTRL);
return 0;
}
static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
rda_ostimer_stop(timer_of_base(to));
return 0;
}
static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
rda_ostimer_stop(timer_of_base(to));
return 0;
}
static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
unsigned long cycles_per_jiffy;
rda_ostimer_stop(timer_of_base(to));
cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
evt->mult) >> evt->shift;
rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
return 0;
}
static int rda_ostimer_tick_resume(struct clock_event_device *evt)
{
return 0;
}
static int rda_ostimer_set_next_event(unsigned long evt,
struct clock_event_device *ev)
{
struct timer_of *to = to_timer_of(ev);
rda_ostimer_start(timer_of_base(to), false, evt);
return 0;
}
static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
struct timer_of *to = to_timer_of(evt);
/* clear timer int */
writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
timer_of_base(to) + RDA_TIMER_IRQ_CLR);
if (evt->event_handler)
evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct timer_of rda_ostimer_of = {
.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
.clkevt = {
.name = "rda-ostimer",
.rating = 250,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_DYNIRQ,
.set_state_shutdown = rda_ostimer_set_state_shutdown,
.set_state_oneshot = rda_ostimer_set_state_oneshot,
.set_state_periodic = rda_ostimer_set_state_periodic,
.tick_resume = rda_ostimer_tick_resume,
.set_next_event = rda_ostimer_set_next_event,
},
.of_base = {
.name = "rda-timer",
.index = 0,
},
.of_irq = {
.name = "ostimer",
.handler = rda_ostimer_interrupt,
.flags = IRQF_TIMER,
},
};
static u64 rda_hwtimer_read(struct clocksource *cs)
{
void __iomem *base = timer_of_base(&rda_ostimer_of);
u32 lo, hi;
/* Always read low 32 bits first */
do {
lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
return ((u64)hi << 32) | lo;
}
static struct clocksource rda_hwtimer_clocksource = {
.name = "rda-timer",
.rating = 400,
.read = rda_hwtimer_read,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init rda_timer_init(struct device_node *np)
{
unsigned long rate = 2000000;
int ret;
ret = timer_of_init(np, &rda_ostimer_of);
if (ret)
return ret;
clocksource_register_hz(&rda_hwtimer_clocksource, rate);
clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
0x2, UINT_MAX);
return 0;
}
TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);
......@@ -8,6 +8,7 @@
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/sched_clock.h>
#include <asm/smp.h>
#include <asm/sbi.h>
......@@ -49,6 +50,11 @@ static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs)
return get_cycles64();
}
static u64 riscv_sched_clock(void)
{
return get_cycles64();
}
static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
.name = "riscv_clocksource",
.rating = 300,
......@@ -97,6 +103,9 @@ static int __init riscv_timer_init_dt(struct device_node *n)
cs = per_cpu_ptr(&riscv_clocksource, cpuid);
clocksource_register_hz(cs, riscv_timebase);
sched_clock_register(riscv_sched_clock,
BITS_PER_LONG, riscv_timebase);
error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,
"clockevents/riscv/timer:starting",
riscv_timer_starting_cpu, riscv_timer_dying_cpu);
......
......@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <asm/mach/time.h>
#include <asm/smp_twd.h>
#define RTC_SECONDS 0x08
#define RTC_SHADOW_SECONDS 0x0c
......
......@@ -991,7 +991,6 @@ static struct platform_driver omap_dm_timer_driver = {
},
};
early_platform_init("earlytimer", &omap_dm_timer_driver);
module_platform_driver(omap_dm_timer_driver);
MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
......
......@@ -145,7 +145,7 @@ static int __init vt8500_timer_init(struct device_node *np)
ret = clocksource_register_hz(&clocksource, VT8500_TIMER_HZ);
if (ret) {
pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n",
pr_err("%s: clocksource_register failed for %s\n",
__func__, clocksource.name);
return ret;
}
......
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