Commit 3f6ec19f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'timers-core-2021-02-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "Time and timer updates:

   - Instead of new drivers remove tango, sirf, u300 and atlas drivers

   - Add suspend/resume support for microchip pit64b

   - The usual fixes, improvements and cleanups here and there"

* tag 'timers-core-2021-02-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  timens: Delete no-op time_ns_init()
  alarmtimer: Update kerneldoc
  clocksource/drivers/timer-microchip-pit64b: Add clocksource suspend/resume
  clocksource/drivers/prima: Remove sirf prima driver
  clocksource/drivers/atlas: Remove sirf atlas driver
  clocksource/drivers/tango: Remove tango driver
  clocksource/drivers/u300: Remove the u300 driver
  dt-bindings: timer: nuvoton: Clarify that interrupt of timer 0 should be specified
  clocksource/drivers/davinci: Move pr_fmt() before the includes
  clocksource/drivers/efm32: Drop unused timer code
parents b5183bc9 11db5710
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -6,8 +6,7 @@ timer counters.
Required properties:
- compatible      : "nuvoton,npcm750-timer" for Poleg NPCM750.
- reg             : Offset and length of the register set for the device.
- interrupts      : Contain the timer interrupt with flags for
                    falling edge.
- interrupts      : Contain the timer interrupt of timer 0.
- clocks          : phandle of timer reference clock (usually a 25 MHz clock).

Example:
+0 −18
Original line number Diff line number Diff line
ST-Ericsson U300 apptimer

Required properties:

- compatible : should be "stericsson,u300-apptimer"
- reg : Specifies base physical address and size of the registers.
- interrupts : A list of 4 interrupts; one for each subtimer. These
  are, in order: OS (operating system), DD (device driver) both
  adopted for EPOC/Symbian with two specific IRQs for these tasks,
  then GP1 and GP2, which are general-purpose timers.

Example:

timer {
	compatible = "stericsson,u300-apptimer";
	reg = <0xc0014000 0x1000>;
	interrupts = <24 25 26 27>;
};
+0 −36
Original line number Diff line number Diff line
@@ -197,12 +197,6 @@ config CLPS711X_TIMER
	help
	  Enables support for the Cirrus Logic PS711 timer.

config ATLAS7_TIMER
	bool "Atlas7 timer driver" if COMPILE_TEST
	select CLKSRC_MMIO
	help
	  Enables support for the Atlas7 timer.

config MXS_TIMER
	bool "MXS timer driver" if COMPILE_TEST
	select CLKSRC_MMIO
@@ -210,19 +204,6 @@ config MXS_TIMER
	help
	  Enables support for the MXS timer.

config PRIMA2_TIMER
	bool "Prima2 timer driver" if COMPILE_TEST
	select CLKSRC_MMIO
	help
	  Enables support for the Prima2 timer.

config U300_TIMER
	bool "U300 timer driver" if COMPILE_TEST
	depends on ARM
	select CLKSRC_MMIO
	help
	  Enables support for the U300 timer.

config NSPIRE_TIMER
	bool "NSpire timer driver" if COMPILE_TEST
	select CLKSRC_MMIO
@@ -242,15 +223,6 @@ config INTEGRATOR_AP_TIMER
	help
	  Enables support for the Integrator-AP timer.

config CLKSRC_EFM32
	bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32
	depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
	select CLKSRC_MMIO
	default ARCH_EFM32
	help
	  Support to use the timers of EFM32 SoCs as clock source and clock
	  event device.

config CLKSRC_LPC32XX
	bool "Clocksource for LPC32XX" if COMPILE_TEST
	depends on HAS_IOMEM
@@ -567,14 +539,6 @@ config CLKSRC_MIPS_GIC
	select CLOCKSOURCE_WATCHDOG
	select TIMER_OF

config CLKSRC_TANGO_XTAL
	bool "Clocksource for Tango SoC" if COMPILE_TEST
	depends on ARM
	select TIMER_OF
	select CLKSRC_MMIO
	help
	  This enables the clocksource for Tango SoC.

config CLKSRC_PXA
	bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
	depends on HAS_IOMEM
