1
0
Fork 0

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
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmAqjecTHHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYodVTD/9UuKlOifRBNd4ECR+yF65MzLfjqNHU
 j76E3Dzuf4QCbXTjmQAsadaqQ+w9l8Ie7OVT51XlmTczEBkJiV3FOGLVJeRun6R4
 7OLF3VOYyBUtMoRdHzyXaYOTbsOK9gZitucDeLCQhvKhDCkVnKKFXNJR+TTkSYM3
 xDBLwuI7uuHWHyh0+W+3SI1pTiEA4yMe5ZbqqoJbjGQapr3Eao+nyjd1aa3ERb2f
 PtS7UVQ69QowRqq6DQyZk0yKit8J3HZnHfCPH/T6eXsxGnui36GiUnTGCMhLMZpD
 Xvl/5cjqQuKjgt2093t8nGiumOGBOfrb8uvc/qMW777DzFe/VJtXrC/7pySVLAhK
 oc9Swj0iX/WPARzlpyOk3lfpDMzv6qyjMNJIXcnav2lrknITp+TMORKWOADB03UV
 sswlN7YFTrNe7d7uxEdybKkNX6bUwgOzo2m69A1IdSXwKPzYkZQmku6Y7GnzYErZ
 aiJiZl858VB9g24ROKLt/uQTarzYCS0sjcdnDgO1KSR7zKHZ4iUpd3zucd3mlmUo
 fGTMIbCqL/gzl4Zcl6njvzMVfJeMzOeDiQ41wCyYnOsXlIKmWNi1rONdGZcyDYvN
 bOiGVUMKicEZwBlSZQQ1GdR9eGf8/Ix5cTlynZepN3dkHUDc7SU+OvQZdg4Yd/RY
 BsquFDHnt4gl+A==
 =xZQt
 -----END PGP SIGNATURE-----

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
master
Linus Torvalds 2021-02-21 11:55:43 -08:00
commit 3f6ec19f2d
13 changed files with 81 additions and 1401 deletions

View File

@ -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:

View File

@ -1,18 +0,0 @@
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>;
};

View File

@ -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

View File

@ -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

View File

@ -1,281 +0,0 @@
// 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);

View File

@ -7,6 +7,8 @@
* (with tiny parts adopted from code by Kevin Hilman <khilman@baylibre.com>)
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
@ -17,9 +19,6 @@
#include <clocksource/timer-davinci.h>
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
#define DAVINCI_TIMER_REG_TIM12 0x10
#define DAVINCI_TIMER_REG_TIM34 0x14
#define DAVINCI_TIMER_REG_PRD12 0x18

View File

