diff options
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 22 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 7 | ||||
| -rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 66 | ||||
| -rw-r--r-- | drivers/clocksource/clps711x-timer.c | 44 | ||||
| -rw-r--r-- | drivers/clocksource/exynos_mct.c | 48 | ||||
| -rw-r--r-- | drivers/clocksource/mips-gic-timer.c | 2 | ||||
| -rw-r--r-- | drivers/clocksource/tcb_clksrc.c | 4 | ||||
| -rw-r--r-- | drivers/clocksource/timer-cs5535.c (renamed from drivers/clocksource/cs5535-clockevt.c) | 0 | ||||
| -rw-r--r-- | drivers/clocksource/timer-milbeaut.c | 161 | ||||
| -rw-r--r-- | drivers/clocksource/timer-pxa.c (renamed from drivers/clocksource/pxa_timer.c) | 0 | ||||
| -rw-r--r-- | drivers/clocksource/timer-riscv.c | 28 | ||||
| -rw-r--r-- | drivers/clocksource/timer-sun5i.c | 10 | ||||
| -rw-r--r-- | drivers/clocksource/timer-tango-xtal.c (renamed from drivers/clocksource/tango_xtal.c) | 0 | ||||
| -rw-r--r-- | drivers/clocksource/timer-tegra20.c | 370 | ||||
| -rw-r--r-- | drivers/clocksource/timer-ti-dm.c | 9 | 
15 files changed, 590 insertions, 181 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a9e26f6a81a1..171502a356aa 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -131,7 +131,8 @@ config SUN5I_HSTIMER  config TEGRA_TIMER  	bool "Tegra timer driver" if COMPILE_TEST  	select CLKSRC_MMIO -	depends on ARM +	select TIMER_OF +	depends on ARM || ARM64  	help  	  Enables support for the Tegra driver. @@ -360,6 +361,16 @@ config ARM64_ERRATUM_858921  	  The workaround will be dynamically enabled when an affected  	  core is detected. +config SUN50I_ERRATUM_UNKNOWN1 +	bool "Workaround for Allwinner A64 erratum UNKNOWN1" +	default y +	depends on ARM_ARCH_TIMER && ARM64 && ARCH_SUNXI +	select ARM_ARCH_TIMER_OOL_WORKAROUND +	help +	  This option enables a workaround for instability in the timer on +	  the Allwinner A64 SoC. The workaround will only be active if the +	  allwinner,erratum-unknown1 property is found in the timer node. +  config ARM_GLOBAL_TIMER  	bool "Support for the ARM global timer" if COMPILE_TEST  	select TIMER_OF if OF @@ -634,4 +645,13 @@ config GX6605S_TIMER  	help  	  This option enables support for gx6605s SOC's timer. +config MILBEAUT_TIMER +	bool "Milbeaut timer driver" if COMPILE_TEST +	depends on OF +	depends on ARM +	select TIMER_OF +	select CLKSRC_MMIO +	help +	  Enables the support for Milbeaut timer driver. +  endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index cdd210ff89ea..be6e0fbc7489 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o  obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o  obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o  obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o -obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= cs5535-clockevt.o +obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= timer-cs5535.o  obj-$(CONFIG_CLKSRC_JCORE_PIT)		+= jcore-pit.o  obj-$(CONFIG_SH_TIMER_CMT)	+= sh_cmt.o  obj-$(CONFIG_SH_TIMER_MTU2)	+= sh_mtu2.o @@ -29,7 +29,7 @@ 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)	+= pxa_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 @@ -55,6 +55,7 @@ obj-$(CONFIG_CLKSRC_TI_32K)	+= timer-ti-32k.o  obj-$(CONFIG_CLKSRC_NPS)	+= timer-nps.o  obj-$(CONFIG_OXNAS_RPS_TIMER)	+= timer-oxnas-rps.o  obj-$(CONFIG_OWL_TIMER)		+= timer-owl.o +obj-$(CONFIG_MILBEAUT_TIMER)	+= timer-milbeaut.o  obj-$(CONFIG_SPRD_TIMER)	+= timer-sprd.o  obj-$(CONFIG_NPCM7XX_TIMER)	+= timer-npcm7xx.o  obj-$(CONFIG_RDA_TIMER)		+= timer-rda.o @@ -69,7 +70,7 @@ 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)		+= tango_xtal.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_ASM9260_TIMER)		+= asm9260_timer.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9a7d4dc00b6e..aa4ec53281ce 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -326,6 +326,48 @@ static u64 notrace arm64_1188873_read_cntvct_el0(void)  }  #endif +#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 +/* + * The low bits of the counter registers are indeterminate while bit 10 or + * greater is rolling over. Since the counter value can jump both backward + * (7ff -> 000 -> 800) and forward (7ff -> fff -> 800), ignore register values + * with all ones or all zeros in the low bits. Bound the loop by the maximum + * number of CPU cycles in 3 consecutive 24 MHz counter periods. + */ +#define __sun50i_a64_read_reg(reg) ({					\ +	u64 _val;							\ +	int _retries = 150;						\ +									\ +	do {								\ +		_val = read_sysreg(reg);				\ +		_retries--;						\ +	} while (((_val + 1) & GENMASK(9, 0)) <= 1 && _retries);	\ +									\ +	WARN_ON_ONCE(!_retries);					\ +	_val;								\ +}) + +static u64 notrace sun50i_a64_read_cntpct_el0(void) +{ +	return __sun50i_a64_read_reg(cntpct_el0); +} + +static u64 notrace sun50i_a64_read_cntvct_el0(void) +{ +	return __sun50i_a64_read_reg(cntvct_el0); +} + +static u32 notrace sun50i_a64_read_cntp_tval_el0(void) +{ +	return read_sysreg(cntp_cval_el0) - sun50i_a64_read_cntpct_el0(); +} + +static u32 notrace sun50i_a64_read_cntv_tval_el0(void) +{ +	return read_sysreg(cntv_cval_el0) - sun50i_a64_read_cntvct_el0(); +} +#endif +  #ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND  DEFINE_PER_CPU(const struct arch_timer_erratum_workaround *, timer_unstable_counter_workaround);  EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); @@ -423,6 +465,19 @@ static const struct arch_timer_erratum_workaround ool_workarounds[] = {  		.read_cntvct_el0 = arm64_1188873_read_cntvct_el0,  	},  #endif +#ifdef CONFIG_SUN50I_ERRATUM_UNKNOWN1 +	{ +		.match_type = ate_match_dt, +		.id = "allwinner,erratum-unknown1", +		.desc = "Allwinner erratum UNKNOWN1", +		.read_cntp_tval_el0 = sun50i_a64_read_cntp_tval_el0, +		.read_cntv_tval_el0 = sun50i_a64_read_cntv_tval_el0, +		.read_cntpct_el0 = sun50i_a64_read_cntpct_el0, +		.read_cntvct_el0 = sun50i_a64_read_cntvct_el0, +		.set_next_event_phys = erratum_set_next_event_tval_phys, +		.set_next_event_virt = erratum_set_next_event_tval_virt, +	}, +#endif  };  typedef bool (*ate_match_fn_t)(const struct arch_timer_erratum_workaround *, @@ -1206,6 +1261,13 @@ static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)  	return ARCH_TIMER_PHYS_SECURE_PPI;  } +static void __init arch_timer_populate_kvm_info(void) +{ +	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; +	if (is_kernel_in_hyp_mode()) +		arch_timer_kvm_info.physical_irq = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]; +} +  static int __init arch_timer_of_init(struct device_node *np)  {  	int i, ret; @@ -1220,7 +1282,7 @@ static int __init arch_timer_of_init(struct device_node *np)  	for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)  		arch_timer_ppi[i] = irq_of_parse_and_map(np, i); -	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; +	arch_timer_populate_kvm_info();  	rate = arch_timer_get_cntfrq();  	arch_timer_of_configure_rate(rate, np); @@ -1550,7 +1612,7 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)  	arch_timer_ppi[ARCH_TIMER_HYP_PPI] =  		acpi_gtdt_map_ppi(ARCH_TIMER_HYP_PPI); -	arch_timer_kvm_info.virtual_irq = arch_timer_ppi[ARCH_TIMER_VIRT_PPI]; +	arch_timer_populate_kvm_info();  	/*  	 * When probing via ACPI, we have no mechanism to override the sysreg diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index a8dd80576c95..857f8c086274 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -31,16 +31,9 @@ static u64 notrace clps711x_sched_clock_read(void)  	return ~readw(tcd);  } -static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base) +static void __init clps711x_clksrc_init(struct clk *clock, void __iomem *base)  { -	unsigned long rate; - -	if (!base) -		return -ENOMEM; -	if (IS_ERR(clock)) -		return PTR_ERR(clock); - -	rate = clk_get_rate(clock); +	unsigned long rate = clk_get_rate(clock);  	tcd = base; @@ -48,8 +41,6 @@ static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base)  			      clocksource_mmio_readw_down);  	sched_clock_register(clps711x_sched_clock_read, 16, rate); - -	return 0;  }  static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) @@ -67,13 +58,6 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base,  	struct clock_event_device *clkevt;  	unsigned long rate; -	if (!irq) -		return -EINVAL; -	if (!base) -		return -ENOMEM; -	if (IS_ERR(clock)) -		return PTR_ERR(clock); -  	clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);  	if (!clkevt)  		return -ENOMEM; @@ -93,31 +77,29 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base,  			   "clps711x-timer", clkevt);  } -void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, -				 unsigned int irq) -{ -	struct clk *tc1 = clk_get_sys("clps711x-timer.0", NULL); -	struct clk *tc2 = clk_get_sys("clps711x-timer.1", NULL); - -	BUG_ON(_clps711x_clksrc_init(tc1, tc1_base)); -	BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq)); -} - -#ifdef CONFIG_TIMER_OF  static int __init clps711x_timer_init(struct device_node *np)  {  	unsigned int irq = irq_of_parse_and_map(np, 0);  	struct clk *clock = of_clk_get(np, 0);  	void __iomem *base = of_iomap(np, 0); +	if (!base) +		return -ENOMEM; +	if (!irq) +		return -EINVAL; +	if (IS_ERR(clock)) +		return PTR_ERR(clock); +  	switch (of_alias_get_id(np, "timer")) {  	case CLPS711X_CLKSRC_CLOCKSOURCE: -		return _clps711x_clksrc_init(clock, base); +		clps711x_clksrc_init(clock, base); +		break;  	case CLPS711X_CLKSRC_CLOCKEVENT:  		return _clps711x_clkevt_init(clock, base, irq);  	default:  		return -EINVAL;  	} + +	return 0;  }  TIMER_OF_DECLARE(clps711x, "cirrus,ep7209-timer", clps711x_timer_init); -#endif diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 7a244b681876..34bd250d46c6 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -10,14 +10,12 @@   * published by the Free Software Foundation.  */ -#include <linux/sched.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/err.h>  #include <linux/clk.h>  #include <linux/clockchips.h>  #include <linux/cpu.h> -#include <linux/platform_device.h>  #include <linux/delay.h>  #include <linux/percpu.h>  #include <linux/of.h> @@ -388,6 +386,13 @@ static void exynos4_mct_tick_start(unsigned long cycles,  	exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);  } +static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) +{ +	/* Clear the MCT tick interrupt */ +	if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) +		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); +} +  static int exynos4_tick_set_next_event(unsigned long cycles,  				       struct clock_event_device *evt)  { @@ -404,6 +409,7 @@ static int set_state_shutdown(struct clock_event_device *evt)  	mevt = container_of(evt, struct mct_clock_event_device, evt);  	exynos4_mct_tick_stop(mevt); +	exynos4_mct_tick_clear(mevt);  	return 0;  } @@ -420,8 +426,11 @@ static int set_state_periodic(struct clock_event_device *evt)  	return 0;  } -static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) +static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)  { +	struct mct_clock_event_device *mevt = dev_id; +	struct clock_event_device *evt = &mevt->evt; +  	/*  	 * This is for supporting oneshot mode.  	 * Mct would generate interrupt periodically @@ -430,16 +439,6 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)  	if (!clockevent_state_periodic(&mevt->evt))  		exynos4_mct_tick_stop(mevt); -	/* Clear the MCT tick interrupt */ -	if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) -		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); -} - -static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) -{ -	struct mct_clock_event_device *mevt = dev_id; -	struct clock_event_device *evt = &mevt->evt; -  	exynos4_mct_tick_clear(mevt);  	evt->event_handler(evt); @@ -507,13 +506,12 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem *  	int err, cpu;  	struct clk *mct_clk, *tick_clk; -	tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : -				clk_get(NULL, "fin_pll"); +	tick_clk = of_clk_get_by_name(np, "fin_pll");  	if (IS_ERR(tick_clk))  		panic("%s: unable to determine tick clock rate\n", __func__);  	clk_rate = clk_get_rate(tick_clk); -	mct_clk = np ? of_clk_get_by_name(np, "mct") : clk_get(NULL, "mct"); +	mct_clk = of_clk_get_by_name(np, "mct");  	if (IS_ERR(mct_clk))  		panic("%s: unable to retrieve mct clock instance\n", __func__);  	clk_prepare_enable(mct_clk); @@ -562,7 +560,19 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem *  	return 0;  out_irq: -	free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); +	if (mct_int_type == MCT_INT_PPI) { +		free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); +	} else { +		for_each_possible_cpu(cpu) { +			struct mct_clock_event_device *pcpu_mevt = +				per_cpu_ptr(&percpu_mct_tick, cpu); + +			if (pcpu_mevt->evt.irq != -1) { +				free_irq(pcpu_mevt->evt.irq, pcpu_mevt); +				pcpu_mevt->evt.irq = -1; +			} +		} +	}  	return err;  } @@ -581,11 +591,7 @@ static int __init mct_init_dt(struct device_node *np, unsigned int int_type)  	 * timer irqs are specified after the four global timer  	 * irqs are specified.  	 */ -#ifdef CONFIG_OF  	nr_irqs = of_irq_count(np); -#else -	nr_irqs = 0; -#endif  	for (i = MCT_L0_IRQ; i < nr_irqs; i++)  		mct_irqs[i] = irq_of_parse_and_map(np, i); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 54f8a331b53a..37671a5d4ed9 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -67,7 +67,7 @@ static irqreturn_t gic_compare_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -struct irqaction gic_compare_irqaction = { +static struct irqaction gic_compare_irqaction = {  	.handler = gic_compare_interrupt,  	.percpu_dev_id = &gic_clockevent_device,  	.flags = IRQF_PERCPU | IRQF_TIMER, diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 43f4d5c4d6fa..f987027ca566 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -71,7 +71,7 @@ static u64 tc_get_cycles32(struct clocksource *cs)  	return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));  } -void tc_clksrc_suspend(struct clocksource *cs) +static void tc_clksrc_suspend(struct clocksource *cs)  {  	int i; @@ -86,7 +86,7 @@ void tc_clksrc_suspend(struct clocksource *cs)  	bmr_cache = readl(tcaddr + ATMEL_TC_BMR);  } -void tc_clksrc_resume(struct clocksource *cs) +static void tc_clksrc_resume(struct clocksource *cs)  {  	int i; diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/timer-cs5535.c index 1de8cac99a0e..1de8cac99a0e 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/timer-cs5535.c diff --git a/drivers/clocksource/timer-milbeaut.c b/drivers/clocksource/timer-milbeaut.c new file mode 100644 index 000000000000..f2019a88e3ee --- /dev/null +++ b/drivers/clocksource/timer-milbeaut.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Socionext Inc. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqreturn.h> +#include <linux/sched_clock.h> +#include "timer-of.h" + +#define MLB_TMR_TMCSR_OFS	0x0 +#define MLB_TMR_TMR_OFS		0x4 +#define MLB_TMR_TMRLR1_OFS	0x8 +#define MLB_TMR_TMRLR2_OFS	0xc +#define MLB_TMR_REGSZPCH	0x10 + +#define MLB_TMR_TMCSR_OUTL	BIT(5) +#define MLB_TMR_TMCSR_RELD	BIT(4) +#define MLB_TMR_TMCSR_INTE	BIT(3) +#define MLB_TMR_TMCSR_UF	BIT(2) +#define MLB_TMR_TMCSR_CNTE	BIT(1) +#define MLB_TMR_TMCSR_TRG	BIT(0) + +#define MLB_TMR_TMCSR_CSL_DIV2	0 +#define MLB_TMR_DIV_CNT		2 + +#define MLB_TMR_SRC_CH  (1) +#define MLB_TMR_EVT_CH  (0) + +#define MLB_TMR_SRC_CH_OFS	(MLB_TMR_REGSZPCH * MLB_TMR_SRC_CH) +#define MLB_TMR_EVT_CH_OFS	(MLB_TMR_REGSZPCH * MLB_TMR_EVT_CH) + +#define MLB_TMR_SRC_TMCSR_OFS	(MLB_TMR_SRC_CH_OFS + MLB_TMR_TMCSR_OFS) +#define MLB_TMR_SRC_TMR_OFS	(MLB_TMR_SRC_CH_OFS + MLB_TMR_TMR_OFS) +#define MLB_TMR_SRC_TMRLR1_OFS	(MLB_TMR_SRC_CH_OFS + MLB_TMR_TMRLR1_OFS) +#define MLB_TMR_SRC_TMRLR2_OFS	(MLB_TMR_SRC_CH_OFS + MLB_TMR_TMRLR2_OFS) + +#define MLB_TMR_EVT_TMCSR_OFS	(MLB_TMR_EVT_CH_OFS + MLB_TMR_TMCSR_OFS) +#define MLB_TMR_EVT_TMR_OFS	(MLB_TMR_EVT_CH_OFS + MLB_TMR_TMR_OFS) +#define MLB_TMR_EVT_TMRLR1_OFS	(MLB_TMR_EVT_CH_OFS + MLB_TMR_TMRLR1_OFS) +#define MLB_TMR_EVT_TMRLR2_OFS	(MLB_TMR_EVT_CH_OFS + MLB_TMR_TMRLR2_OFS) + +#define MLB_TIMER_RATING	500 + +static irqreturn_t mlb_timer_interrupt(int irq, void *dev_id) +{ +	struct clock_event_device *clk = dev_id; +	struct timer_of *to = to_timer_of(clk); +	u32 val; + +	val = readl_relaxed(timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +	val &= ~MLB_TMR_TMCSR_UF; +	writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + +	clk->event_handler(clk); + +	return IRQ_HANDLED; +} + +static int mlb_set_state_periodic(struct clock_event_device *clk) +{ +	struct timer_of *to = to_timer_of(clk); +	u32 val = MLB_TMR_TMCSR_CSL_DIV2; + +	writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); + +	writel_relaxed(to->of_clk.period, timer_of_base(to) + +				MLB_TMR_EVT_TMRLR1_OFS); +	val |= MLB_TMR_TMCSR_RELD | MLB_TMR_TMCSR_CNTE | +		MLB_TMR_TMCSR_TRG | MLB_TMR_TMCSR_INTE; +	writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +	return 0; +} + +static int mlb_set_state_oneshot(struct clock_event_device *clk) +{ +	struct timer_of *to = to_timer_of(clk); +	u32 val = MLB_TMR_TMCSR_CSL_DIV2; + +	writel_relaxed(val, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +	return 0; +} + +static int mlb_clkevt_next_event(unsigned long event, +				   struct clock_event_device *clk) +{ +	struct timer_of *to = to_timer_of(clk); + +	writel_relaxed(event, timer_of_base(to) + MLB_TMR_EVT_TMRLR1_OFS); +	writel_relaxed(MLB_TMR_TMCSR_CSL_DIV2 | +			MLB_TMR_TMCSR_CNTE | MLB_TMR_TMCSR_INTE | +			MLB_TMR_TMCSR_TRG, timer_of_base(to) + +			MLB_TMR_EVT_TMCSR_OFS); +	return 0; +} + +static int mlb_config_clock_source(struct timer_of *to) +{ +	writel_relaxed(0, timer_of_base(to) + MLB_TMR_SRC_TMCSR_OFS); +	writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMR_OFS); +	writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR1_OFS); +	writel_relaxed(~0, timer_of_base(to) + MLB_TMR_SRC_TMRLR2_OFS); +	writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) + +		MLB_TMR_SRC_TMCSR_OFS); +	return 0; +} + +static int mlb_config_clock_event(struct timer_of *to) +{ +	writel_relaxed(0, timer_of_base(to) + MLB_TMR_EVT_TMCSR_OFS); +	return 0; +} + +static struct timer_of to = { +	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, + +	.clkevt = { +		.name = "mlb-clkevt", +		.rating = MLB_TIMER_RATING, +		.cpumask = cpu_possible_mask, +		.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT, +		.set_state_oneshot = mlb_set_state_oneshot, +		.set_state_periodic = mlb_set_state_periodic, +		.set_next_event = mlb_clkevt_next_event, +	}, + +	.of_irq = { +		.flags = IRQF_TIMER | IRQF_IRQPOLL, +		.handler = mlb_timer_interrupt, +	}, +}; + +static u64 notrace mlb_timer_sched_read(void) +{ +	return ~readl_relaxed(timer_of_base(&to) + MLB_TMR_SRC_TMR_OFS); +} + +static int __init mlb_timer_init(struct device_node *node) +{ +	int ret; +	unsigned long rate; + +	ret = timer_of_init(node, &to); +	if (ret) +		return ret; + +	rate = timer_of_rate(&to) / MLB_TMR_DIV_CNT; +	mlb_config_clock_source(&to); +	clocksource_mmio_init(timer_of_base(&to) + MLB_TMR_SRC_TMR_OFS, +		node->name, rate, MLB_TIMER_RATING, 32, +		clocksource_mmio_readl_down); +	sched_clock_register(mlb_timer_sched_read, 32, rate); +	mlb_config_clock_event(&to); +	clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 15, +		0xffffffff); +	return 0; +} +TIMER_OF_DECLARE(mlb_peritimer, "socionext,milbeaut-timer", +		mlb_timer_init); diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/timer-pxa.c index 395837938301..395837938301 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/timer-pxa.c diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index 431892200a08..5e6038fbf115 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c @@ -58,7 +58,7 @@ static u64 riscv_sched_clock(void)  static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {  	.name		= "riscv_clocksource",  	.rating		= 300, -	.mask		= CLOCKSOURCE_MASK(BITS_PER_LONG), +	.mask		= CLOCKSOURCE_MASK(64),  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,  	.read		= riscv_clocksource_rdtime,  }; @@ -95,23 +95,39 @@ static int __init riscv_timer_init_dt(struct device_node *n)  	struct clocksource *cs;  	hartid = riscv_of_processor_hartid(n); +	if (hartid < 0) { +		pr_warn("Not valid hartid for node [%pOF] error = [%d]\n", +			n, hartid); +		return hartid; +	} +  	cpuid = riscv_hartid_to_cpuid(hartid); +	if (cpuid < 0) { +		pr_warn("Invalid cpuid for hartid [%d]\n", hartid); +		return cpuid; +	}  	if (cpuid != smp_processor_id())  		return 0; +	pr_info("%s: Registering clocksource cpuid [%d] hartid [%d]\n", +	       __func__, cpuid, hartid);  	cs = per_cpu_ptr(&riscv_clocksource, cpuid); -	clocksource_register_hz(cs, riscv_timebase); +	error = clocksource_register_hz(cs, riscv_timebase); +	if (error) { +		pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", +		       error, cpuid); +		return error; +	} -	sched_clock_register(riscv_sched_clock, -			BITS_PER_LONG, riscv_timebase); +	sched_clock_register(riscv_sched_clock, 64, riscv_timebase);  	error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,  			 "clockevents/riscv/timer:starting",  			 riscv_timer_starting_cpu, riscv_timer_dying_cpu);  	if (error) -		pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", -		       error, cpuid); +		pr_err("cpu hp setup state failed for RISCV timer [%d]\n", +		       error);  	return error;  } diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 3b56ea3f52af..552c5254390c 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -202,6 +202,11 @@ static int __init sun5i_setup_clocksource(struct device_node *node,  	}  	rate = clk_get_rate(clk); +	if (!rate) { +		pr_err("Couldn't get parent clock rate\n"); +		ret = -EINVAL; +		goto err_disable_clk; +	}  	cs->timer.base = base;  	cs->timer.clk = clk; @@ -275,6 +280,11 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem  	}  	rate = clk_get_rate(clk); +	if (!rate) { +		pr_err("Couldn't get parent clock rate\n"); +		ret = -EINVAL; +		goto err_disable_clk; +	}  	ce->timer.base = base;  	ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/timer-tango-xtal.c index 3f94e454ef99..3f94e454ef99 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/timer-tango-xtal.c diff --git a/drivers/clocksource/timer-tegra20.c b/drivers/clocksource/timer-tegra20.c index 4293943f4e2b..fdb3d795a409 100644 --- a/drivers/clocksource/timer-tegra20.c +++ b/drivers/clocksource/timer-tegra20.c @@ -15,21 +15,24 @@   *   */ -#include <linux/init.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/delay.h>  #include <linux/err.h> -#include <linux/time.h>  #include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/clockchips.h> -#include <linux/clocksource.h> -#include <linux/clk.h> -#include <linux/io.h>  #include <linux/of_address.h>  #include <linux/of_irq.h> +#include <linux/percpu.h>  #include <linux/sched_clock.h> -#include <linux/delay.h> +#include <linux/time.h> + +#include "timer-of.h" +#ifdef CONFIG_ARM  #include <asm/mach/time.h> +#endif  #define RTC_SECONDS            0x08  #define RTC_SHADOW_SECONDS     0x0c @@ -39,74 +42,161 @@  #define TIMERUS_USEC_CFG 0x14  #define TIMERUS_CNTR_FREEZE 0x4c -#define TIMER1_BASE 0x0 -#define TIMER2_BASE 0x8 -#define TIMER3_BASE 0x50 -#define TIMER4_BASE 0x58 - -#define TIMER_PTV 0x0 -#define TIMER_PCR 0x4 - +#define TIMER_PTV		0x0 +#define TIMER_PTV_EN		BIT(31) +#define TIMER_PTV_PER		BIT(30) +#define TIMER_PCR		0x4 +#define TIMER_PCR_INTR_CLR	BIT(30) + +#ifdef CONFIG_ARM +#define TIMER_CPU0		0x50 /* TIMER3 */ +#else +#define TIMER_CPU0		0x90 /* TIMER10 */ +#define TIMER10_IRQ_IDX		10 +#define IRQ_IDX_FOR_CPU(cpu)	(TIMER10_IRQ_IDX + cpu) +#endif +#define TIMER_BASE_FOR_CPU(cpu) (TIMER_CPU0 + (cpu) * 8) + +static u32 usec_config;  static void __iomem *timer_reg_base; +#ifdef CONFIG_ARM  static void __iomem *rtc_base; -  static struct timespec64 persistent_ts;  static u64 persistent_ms, last_persistent_ms; -  static struct delay_timer tegra_delay_timer; - -#define timer_writel(value, reg) \ -	writel_relaxed(value, timer_reg_base + (reg)) -#define timer_readl(reg) \ -	readl_relaxed(timer_reg_base + (reg)) +#endif  static int tegra_timer_set_next_event(unsigned long cycles,  					 struct clock_event_device *evt)  { -	u32 reg; +	void __iomem *reg_base = timer_of_base(to_timer_of(evt)); -	reg = 0x80000000 | ((cycles > 1) ? (cycles-1) : 0); -	timer_writel(reg, TIMER3_BASE + TIMER_PTV); +	writel(TIMER_PTV_EN | +	       ((cycles > 1) ? (cycles - 1) : 0), /* n+1 scheme */ +	       reg_base + TIMER_PTV);  	return 0;  } -static inline void timer_shutdown(struct clock_event_device *evt) +static int tegra_timer_shutdown(struct clock_event_device *evt)  { -	timer_writel(0, TIMER3_BASE + TIMER_PTV); +	void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + +	writel(0, reg_base + TIMER_PTV); + +	return 0;  } -static int tegra_timer_shutdown(struct clock_event_device *evt) +static int tegra_timer_set_periodic(struct clock_event_device *evt)  { -	timer_shutdown(evt); +	void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + +	writel(TIMER_PTV_EN | TIMER_PTV_PER | +	       ((timer_of_rate(to_timer_of(evt)) / HZ) - 1), +	       reg_base + TIMER_PTV); +  	return 0;  } -static int tegra_timer_set_periodic(struct clock_event_device *evt) +static irqreturn_t tegra_timer_isr(int irq, void *dev_id) +{ +	struct clock_event_device *evt = (struct clock_event_device *)dev_id; +	void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + +	writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); +	evt->event_handler(evt); + +	return IRQ_HANDLED; +} + +static void tegra_timer_suspend(struct clock_event_device *evt) +{ +	void __iomem *reg_base = timer_of_base(to_timer_of(evt)); + +	writel(TIMER_PCR_INTR_CLR, reg_base + TIMER_PCR); +} + +static void tegra_timer_resume(struct clock_event_device *evt) +{ +	writel(usec_config, timer_reg_base + TIMERUS_USEC_CFG); +} + +#ifdef CONFIG_ARM64 +static DEFINE_PER_CPU(struct timer_of, tegra_to) = { +	.flags = TIMER_OF_CLOCK | TIMER_OF_BASE, + +	.clkevt = { +		.name = "tegra_timer", +		.rating = 460, +		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, +		.set_next_event = tegra_timer_set_next_event, +		.set_state_shutdown = tegra_timer_shutdown, +		.set_state_periodic = tegra_timer_set_periodic, +		.set_state_oneshot = tegra_timer_shutdown, +		.tick_resume = tegra_timer_shutdown, +		.suspend = tegra_timer_suspend, +		.resume = tegra_timer_resume, +	}, +}; + +static int tegra_timer_setup(unsigned int cpu)  { -	u32 reg = 0xC0000000 | ((1000000 / HZ) - 1); +	struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); + +	irq_force_affinity(to->clkevt.irq, cpumask_of(cpu)); +	enable_irq(to->clkevt.irq); + +	clockevents_config_and_register(&to->clkevt, timer_of_rate(to), +					1, /* min */ +					0x1fffffff); /* 29 bits */ -	timer_shutdown(evt); -	timer_writel(reg, TIMER3_BASE + TIMER_PTV);  	return 0;  } -static struct clock_event_device tegra_clockevent = { -	.name			= "timer0", -	.rating			= 300, -	.features		= CLOCK_EVT_FEAT_ONESHOT | -				  CLOCK_EVT_FEAT_PERIODIC | -				  CLOCK_EVT_FEAT_DYNIRQ, -	.set_next_event		= tegra_timer_set_next_event, -	.set_state_shutdown	= tegra_timer_shutdown, -	.set_state_periodic	= tegra_timer_set_periodic, -	.set_state_oneshot	= tegra_timer_shutdown, -	.tick_resume		= tegra_timer_shutdown, +static int tegra_timer_stop(unsigned int cpu) +{ +	struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); + +	to->clkevt.set_state_shutdown(&to->clkevt); +	disable_irq_nosync(to->clkevt.irq); + +	return 0; +} +#else /* CONFIG_ARM */ +static struct timer_of tegra_to = { +	.flags = TIMER_OF_CLOCK | TIMER_OF_BASE | TIMER_OF_IRQ, + +	.clkevt = { +		.name = "tegra_timer", +		.rating	= 300, +		.features = CLOCK_EVT_FEAT_ONESHOT | +			    CLOCK_EVT_FEAT_PERIODIC | +			    CLOCK_EVT_FEAT_DYNIRQ, +		.set_next_event	= tegra_timer_set_next_event, +		.set_state_shutdown = tegra_timer_shutdown, +		.set_state_periodic = tegra_timer_set_periodic, +		.set_state_oneshot = tegra_timer_shutdown, +		.tick_resume = tegra_timer_shutdown, +		.suspend = tegra_timer_suspend, +		.resume = tegra_timer_resume, +		.cpumask = cpu_possible_mask, +	}, + +	.of_irq = { +		.index = 2, +		.flags = IRQF_TIMER | IRQF_TRIGGER_HIGH, +		.handler = tegra_timer_isr, +	},  };  static u64 notrace tegra_read_sched_clock(void)  { -	return timer_readl(TIMERUS_CNTR_1US); +	return readl(timer_reg_base + TIMERUS_CNTR_1US); +} + +static unsigned long tegra_delay_timer_read_counter_long(void) +{ +	return readl(timer_reg_base + TIMERUS_CNTR_1US);  }  /* @@ -143,100 +233,155 @@ static void tegra_read_persistent_clock64(struct timespec64 *ts)  	timespec64_add_ns(&persistent_ts, delta * NSEC_PER_MSEC);  	*ts = persistent_ts;  } +#endif -static unsigned long tegra_delay_timer_read_counter_long(void) -{ -	return readl(timer_reg_base + TIMERUS_CNTR_1US); -} - -static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) -{ -	struct clock_event_device *evt = (struct clock_event_device *)dev_id; -	timer_writel(1<<30, TIMER3_BASE + TIMER_PCR); -	evt->event_handler(evt); -	return IRQ_HANDLED; -} - -static struct irqaction tegra_timer_irq = { -	.name		= "timer0", -	.flags		= IRQF_TIMER | IRQF_TRIGGER_HIGH, -	.handler	= tegra_timer_interrupt, -	.dev_id		= &tegra_clockevent, -}; - -static int __init tegra20_init_timer(struct device_node *np) +static int tegra_timer_common_init(struct device_node *np, struct timer_of *to)  { -	struct clk *clk; -	unsigned long rate; -	int ret; - -	timer_reg_base = of_iomap(np, 0); -	if (!timer_reg_base) { -		pr_err("Can't map timer registers\n"); -		return -ENXIO; -	} +	int ret = 0; -	tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); -	if (tegra_timer_irq.irq <= 0) { -		pr_err("Failed to map timer IRQ\n"); -		return -EINVAL; -	} +	ret = timer_of_init(np, to); +	if (ret < 0) +		goto out; -	clk = of_clk_get(np, 0); -	if (IS_ERR(clk)) { -		pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n"); -		rate = 12000000; -	} else { -		clk_prepare_enable(clk); -		rate = clk_get_rate(clk); -	} +	timer_reg_base = timer_of_base(to); -	switch (rate) { +	/* +	 * Configure microsecond timers to have 1MHz clock +	 * Config register is 0xqqww, where qq is "dividend", ww is "divisor" +	 * Uses n+1 scheme +	 */ +	switch (timer_of_rate(to)) {  	case 12000000: -		timer_writel(0x000b, TIMERUS_USEC_CFG); +		usec_config = 0x000b; /* (11+1)/(0+1) */ +		break; +	case 12800000: +		usec_config = 0x043f; /* (63+1)/(4+1) */  		break;  	case 13000000: -		timer_writel(0x000c, TIMERUS_USEC_CFG); +		usec_config = 0x000c; /* (12+1)/(0+1) */ +		break; +	case 16800000: +		usec_config = 0x0453; /* (83+1)/(4+1) */  		break;  	case 19200000: -		timer_writel(0x045f, TIMERUS_USEC_CFG); +		usec_config = 0x045f; /* (95+1)/(4+1) */  		break;  	case 26000000: -		timer_writel(0x0019, TIMERUS_USEC_CFG); +		usec_config = 0x0019; /* (25+1)/(0+1) */ +		break; +	case 38400000: +		usec_config = 0x04bf; /* (191+1)/(4+1) */ +		break; +	case 48000000: +		usec_config = 0x002f; /* (47+1)/(0+1) */  		break;  	default: -		WARN(1, "Unknown clock rate"); +		ret = -EINVAL; +		goto out; +	} + +	writel(usec_config, timer_of_base(to) + TIMERUS_USEC_CFG); + +out: +	return ret; +} + +#ifdef CONFIG_ARM64 +static int __init tegra_init_timer(struct device_node *np) +{ +	int cpu, ret = 0; +	struct timer_of *to; + +	to = this_cpu_ptr(&tegra_to); +	ret = tegra_timer_common_init(np, to); +	if (ret < 0) +		goto out; + +	for_each_possible_cpu(cpu) { +		struct timer_of *cpu_to; + +		cpu_to = per_cpu_ptr(&tegra_to, cpu); +		cpu_to->of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(cpu); +		cpu_to->of_clk.rate = timer_of_rate(to); +		cpu_to->clkevt.cpumask = cpumask_of(cpu); +		cpu_to->clkevt.irq = +			irq_of_parse_and_map(np, IRQ_IDX_FOR_CPU(cpu)); +		if (!cpu_to->clkevt.irq) { +			pr_err("%s: can't map IRQ for CPU%d\n", +			       __func__, cpu); +			ret = -EINVAL; +			goto out; +		} + +		irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN); +		ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, +				  IRQF_TIMER | IRQF_NOBALANCING, +				  cpu_to->clkevt.name, &cpu_to->clkevt); +		if (ret) { +			pr_err("%s: cannot setup irq %d for CPU%d\n", +				__func__, cpu_to->clkevt.irq, cpu); +			ret = -EINVAL; +			goto out_irq; +		} +	} + +	cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING, +			  "AP_TEGRA_TIMER_STARTING", tegra_timer_setup, +			  tegra_timer_stop); + +	return ret; +out_irq: +	for_each_possible_cpu(cpu) { +		struct timer_of *cpu_to; + +		cpu_to = per_cpu_ptr(&tegra_to, cpu); +		if (cpu_to->clkevt.irq) { +			free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt); +			irq_dispose_mapping(cpu_to->clkevt.irq); +		}  	} +out: +	timer_of_cleanup(to); +	return ret; +} +#else /* CONFIG_ARM */ +static int __init tegra_init_timer(struct device_node *np) +{ +	int ret = 0; + +	ret = tegra_timer_common_init(np, &tegra_to); +	if (ret < 0) +		goto out; -	sched_clock_register(tegra_read_sched_clock, 32, 1000000); +	tegra_to.of_base.base = timer_reg_base + TIMER_BASE_FOR_CPU(0); +	tegra_to.of_clk.rate = 1000000; /* microsecond timer */ +	sched_clock_register(tegra_read_sched_clock, 32, +			     timer_of_rate(&tegra_to));  	ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, -				    "timer_us", 1000000, 300, 32, -				    clocksource_mmio_readl_up); +				    "timer_us", timer_of_rate(&tegra_to), +				    300, 32, clocksource_mmio_readl_up);  	if (ret) {  		pr_err("Failed to register clocksource\n"); -		return ret; +		goto out;  	}  	tegra_delay_timer.read_current_timer =  			tegra_delay_timer_read_counter_long; -	tegra_delay_timer.freq = 1000000; +	tegra_delay_timer.freq = timer_of_rate(&tegra_to);  	register_current_timer_delay(&tegra_delay_timer); -	ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); -	if (ret) { -		pr_err("Failed to register timer IRQ: %d\n", ret); -		return ret; -	} +	clockevents_config_and_register(&tegra_to.clkevt, +					timer_of_rate(&tegra_to), +					0x1, +					0x1fffffff); -	tegra_clockevent.cpumask = cpu_possible_mask; -	tegra_clockevent.irq = tegra_timer_irq.irq; -	clockevents_config_and_register(&tegra_clockevent, 1000000, -					0x1, 0x1fffffff); +	return ret; +out: +	timer_of_cleanup(&tegra_to); -	return 0; +	return ret;  } -TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer);  static int __init tegra20_init_rtc(struct device_node *np)  { @@ -261,3 +406,6 @@ static int __init tegra20_init_rtc(struct device_node *np)  	return register_persistent_clock(tegra_read_persistent_clock64);  }  TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); +#endif +TIMER_OF_DECLARE(tegra210_timer, "nvidia,tegra210-timer", tegra_init_timer); +TIMER_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra_init_timer); diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 595124074821..3352da6ed61f 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -154,6 +154,10 @@ static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)  	if (IS_ERR(parent))  		return -ENODEV; +	/* Bail out if both clocks point to fck */ +	if (clk_is_match(parent, timer->fclk)) +		return 0; +  	ret = clk_set_parent(timer->fclk, parent);  	if (ret < 0)  		pr_err("%s: failed to set parent\n", __func__); @@ -582,8 +586,8 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,  }  /* Optimized set_load which removes costly spin wait in timer_start */ -int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, -                            unsigned int load) +static int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, +					int autoreload, unsigned int load)  {  	u32 l; @@ -864,7 +868,6 @@ static int omap_dm_timer_probe(struct platform_device *pdev)  	timer->pdev = pdev;  	pm_runtime_enable(dev); -	pm_runtime_irq_safe(dev);  	if (!timer->reserved) {  		ret = pm_runtime_get_sync(dev);  | 