+0 −5
Original line number Diff line number Diff line
@@ -30,11 +30,8 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER) += timer-armada-370-xp.o
obj-$(CONFIG_ORION_TIMER)	+= timer-orion.o
obj-$(CONFIG_BCM2835_TIMER)	+= bcm2835_timer.o
obj-$(CONFIG_CLPS711X_TIMER)	+= clps711x-timer.o
obj-$(CONFIG_ATLAS7_TIMER)	+= timer-atlas7.o
obj-$(CONFIG_MXS_TIMER)		+= mxs_timer.o
obj-$(CONFIG_CLKSRC_PXA)	+= timer-pxa.o
obj-$(CONFIG_PRIMA2_TIMER)	+= timer-prima2.o
obj-$(CONFIG_U300_TIMER)	+= timer-u300.o
obj-$(CONFIG_SUN4I_TIMER)	+= timer-sun4i.o
obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER)	+= timer-meson6.o
@@ -43,7 +40,6 @@ obj-$(CONFIG_VT8500_TIMER) += timer-vt8500.o
obj-$(CONFIG_NSPIRE_TIMER)	+= timer-zevio.o
obj-$(CONFIG_BCM_KONA_TIMER)	+= bcm_kona_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
obj-$(CONFIG_CLKSRC_EFM32)	+= timer-efm32.o
obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
@@ -73,7 +69,6 @@ obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o
obj-$(CONFIG_INTEGRATOR_AP_TIMER)	+= timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE)		+= timer-versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
obj-$(CONFIG_CLKSRC_TANGO_XTAL)		+= timer-tango-xtal.o
obj-$(CONFIG_CLKSRC_IMX_GPT)		+= timer-imx-gpt.o
obj-$(CONFIG_CLKSRC_IMX_TPM)		+= timer-imx-tpm.o
obj-$(CONFIG_TIMER_IMX_SYS_CTR)		+= timer-imx-sysctr.o
+0 −281
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * System timer for CSR SiRFprimaII
 *
 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
 */

#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/sched_clock.h>

#define SIRFSOC_TIMER_32COUNTER_0_CTRL			0x0000
#define SIRFSOC_TIMER_32COUNTER_1_CTRL			0x0004
#define SIRFSOC_TIMER_MATCH_0				0x0018
#define SIRFSOC_TIMER_MATCH_1				0x001c
#define SIRFSOC_TIMER_COUNTER_0				0x0048
#define SIRFSOC_TIMER_COUNTER_1				0x004c
#define SIRFSOC_TIMER_INTR_STATUS			0x0060
#define SIRFSOC_TIMER_WATCHDOG_EN			0x0064
#define SIRFSOC_TIMER_64COUNTER_CTRL			0x0068
#define SIRFSOC_TIMER_64COUNTER_LO			0x006c
#define SIRFSOC_TIMER_64COUNTER_HI			0x0070
#define SIRFSOC_TIMER_64COUNTER_LOAD_LO			0x0074
#define SIRFSOC_TIMER_64COUNTER_LOAD_HI			0x0078
#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO		0x007c
#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI		0x0080

#define SIRFSOC_TIMER_REG_CNT 6

static unsigned long atlas7_timer_rate;

static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
	SIRFSOC_TIMER_WATCHDOG_EN,
	SIRFSOC_TIMER_32COUNTER_0_CTRL,
	SIRFSOC_TIMER_32COUNTER_1_CTRL,
	SIRFSOC_TIMER_64COUNTER_CTRL,
	SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
	SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
};

static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];

static void __iomem *sirfsoc_timer_base;

/* disable count and interrupt */
static inline void sirfsoc_timer_count_disable(int idx)
{
	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
}

/* enable count and interrupt */
static inline void sirfsoc_timer_count_enable(int idx)
{
	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
}

/* timer interrupt handler */
static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *ce = dev_id;
	int cpu = smp_processor_id();

	/* clear timer interrupt */
	writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);

	if (clockevent_state_oneshot(ce))
		sirfsoc_timer_count_disable(cpu);

	ce->event_handler(ce);

	return IRQ_HANDLED;
}

/* read 64-bit timer counter */
static u64 sirfsoc_timer_read(struct clocksource *cs)
{
	u64 cycles;

	writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
			BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);

	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);

	return cycles;
}

static int sirfsoc_timer_set_next_event(unsigned long delta,
	struct clock_event_device *ce)
{
	int cpu = smp_processor_id();

	/* disable timer first, then modify the related registers */
	sirfsoc_timer_count_disable(cpu);

	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
		4 * cpu);
	writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
		4 * cpu);

	/* enable the tick */
	sirfsoc_timer_count_enable(cpu);

	return 0;
}