@ -1,278 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Pengutronix
* Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
#define TIMERn_CTRL 0x00
#define TIMERn_CTRL_PRESC(val) (((val) & 0xf) << 24)
#define TIMERn_CTRL_PRESC_1024 TIMERn_CTRL_PRESC(10)
#define TIMERn_CTRL_CLKSEL(val) (((val) & 0x3) << 16)
#define TIMERn_CTRL_CLKSEL_PRESCHFPERCLK TIMERn_CTRL_CLKSEL(0)
#define TIMERn_CTRL_OSMEN 0x00000010
#define TIMERn_CTRL_MODE(val) (((val) & 0x3) << 0)
#define TIMERn_CTRL_MODE_UP TIMERn_CTRL_MODE(0)
#define TIMERn_CTRL_MODE_DOWN TIMERn_CTRL_MODE(1)
#define TIMERn_CMD 0x04
#define TIMERn_CMD_START 0x00000001
#define TIMERn_CMD_STOP 0x00000002
#define TIMERn_IEN 0x0c
#define TIMERn_IF 0x10
#define TIMERn_IFS 0x14
#define TIMERn_IFC 0x18
#define TIMERn_IRQ_UF 0x00000002
#define TIMERn_TOP 0x1c
#define TIMERn_CNT 0x24
struct efm32_clock_event_ddata {
struct clock_event_device evtdev;
void __iomem *base;
unsigned periodic_top;
};
static int efm32_clock_event_shutdown(struct clock_event_device *evtdev)
{
struct efm32_clock_event_ddata *ddata =
container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
return 0;
}
static int efm32_clock_event_set_oneshot(struct clock_event_device *evtdev)
{
struct efm32_clock_event_ddata *ddata =
container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
writel_relaxed(TIMERn_CTRL_PRESC_1024 |
TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
TIMERn_CTRL_OSMEN |
TIMERn_CTRL_MODE_DOWN,
ddata->base + TIMERn_CTRL);
return 0;
}
static int efm32_clock_event_set_periodic(struct clock_event_device *evtdev)
{
struct efm32_clock_event_ddata *ddata =
container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP);
writel_relaxed(TIMERn_CTRL_PRESC_1024 |
TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
TIMERn_CTRL_MODE_DOWN,
ddata->base + TIMERn_CTRL);
writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
return 0;
}
static int efm32_clock_event_set_next_event(unsigned long evt,
struct clock_event_device *evtdev)
{
struct efm32_clock_event_ddata *ddata =
container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
writel_relaxed(evt, ddata->base + TIMERn_CNT);
writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
return 0;
}
static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id)
{
struct efm32_clock_event_ddata *ddata = dev_id;
writel_relaxed(TIMERn_IRQ_UF, ddata->base + TIMERn_IFC);
ddata->evtdev.event_handler(&ddata->evtdev);
return IRQ_HANDLED;
}
static struct efm32_clock_event_ddata clock_event_ddata = {
.evtdev = {
.name = "efm32 clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.set_state_shutdown = efm32_clock_event_shutdown,
.set_state_periodic = efm32_clock_event_set_periodic,
.set_state_oneshot = efm32_clock_event_set_oneshot,
.set_next_event = efm32_clock_event_set_next_event,
.rating = 200,
},
};
static int __init efm32_clocksource_init(struct device_node *np)
{
struct clk *clk;
void __iomem *base;
unsigned long rate;
int ret;
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
pr_err("failed to get clock for clocksource (%d)\n", ret);
goto err_clk_get;
}
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("failed to enable timer clock for clocksource (%d)\n",
ret);
goto err_clk_enable;
}
rate = clk_get_rate(clk);
base = of_iomap(np, 0);
if (!base) {
ret = -EADDRNOTAVAIL;
pr_err("failed to map registers for clocksource\n");
goto err_iomap;
}
writel_relaxed(TIMERn_CTRL_PRESC_1024 |
TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
TIMERn_CTRL_MODE_UP, base + TIMERn_CTRL);
writel_relaxed(TIMERn_CMD_START, base + TIMERn_CMD);
ret = clocksource_mmio_init(base + TIMERn_CNT, "efm32 timer",
DIV_ROUND_CLOSEST(rate, 1024), 200, 16,
clocksource_mmio_readl_up);
if (ret) {
pr_err("failed to init clocksource (%d)\n", ret);
goto err_clocksource_init;
}
return 0;
err_clocksource_init:
iounmap(base);
err_iomap:
clk_disable_unprepare(clk);
err_clk_enable:
clk_put(clk);
err_clk_get:
return ret;
}
static int __init efm32_clockevent_init(struct device_node *np)
{
struct clk *clk;
void __iomem *base;
unsigned long rate;
int irq;
int ret;
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
pr_err("failed to get clock for clockevent (%d)\n", ret);
goto err_clk_get;
}
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("failed to enable timer clock for clockevent (%d)\n",
ret);
goto err_clk_enable;
}
rate = clk_get_rate(clk);
base = of_iomap(np, 0);
if (!base) {
ret = -EADDRNOTAVAIL;
pr_err("failed to map registers for clockevent\n");
goto err_iomap;
}
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
ret = -ENOENT;
pr_err("failed to get irq for clockevent\n");
goto err_get_irq;
}
writel_relaxed(TIMERn_IRQ_UF, base + TIMERn_IEN);
clock_event_ddata.base = base;
clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
clockevents_config_and_register(&clock_event_ddata.evtdev,
DIV_ROUND_CLOSEST(rate, 1024),
0xf, 0xffff);
ret = request_irq(irq, efm32_clock_event_handler, IRQF_TIMER,
"efm32 clockevent", &clock_event_ddata);
if (ret) {
pr_err("Failed setup irq\n");
goto err_setup_irq;
}
return 0;
err_setup_irq:
err_get_irq:
iounmap(base);
err_iomap:
clk_disable_unprepare(clk);
err_clk_enable:
clk_put(clk);
err_clk_get:
return ret;
}
/*
* This function asserts that we have exactly one clocksource and one
* clock_event_device in the end.
*/
static int __init efm32_timer_init(struct device_node *np)
{
static int has_clocksource, has_clockevent;
int ret = 0;
if (!has_clocksource) {
ret = efm32_clocksource_init(np);
if (!ret) {
has_clocksource = 1;
return 0;
}
}
if (!has_clockevent) {
ret = efm32_clockevent_init(np);
if (!ret) {
has_clockevent = 1;
return 0;
}
}
return ret;
}
TIMER_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
TIMER_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);

View File

@ -71,10 +71,24 @@ struct mchp_pit64b_clkevt {
struct clock_event_device clkevt;
};
#define to_mchp_pit64b_timer(x) \
#define clkevt_to_mchp_pit64b_timer(x) \
((struct mchp_pit64b_timer *)container_of(x,\
struct mchp_pit64b_clkevt, clkevt))
/**
* mchp_pit64b_clksrc - PIT64B clocksource data structure
* @timer: PIT64B timer
* @clksrc: clocksource
*/
struct mchp_pit64b_clksrc {
struct mchp_pit64b_timer timer;
struct clocksource clksrc;
};
#define clksrc_to_mchp_pit64b_timer(x) \
((struct mchp_pit64b_timer *)container_of(x,\
struct mchp_pit64b_clksrc, clksrc))
/* Base address for clocksource timer. */
static void __iomem *mchp_pit64b_cs_base;
/* Default cycles for clockevent timer. */
@ -116,6 +130,36 @@ static inline void mchp_pit64b_reset(struct mchp_pit64b_timer *timer,
writel_relaxed(MCHP_PIT64B_CR_START, timer->base + MCHP_PIT64B_CR);
}
static void mchp_pit64b_suspend(struct mchp_pit64b_timer *timer)
{
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
clk_disable_unprepare(timer->gclk);
clk_disable_unprepare(timer->pclk);
}
static void mchp_pit64b_resume(struct mchp_pit64b_timer *timer)
{
clk_prepare_enable(timer->pclk);
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
clk_prepare_enable(timer->gclk);
}
static void mchp_pit64b_clksrc_suspend(struct clocksource *cs)
{
struct mchp_pit64b_timer *timer = clksrc_to_mchp_pit64b_timer(cs);
mchp_pit64b_suspend(timer);
}
static void mchp_pit64b_clksrc_resume(struct clocksource *cs)
{
struct mchp_pit64b_timer *timer = clksrc_to_mchp_pit64b_timer(cs);
mchp_pit64b_resume(timer);
mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
}
static u64 mchp_pit64b_clksrc_read(struct clocksource *cs)
{
return mchp_pit64b_cnt_read(mchp_pit64b_cs_base);
@ -128,7 +172,7 @@ static u64 mchp_pit64b_sched_read_clk(void)
static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
{
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
@ -137,7 +181,7 @@ static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
{
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
mchp_pit64b_reset(timer, mchp_pit64b_ce_cycles, MCHP_PIT64B_MR_CONT,
MCHP_PIT64B_IER_PERIOD);
@ -148,7 +192,7 @@ static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
struct clock_event_device *cedev)
{
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
mchp_pit64b_reset(timer, evt, MCHP_PIT64B_MR_ONE_SHOT,
MCHP_PIT64B_IER_PERIOD);
@ -158,21 +202,16 @@ static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
{
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
writel_relaxed(MCHP_PIT64B_CR_SWRST, timer->base + MCHP_PIT64B_CR);
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
clk_disable_unprepare(timer->gclk);
clk_disable_unprepare(timer->pclk);
mchp_pit64b_suspend(timer);
}
static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
{
struct mchp_pit64b_timer *timer = to_mchp_pit64b_timer(cedev);
struct mchp_pit64b_timer *timer = clkevt_to_mchp_pit64b_timer(cedev);
clk_prepare_enable(timer->pclk);
if (timer->mode & MCHP_PIT64B_MR_SGCLK)
clk_prepare_enable(timer->gclk);
mchp_pit64b_resume(timer);
}
static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
@ -296,20 +335,37 @@ done:
static int __init mchp_pit64b_init_clksrc(struct mchp_pit64b_timer *timer,
u32 clk_rate)
{
struct mchp_pit64b_clksrc *cs;
int ret;
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
mchp_pit64b_reset(timer, ULLONG_MAX, MCHP_PIT64B_MR_CONT, 0);
mchp_pit64b_cs_base = timer->base;
ret = clocksource_mmio_init(timer->base, MCHP_PIT64B_NAME, clk_rate,
210, 64, mchp_pit64b_clksrc_read);
cs->timer.base = timer->base;
cs->timer.pclk = timer->pclk;
cs->timer.gclk = timer->gclk;
cs->timer.mode = timer->mode;
cs->clksrc.name = MCHP_PIT64B_NAME;
cs->clksrc.mask = CLOCKSOURCE_MASK(64);
cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
cs->clksrc.rating = 210;
cs->clksrc.read = mchp_pit64b_clksrc_read;
cs->clksrc.suspend = mchp_pit64b_clksrc_suspend;
cs->clksrc.resume = mchp_pit64b_clksrc_resume;
ret = clocksource_register_hz(&cs->clksrc, clk_rate);
if (ret) {
pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
/* Stop timer. */
writel_relaxed(MCHP_PIT64B_CR_SWRST,
timer->base + MCHP_PIT64B_CR);
kfree(cs);
return ret;
}

View File

@ -1,242 +0,0 @@
// 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/bitops.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/err.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 PRIMA2_CLOCK_FREQ 1000000
#define SIRFSOC_TIMER_COUNTER_LO 0x0000
#define SIRFSOC_TIMER_COUNTER_HI 0x0004
#define SIRFSOC_TIMER_MATCH_0 0x0008
#define SIRFSOC_TIMER_MATCH_1 0x000C
#define SIRFSOC_TIMER_MATCH_2 0x0010
#define SIRFSOC_TIMER_MATCH_3 0x0014
#define SIRFSOC_TIMER_MATCH_4 0x0018
#define SIRFSOC_TIMER_MATCH_5 0x001C
#define SIRFSOC_TIMER_STATUS 0x0020
#define SIRFSOC_TIMER_INT_EN 0x0024
#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028
#define SIRFSOC_TIMER_DIV 0x002C
#define SIRFSOC_TIMER_LATCH 0x0030
#define SIRFSOC_TIMER_LATCHED_LO 0x0034
#define SIRFSOC_TIMER_LATCHED_HI 0x0038
#define SIRFSOC_TIMER_WDT_INDEX 5
#define SIRFSOC_TIMER_LATCH_BIT BIT(0)
#define SIRFSOC_TIMER_REG_CNT 11
static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
SIRFSOC_TIMER_MATCH_0, SIRFSOC_TIMER_MATCH_1, SIRFSOC_TIMER_MATCH_2,
SIRFSOC_TIMER_MATCH_3, SIRFSOC_TIMER_MATCH_4, SIRFSOC_TIMER_MATCH_5,
SIRFSOC_TIMER_INT_EN, SIRFSOC_TIMER_WATCHDOG_EN, SIRFSOC_TIMER_DIV,
SIRFSOC_TIMER_LATCHED_LO, SIRFSOC_TIMER_LATCHED_HI,
};
static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
static void __iomem *sirfsoc_timer_base;
/* timer0 interrupt handler */
static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *ce = dev_id;
WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) &
BIT(0)));
/* clear timer0 interrupt */
writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
ce->event_handler(ce);
return IRQ_HANDLED;
}
/* read 64-bit timer counter */
static u64 notrace sirfsoc_timer_read(struct clocksource *cs)
{
u64 cycles;
/* latch the 64-bit timer counter */
writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
cycles = (cycles << 32) |
readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
return cycles;
}
static int sirfsoc_timer_set_next_event(unsigned long delta,
struct clock_event_device *ce)
{
unsigned long now, next;
writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
next = now + delta;
writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
return next - now > delta ? -ETIME : 0;
}
static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
{
u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
writel_relaxed(val & ~BIT(0),
sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
return 0;
}
static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt)
{
u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
return 0;
}
static void sirfsoc_clocksource_suspend(struct clocksource *cs)
{
int i;
writel_relaxed(SIRFSOC_TIMER_LATCH_BIT,
sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
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_COUNTER_LO);
writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
}
static struct clock_event_device sirfsoc_clockevent = {
.name = "sirfsoc_clockevent",
.rating = 200,
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_state_shutdown = sirfsoc_timer_shutdown,
.set_state_oneshot = sirfsoc_timer_set_oneshot,
.set_next_event = sirfsoc_timer_set_next_event,
};
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,
};
/* Overwrite weak default sched_clock with more precise one */
static u64 notrace sirfsoc_read_sched_clock(void)
{
return sirfsoc_timer_read(NULL);
}
static void __init sirfsoc_clockevent_init(void)
{
sirfsoc_clockevent.cpumask = cpumask_of(0);
clockevents_config_and_register(&sirfsoc_clockevent, PRIMA2_CLOCK_FREQ,
2, -2);
}
/* initialize the kernel jiffy timer source */
static int __init sirfsoc_prima2_timer_init(struct device_node *np)
{
unsigned long rate;
unsigned int irq;
struct clk *clk;
int ret;
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
pr_err("Failed to get clock\n");
return PTR_ERR(clk);
}
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("Failed to enable clock\n");
return ret;
}
rate = clk_get_rate(clk);
if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) {
pr_err("Invalid clock rate\n");
return -EINVAL;
}
sirfsoc_timer_base = of_iomap(np, 0);
if (!sirfsoc_timer_base) {
pr_err("unable to map timer cpu registers\n");
return -ENXIO;
}
irq = irq_of_parse_and_map(np, 0);
writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1,
sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ);
if (ret) {
pr_err("Failed to register clocksource\n");
return ret;
}
sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ);
ret = request_irq(irq, sirfsoc_timer_interrupt, IRQF_TIMER,
"sirfsoc_timer0", &sirfsoc_clockevent);
if (ret) {
pr_err("Failed to setup irq\n");
return ret;
}
sirfsoc_clockevent_init();
return 0;
}
TIMER_OF_DECLARE(sirfsoc_prima2_timer,
"sirf,prima2-tick", sirfsoc_prima2_timer_init);