/* Oneshot is enabled in set_next_event */
static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
{
	sirfsoc_timer_count_disable(smp_processor_id());
	return 0;
}

static void sirfsoc_clocksource_suspend(struct clocksource *cs)
{
	int i;

	for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
		sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
}

static void sirfsoc_clocksource_resume(struct clocksource *cs)
{
	int i;

	for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
		writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);

	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);

	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
}

static struct clock_event_device __percpu *sirfsoc_clockevent;

static struct clocksource sirfsoc_clocksource = {
	.name = "sirfsoc_clocksource",
	.rating = 200,
	.mask = CLOCKSOURCE_MASK(64),
	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
	.read = sirfsoc_timer_read,
	.suspend = sirfsoc_clocksource_suspend,
	.resume = sirfsoc_clocksource_resume,
};

static unsigned int sirfsoc_timer_irq, sirfsoc_timer1_irq;

static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
{
	struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);
	unsigned int irq;
	const char *name;

	if (cpu == 0) {
		irq = sirfsoc_timer_irq;
		name = "sirfsoc_timer0";
	} else {
		irq = sirfsoc_timer1_irq;
		name = "sirfsoc_timer1";
	}

	ce->irq = irq;
	ce->name = "local_timer";
	ce->features = CLOCK_EVT_FEAT_ONESHOT;
	ce->rating = 200;
	ce->set_state_shutdown = sirfsoc_timer_shutdown;
	ce->set_state_oneshot = sirfsoc_timer_shutdown;
	ce->tick_resume = sirfsoc_timer_shutdown;
	ce->set_next_event = sirfsoc_timer_set_next_event;
	clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
	ce->max_delta_ticks = (unsigned long)-2;
	ce->min_delta_ns = clockevent_delta2ns(2, ce);
	ce->min_delta_ticks = 2;
	ce->cpumask = cpumask_of(cpu);

	BUG_ON(request_irq(ce->irq, sirfsoc_timer_interrupt,
			   IRQF_TIMER | IRQF_NOBALANCING, name, ce));
	irq_force_affinity(ce->irq, cpumask_of(cpu));

	clockevents_register_device(ce);
	return 0;
}

static int sirfsoc_local_timer_dying_cpu(unsigned int cpu)
{
	struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);

	sirfsoc_timer_count_disable(1);

	if (cpu == 0)
		free_irq(sirfsoc_timer_irq, ce);
	else
		free_irq(sirfsoc_timer1_irq, ce);
	return 0;
}

static int __init sirfsoc_clockevent_init(void)
{
	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
	BUG_ON(!sirfsoc_clockevent);

	/* Install and invoke hotplug callbacks */
	return cpuhp_setup_state(CPUHP_AP_MARCO_TIMER_STARTING,
				 "clockevents/marco:starting",
				 sirfsoc_local_timer_starting_cpu,
				 sirfsoc_local_timer_dying_cpu);
}

/* initialize the kernel jiffy timer source */
static int __init sirfsoc_atlas7_timer_init(struct device_node *np)
{
	struct clk *clk;

	clk = of_clk_get(np, 0);
	BUG_ON(IS_ERR(clk));

	BUG_ON(clk_prepare_enable(clk));

	atlas7_timer_rate = clk_get_rate(clk);

	/* timer dividers: 0, not divided */
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);

	/* Initialize timer counters to 0 */
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);

	/* Clear all interrupts */
	writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);

	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate));

	return sirfsoc_clockevent_init();
}

static int __init sirfsoc_of_timer_init(struct device_node *np)
{
	sirfsoc_timer_base = of_iomap(np, 0);
	if (!sirfsoc_timer_base) {
		pr_err("unable to map timer cpu registers\n");
		return -ENXIO;
	}

	sirfsoc_timer_irq = irq_of_parse_and_map(np, 0);
	if (!sirfsoc_timer_irq) {
		pr_err("No irq passed for timer0 via DT\n");
		return -EINVAL;
	}

	sirfsoc_timer1_irq = irq_of_parse_and_map(np, 1);
	if (!sirfsoc_timer1_irq) {
		pr_err("No irq passed for timer1 via DT\n");
		return -EINVAL;
	}

	return sirfsoc_atlas7_timer_init(np);
}
TIMER_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
Loading