View File

@ -1,57 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clocksource.h>
#include <linux/sched_clock.h>
#include <linux/of_address.h>
#include <linux/printk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/clk.h>
static void __iomem *xtal_in_cnt;
static struct delay_timer delay_timer;
static unsigned long notrace read_xtal_counter(void)
{
return readl_relaxed(xtal_in_cnt);
}
static u64 notrace read_sched_clock(void)
{
return read_xtal_counter();
}
static int __init tango_clocksource_init(struct device_node *np)
{
struct clk *clk;
int xtal_freq, ret;
xtal_in_cnt = of_iomap(np, 0);
if (xtal_in_cnt == NULL) {
pr_err("%pOF: invalid address\n", np);
return -ENXIO;
}
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
pr_err("%pOF: invalid clock\n", np);
return PTR_ERR(clk);
}
xtal_freq = clk_get_rate(clk);
delay_timer.freq = xtal_freq;
delay_timer.read_current_timer = read_xtal_counter;
ret = clocksource_mmio_init(xtal_in_cnt, "tango-xtal", xtal_freq, 350,
32, clocksource_mmio_readl_up);
if (ret) {
pr_err("%pOF: registration failed\n", np);
return ret;
}
sched_clock_register(read_sched_clock, 32, xtal_freq);
register_current_timer_delay(&delay_timer);
return 0;
}
TIMER_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init);

View File

@ -1,457 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007-2009 ST-Ericsson AB
* Timer COH 901 328, runs the OS timer interrupt.
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
/* Generic stuff */
#include <asm/mach/map.h>
#include <asm/mach/time.h>
/*
* APP side special timer registers
* This timer contains four timers which can fire an interrupt each.
* OS (operating system) timer @ 32768 Hz
* DD (device driver) timer @ 1 kHz
* GP1 (general purpose 1) timer @ 1MHz
* GP2 (general purpose 2) timer @ 1MHz
*/
/* Reset OS Timer 32bit (-/W) */
#define U300_TIMER_APP_ROST (0x0000)
#define U300_TIMER_APP_ROST_TIMER_RESET (0x00000000)
/* Enable OS Timer 32bit (-/W) */
#define U300_TIMER_APP_EOST (0x0004)
#define U300_TIMER_APP_EOST_TIMER_ENABLE (0x00000000)
/* Disable OS Timer 32bit (-/W) */
#define U300_TIMER_APP_DOST (0x0008)
#define U300_TIMER_APP_DOST_TIMER_DISABLE (0x00000000)
/* OS Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SOSTM (0x000c)
#define U300_TIMER_APP_SOSTM_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SOSTM_MODE_ONE_SHOT (0x00000001)
/* OS Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_OSTS (0x0010)
#define U300_TIMER_APP_OSTS_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_OSTS_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_OSTS_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_OSTS_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_OSTS_MODE_MASK (0x00000020)
#define U300_TIMER_APP_OSTS_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_OSTS_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_OSTS_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_OSTS_IRQ_PENDING_IND (0x00000080)
/* OS Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_OSTCC (0x0014)
/* OS Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_OSTTC (0x0018)
/* OS Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_OSTIE (0x001c)
#define U300_TIMER_APP_OSTIE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_OSTIE_IRQ_ENABLE (0x00000001)
/* OS Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_OSTIA (0x0020)
#define U300_TIMER_APP_OSTIA_IRQ_ACK (0x00000080)
/* Reset DD Timer 32bit (-/W) */
#define U300_TIMER_APP_RDDT (0x0040)
#define U300_TIMER_APP_RDDT_TIMER_RESET (0x00000000)
/* Enable DD Timer 32bit (-/W) */
#define U300_TIMER_APP_EDDT (0x0044)
#define U300_TIMER_APP_EDDT_TIMER_ENABLE (0x00000000)
/* Disable DD Timer 32bit (-/W) */
#define U300_TIMER_APP_DDDT (0x0048)
#define U300_TIMER_APP_DDDT_TIMER_DISABLE (0x00000000)
/* DD Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SDDTM (0x004c)
#define U300_TIMER_APP_SDDTM_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SDDTM_MODE_ONE_SHOT (0x00000001)
/* DD Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_DDTS (0x0050)
#define U300_TIMER_APP_DDTS_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_DDTS_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_DDTS_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_DDTS_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_DDTS_MODE_MASK (0x00000020)
#define U300_TIMER_APP_DDTS_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_DDTS_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_DDTS_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_DDTS_IRQ_PENDING_IND (0x00000080)
/* DD Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_DDTCC (0x0054)
/* DD Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_DDTTC (0x0058)
/* DD Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_DDTIE (0x005c)
#define U300_TIMER_APP_DDTIE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_DDTIE_IRQ_ENABLE (0x00000001)
/* DD Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_DDTIA (0x0060)
#define U300_TIMER_APP_DDTIA_IRQ_ACK (0x00000080)
/* Reset GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_RGPT1 (0x0080)
#define U300_TIMER_APP_RGPT1_TIMER_RESET (0x00000000)
/* Enable GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_EGPT1 (0x0084)
#define U300_TIMER_APP_EGPT1_TIMER_ENABLE (0x00000000)
/* Disable GP1 Timer 32bit (-/W) */
#define U300_TIMER_APP_DGPT1 (0x0088)
#define U300_TIMER_APP_DGPT1_TIMER_DISABLE (0x00000000)
/* GP1 Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SGPT1M (0x008c)
#define U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT (0x00000001)
/* GP1 Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_GPT1S (0x0090)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_GPT1S_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_GPT1S_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_GPT1S_MODE_MASK (0x00000020)
#define U300_TIMER_APP_GPT1S_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_GPT1S_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_GPT1S_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_GPT1S_IRQ_PENDING_IND (0x00000080)
/* GP1 Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_GPT1CC (0x0094)
/* GP1 Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_GPT1TC (0x0098)
/* GP1 Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_GPT1IE (0x009c)
#define U300_TIMER_APP_GPT1IE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_GPT1IE_IRQ_ENABLE (0x00000001)
/* GP1 Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_GPT1IA (0x00a0)
#define U300_TIMER_APP_GPT1IA_IRQ_ACK (0x00000080)
/* Reset GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_RGPT2 (0x00c0)
#define U300_TIMER_APP_RGPT2_TIMER_RESET (0x00000000)
/* Enable GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_EGPT2 (0x00c4)
#define U300_TIMER_APP_EGPT2_TIMER_ENABLE (0x00000000)
/* Disable GP2 Timer 32bit (-/W) */
#define U300_TIMER_APP_DGPT2 (0x00c8)
#define U300_TIMER_APP_DGPT2_TIMER_DISABLE (0x00000000)
/* GP2 Timer Mode Register 32bit (-/W) */
#define U300_TIMER_APP_SGPT2M (0x00cc)
#define U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_SGPT2M_MODE_ONE_SHOT (0x00000001)
/* GP2 Timer Status Register 32bit (R/-) */
#define U300_TIMER_APP_GPT2S (0x00d0)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_MASK (0x0000000F)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_IDLE (0x00000001)
#define U300_TIMER_APP_GPT2S_TIMER_STATE_ACTIVE (0x00000002)
#define U300_TIMER_APP_GPT2S_ENABLE_IND (0x00000010)
#define U300_TIMER_APP_GPT2S_MODE_MASK (0x00000020)
#define U300_TIMER_APP_GPT2S_MODE_CONTINUOUS (0x00000000)
#define U300_TIMER_APP_GPT2S_MODE_ONE_SHOT (0x00000020)
#define U300_TIMER_APP_GPT2S_IRQ_ENABLED_IND (0x00000040)
#define U300_TIMER_APP_GPT2S_IRQ_PENDING_IND (0x00000080)
/* GP2 Timer Current Count Register 32bit (R/-) */
#define U300_TIMER_APP_GPT2CC (0x00d4)
/* GP2 Timer Terminal Count Register 32bit (R/W) */
#define U300_TIMER_APP_GPT2TC (0x00d8)
/* GP2 Timer Interrupt Enable Register 32bit (-/W) */
#define U300_TIMER_APP_GPT2IE (0x00dc)
#define U300_TIMER_APP_GPT2IE_IRQ_DISABLE (0x00000000)
#define U300_TIMER_APP_GPT2IE_IRQ_ENABLE (0x00000001)
/* GP2 Timer Interrupt Acknowledge Register 32bit (-/W) */
#define U300_TIMER_APP_GPT2IA (0x00e0)
#define U300_TIMER_APP_GPT2IA_IRQ_ACK (0x00000080)
/* Clock request control register - all four timers */
#define U300_TIMER_APP_CRC (0x100)
#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE (0x00000001)
static void __iomem *u300_timer_base;
struct u300_clockevent_data {
struct clock_event_device cevd;
unsigned ticks_per_jiffy;
};
static int u300_shutdown(struct clock_event_device *evt)
{
/* Disable interrupts on GP1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
return 0;
}
/*
* If we have oneshot timer active, the oneshot scheduling function
* u300_set_next_event() is called immediately after.
*/
static int u300_set_oneshot(struct clock_event_device *evt)
{
/* Just return; here? */
/*
* The actual event will be programmed by the next event hook,
* so we just set a dummy value somewhere at the end of the
* universe here.
*/
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
/*
* Expire far in the future, u300_set_next_event() will be
* called soon...
*/
writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC);
/* We run one shot per tick here! */
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
u300_timer_base + U300_TIMER_APP_SGPT1M);
/* Enable interrupts for this timer */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Enable timer */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT1);
return 0;
}
static int u300_set_periodic(struct clock_event_device *evt)
{
struct u300_clockevent_data *cevdata =
container_of(evt, struct u300_clockevent_data, cevd);
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
/*
* Set the periodic mode to a certain number of ticks per
* jiffy.
*/
writel(cevdata->ticks_per_jiffy,
u300_timer_base + U300_TIMER_APP_GPT1TC);
/*
* Set continuous mode, so the timer keeps triggering
* interrupts.
*/
writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
u300_timer_base + U300_TIMER_APP_SGPT1M);
/* Enable timer interrupts */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Then enable the OS timer again */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT1);
return 0;
}
/*
* The app timer in one shot mode obviously has to be reprogrammed
* in EXACTLY this sequence to work properly. Do NOT try to e.g. replace
* the interrupt disable + timer disable commands with a reset command,
* it will fail miserably. Apparently (and I found this the hard way)
* the timer is very sensitive to the instruction order, though you don't
* get that impression from the data sheet.
*/
static int u300_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
/* Reset the General Purpose timer 1. */
writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
u300_timer_base + U300_TIMER_APP_RGPT1);
/* IRQ in n * cycles */
writel(cycles, u300_timer_base + U300_TIMER_APP_GPT1TC);
/*
* We run one shot per tick here! (This is necessary to reconfigure,
* the timer will tilt if you don't!)
*/
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
u300_timer_base + U300_TIMER_APP_SGPT1M);
/* Enable timer interrupts */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Then enable the OS timer again */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT1);
return 0;
}
static struct u300_clockevent_data u300_clockevent_data = {
/* Use general purpose timer 1 as clock event */
.cevd = {
.name = "GPT1",
/* Reasonably fast and accurate clock event */
.rating = 300,
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = u300_set_next_event,
.set_state_shutdown = u300_shutdown,
.set_state_periodic = u300_set_periodic,
.set_state_oneshot = u300_set_oneshot,
},
};
/* Clock event timer interrupt handler */
static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &u300_clockevent_data.cevd;
/* ACK/Clear timer IRQ for the APP GPT1 Timer */
writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
u300_timer_base + U300_TIMER_APP_GPT1IA);
evt->event_handler(evt);
return IRQ_HANDLED;
}
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
* better resolution when scheduling the kernel. We accept that
* this wraps around for now, since it is just a relative time
* stamp. (Inspired by OMAP implementation.)
*/
static u64 notrace u300_read_sched_clock(void)
{
return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
}
static unsigned long u300_read_current_timer(void)
{
return readl(u300_timer_base + U300_TIMER_APP_GPT2CC);
}
static struct delay_timer u300_delay_timer;
/*
* This sets up the system timers, clock source and clock event.
*/
static int __init u300_timer_init_of(struct device_node *np)
{
unsigned int irq;
struct clk *clk;
unsigned long rate;
int ret;
u300_timer_base = of_iomap(np, 0);
if (!u300_timer_base) {
pr_err("could not ioremap system timer\n");
return -ENXIO;
}
/* Get the IRQ for the GP1 timer */
irq = irq_of_parse_and_map(np, 2);
if (!irq) {
pr_err("no IRQ for system timer\n");
return -EINVAL;
}
pr_info("U300 GP1 timer @ base: %p, IRQ: %u\n", u300_timer_base, irq);
/* Clock the interrupt controller */
clk = of_clk_get(np, 0);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = clk_prepare_enable(clk);
if (ret)
return ret;
rate = clk_get_rate(clk);
u300_clockevent_data.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
sched_clock_register(u300_read_sched_clock, 32, rate);
u300_delay_timer.read_current_timer = &u300_read_current_timer;
u300_delay_timer.freq = rate;
register_current_timer_delay(&u300_delay_timer);
/*
* Disable the "OS" and "DD" timers - these are designed for Symbian!
* Example usage in cnh1601578 cpu subsystem pd_timer_app.c
*/
writel(U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE,
u300_timer_base + U300_TIMER_APP_CRC);
writel(U300_TIMER_APP_ROST_TIMER_RESET,
u300_timer_base + U300_TIMER_APP_ROST);
writel(U300_TIMER_APP_DOST_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DOST);
writel(U300_TIMER_APP_RDDT_TIMER_RESET,
u300_timer_base + U300_TIMER_APP_RDDT);
writel(U300_TIMER_APP_DDDT_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DDDT);
/* Reset the General Purpose timer 1. */
writel(U300_TIMER_APP_RGPT1_TIMER_RESET,
u300_timer_base + U300_TIMER_APP_RGPT1);
/* Set up the IRQ handler */
ret = request_irq(irq, u300_timer_interrupt,
IRQF_TIMER | IRQF_IRQPOLL, "U300 Timer Tick", NULL);
if (ret)
return ret;
/* Reset the General Purpose timer 2 */
writel(U300_TIMER_APP_RGPT2_TIMER_RESET,
u300_timer_base + U300_TIMER_APP_RGPT2);
/* Set this timer to run around forever */
writel(0xFFFFFFFFU, u300_timer_base + U300_TIMER_APP_GPT2TC);
/* Set continuous mode so it wraps around */
writel(U300_TIMER_APP_SGPT2M_MODE_CONTINUOUS,
u300_timer_base + U300_TIMER_APP_SGPT2M);
/* Disable timer interrupts */
writel(U300_TIMER_APP_GPT2IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT2IE);
/* Then enable the GP2 timer to use as a free running us counter */
writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT2);
/* Use general purpose timer 2 as clock source */
ret = clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC,
"GPT2", rate, 300, 32, clocksource_mmio_readl_up);
if (ret) {
pr_err("timer: failed to initialize U300 clock source\n");
return ret;
}
/* Configure and register the clockevent */
clockevents_config_and_register(&u300_clockevent_data.cevd, rate,
1, 0xffffffff);
/*
* TODO: init and register the rest of the timers too, they can be
* used by hrtimers!
*/
return 0;
}
TIMER_OF_DECLARE(u300_timer, "stericsson,u300-apptimer",
u300_timer_init_of);

View File

@ -527,8 +527,11 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid)
/**
* alarm_handle_timer - Callback for posix timers
* @alarm: alarm that fired
* @now: time at the timer expiration
*
* Posix timer callback for expired alarm timers.
*
* Return: whether the timer is to be restarted
*/
static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
ktime_t now)
@ -715,8 +718,11 @@ static int alarm_timer_create(struct k_itimer *new_timer)
/**
* alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep
* @alarm: ptr to alarm that fired
* @now: time at the timer expiration
*
* Wakes up the task that set the alarmtimer
*
* Return: ALARMTIMER_NORESTART
*/
static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
ktime_t now)
@ -733,6 +739,7 @@ static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm,
* alarmtimer_do_nsleep - Internal alarmtimer nsleep implementation
* @alarm: ptr to alarmtimer
* @absexp: absolute expiration time
* @type: alarm type (BOOTTIME/REALTIME).
*
* Sets the alarm timer and sleeps until it is fired or interrupted.
*/
@ -806,7 +813,6 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
* @which_clock: clockid
* @flags: determins abstime or relative
* @tsreq: requested sleep time (abs or rel)
* @rmtp: remaining sleep time saved
*
* Handles clock_nanosleep calls against _ALARM clockids
*/

View File

@ -465,9 +465,3 @@ struct time_namespace init_time_ns = {
.ns.ops = &timens_operations,
.frozen_offsets = true,
};
static int __init time_ns_init(void)
{
return 0;
}
subsys_initcall(time_ns_init);