linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] ARM: davinci: convert dm365 to using the new clocksource driver
@ 2019-12-13 16:24 Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-13 16:24 UTC (permalink / raw)
  To: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, David Lechner,
	Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This is a follow-up to the big series converting DaVinci to using
a proper clocksource driver. Last time we couldn't merge the entire
series because of a bug that only appears on dm365 Soc when using
ancient u-boot.

This series contains a workaround for this problem, a patch finally
converting the platform as well as a removal of all obsolete code.

Bartosz Golaszewski (3):
  clocksource: davinci: work around a clocksource problem on dm365 SoC
  ARM: davinci: dm365: switch to using the clocksource driver
  ARM: davinci: remove legacy timer support

 arch/arm/mach-davinci/Makefile              |   3 +-
 arch/arm/mach-davinci/devices-da8xx.c       |   1 -
 arch/arm/mach-davinci/devices.c             |  19 -
 arch/arm/mach-davinci/dm365.c               |  22 +-
 arch/arm/mach-davinci/include/mach/common.h |  17 -
 arch/arm/mach-davinci/include/mach/time.h   |  33 --
 arch/arm/mach-davinci/time.c                | 400 --------------------
 drivers/clocksource/timer-davinci.c         |   8 +-
 8 files changed, 22 insertions(+), 481 deletions(-)
 delete mode 100644 arch/arm/mach-davinci/include/mach/time.h
 delete mode 100644 arch/arm/mach-davinci/time.c

-- 
2.23.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-13 16:24 [PATCH 0/3] ARM: davinci: convert dm365 to using the new clocksource driver Bartosz Golaszewski
@ 2019-12-13 16:24 ` Bartosz Golaszewski
  2019-12-16 17:58   ` David Lechner
  2019-12-18  9:28   ` Sekhar Nori
  2019-12-13 16:24 ` [PATCH 2/3] ARM: davinci: dm365: switch to using the clocksource driver Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 3/3] ARM: davinci: remove legacy timer support Bartosz Golaszewski
  2 siblings, 2 replies; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-13 16:24 UTC (permalink / raw)
  To: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, David Lechner,
	Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

The DM365 platform has a strange quirk (only present when using ancient
u-boot - mainline u-boot v2013.01 and later works fine) where if we
enable the second half of the timer in periodic mode before we do its
initialization - the time won't start flowing and we can't boot.

When using more recent u-boot, we can enable the timer, then reinitialize
it and all works fine.

I've been unable to figure out why that is, but a workaround for this
is straightforward - just cache the enable bits for tim34.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/clocksource/timer-davinci.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c
index 62745c962049..1c22443acaeb 100644
--- a/drivers/clocksource/timer-davinci.c
+++ b/drivers/clocksource/timer-davinci.c
@@ -64,6 +64,8 @@ static struct {
 	unsigned int tim_off;
 } davinci_clocksource;
 
+static unsigned int davinci_clocksource_tim32_mode;
+
 static struct davinci_clockevent *
 to_davinci_clockevent(struct clock_event_device *clockevent)
 {
@@ -94,7 +96,7 @@ static void davinci_tim12_shutdown(void __iomem *base)
 	 * halves. In this case TIM34 runs in periodic mode and we must
 	 * not modify it.
 	 */
-	tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
+	tcr |= davinci_clocksource_tim32_mode <<
 		DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
 
 	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
@@ -107,7 +109,7 @@ static void davinci_tim12_set_oneshot(void __iomem *base)
 	tcr = DAVINCI_TIMER_ENAMODE_ONESHOT <<
 		DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
 	/* Same as above. */
-	tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
+	tcr |= davinci_clocksource_tim32_mode <<
 		DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
 
 	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
@@ -206,6 +208,8 @@ static void davinci_clocksource_init_tim34(void __iomem *base)
 	writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34);
 	writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34);
 	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
+
+	davinci_clocksource_tim32_mode = DAVINCI_TIMER_ENAMODE_PERIODIC;
 }
 
 /*
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] ARM: davinci: dm365: switch to using the clocksource driver
  2019-12-13 16:24 [PATCH 0/3] ARM: davinci: convert dm365 to using the new clocksource driver Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
@ 2019-12-13 16:24 ` Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 3/3] ARM: davinci: remove legacy timer support Bartosz Golaszewski
  2 siblings, 0 replies; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-13 16:24 UTC (permalink / raw)
  To: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, David Lechner,
	Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

We now have a proper clocksource driver for davinci. Switch the dm365
platform to using it.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
---
 arch/arm/mach-davinci/dm365.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 9fc5c73cc0be..c1e0d46996e4 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -35,7 +35,8 @@
 #include <mach/cputype.h>
 #include <mach/mux.h>
 #include <mach/serial.h>
-#include <mach/time.h>
+
+#include <clocksource/timer-davinci.h>
 
 #include "asp.h"
 #include "davinci.h"
@@ -660,10 +661,16 @@ static struct davinci_id dm365_ids[] = {
 	},
 };
 
-static struct davinci_timer_info dm365_timer_info = {
-	.timers		= davinci_timer_instance,
-	.clockevent_id	= T0_BOT,
-	.clocksource_id	= T0_TOP,
+/*
+ * Bottom half of timer0 is used for clockevent, top half is used for
+ * clocksource.
+ */
+static const struct davinci_timer_cfg dm365_timer_cfg = {
+	.reg = DEFINE_RES_IO(DAVINCI_TIMER0_BASE, SZ_128),
+	.irq = {
+		DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12)),
+		DEFINE_RES_IRQ(DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34)),
+	},
 };
 
 #define DM365_UART1_BASE	(IO_PHYS + 0x106000)
@@ -723,7 +730,6 @@ static const struct davinci_soc_info davinci_soc_info_dm365 = {
 	.pinmux_base		= DAVINCI_SYSTEM_MODULE_BASE,
 	.pinmux_pins		= dm365_pins,
 	.pinmux_pins_num	= ARRAY_SIZE(dm365_pins),
-	.timer_info		= &dm365_timer_info,
 	.emac_pdata		= &dm365_emac_pdata,
 	.sram_dma		= 0x00010000,
 	.sram_len		= SZ_32K,
@@ -771,6 +777,7 @@ void __init dm365_init_time(void)
 {
 	void __iomem *pll1, *pll2, *psc;
 	struct clk *clk;
+	int rv;
 
 	clk_register_fixed_rate(NULL, "ref_clk", NULL, 0, DM365_REF_FREQ);
 
@@ -789,7 +796,8 @@ void __init dm365_init_time(void)
 		return;
 	}
 
-	davinci_timer_init(clk);
+	rv = davinci_timer_register(clk, &dm365_timer_cfg);
+	WARN(rv, "Unable to register the timer: %d\n", rv);
 }
 
 void __init dm365_register_clocks(void)
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] ARM: davinci: remove legacy timer support
  2019-12-13 16:24 [PATCH 0/3] ARM: davinci: convert dm365 to using the new clocksource driver Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
  2019-12-13 16:24 ` [PATCH 2/3] ARM: davinci: dm365: switch to using the clocksource driver Bartosz Golaszewski
@ 2019-12-13 16:24 ` Bartosz Golaszewski
  2 siblings, 0 replies; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-13 16:24 UTC (permalink / raw)
  To: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, David Lechner,
	Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

All platforms have now been switched to the new clocksource driver.
Remove the old code and various no longer needed bits and pieces.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
---
 arch/arm/mach-davinci/Makefile              |   3 +-
 arch/arm/mach-davinci/devices-da8xx.c       |   1 -
 arch/arm/mach-davinci/devices.c             |  19 -
 arch/arm/mach-davinci/include/mach/common.h |  17 -
 arch/arm/mach-davinci/include/mach/time.h   |  33 --
 arch/arm/mach-davinci/time.c                | 400 --------------------
 6 files changed, 1 insertion(+), 472 deletions(-)
 delete mode 100644 arch/arm/mach-davinci/include/mach/time.h
 delete mode 100644 arch/arm/mach-davinci/time.c

diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index a03d8443ef08..58838a9de651 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -7,8 +7,7 @@
 ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
 
 # Common objects
-obj-y 					:= time.o serial.o usb.o \
-					   common.o sram.o
+obj-y 					:= serial.o usb.o common.o sram.o
 
 obj-$(CONFIG_DAVINCI_MUX)		+= mux.o
 
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 2d69e704f7f6..feb206bdf6e1 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -21,7 +21,6 @@
 #include <mach/common.h>
 #include <mach/cputype.h>
 #include <mach/da8xx.h>
-#include <mach/time.h>
 
 #include "asp.h"
 #include "cpuidle.h"
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 3e447d468845..d912d62a0eca 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -17,7 +17,6 @@
 #include <mach/hardware.h>
 #include <mach/cputype.h>
 #include <mach/mux.h>
-#include <mach/time.h>
 
 #include "davinci.h"
 #include "irqs.h"
@@ -303,21 +302,3 @@ int davinci_gpio_register(struct resource *res, int size, void *pdata)
 	davinci_gpio_device.dev.platform_data = pdata;
 	return platform_device_register(&davinci_gpio_device);
 }
-
-/*-------------------------------------------------------------------------*/
-
-/*-------------------------------------------------------------------------*/
-
-struct davinci_timer_instance davinci_timer_instance[2] = {
-	{
-		.base		= DAVINCI_TIMER0_BASE,
-		.bottom_irq	= DAVINCI_INTC_IRQ(IRQ_TINT0_TINT12),
-		.top_irq	= DAVINCI_INTC_IRQ(IRQ_TINT0_TINT34),
-	},
-	{
-		.base		= DAVINCI_TIMER1_BASE,
-		.bottom_irq	= DAVINCI_INTC_IRQ(IRQ_TINT1_TINT12),
-		.top_irq	= DAVINCI_INTC_IRQ(IRQ_TINT1_TINT34),
-	},
-};
-
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index 9526e5da0d33..139b83de011d 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -22,22 +22,6 @@
 #define DAVINCI_INTC_START		NR_IRQS
 #define DAVINCI_INTC_IRQ(_irqnum)	(DAVINCI_INTC_START + (_irqnum))
 
-void davinci_timer_init(struct clk *clk);
-
-struct davinci_timer_instance {
-	u32		base;
-	u32		bottom_irq;
-	u32		top_irq;
-	unsigned long	cmp_off;
-	unsigned int	cmp_irq;
-};
-
-struct davinci_timer_info {
-	struct davinci_timer_instance	*timers;
-	unsigned int			clockevent_id;
-	unsigned int			clocksource_id;
-};
-
 struct davinci_gpio_controller;
 
 /*
@@ -58,7 +42,6 @@ struct davinci_soc_info {
 	u32				pinmux_base;
 	const struct mux_config		*pinmux_pins;
 	unsigned long			pinmux_pins_num;
-	struct davinci_timer_info	*timer_info;
 	int				gpio_type;
 	u32				gpio_base;
 	unsigned			gpio_num;
diff --git a/arch/arm/mach-davinci/include/mach/time.h b/arch/arm/mach-davinci/include/mach/time.h
deleted file mode 100644
index ba913736990f..000000000000
--- a/arch/arm/mach-davinci/include/mach/time.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Local header file for DaVinci time code.
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ARCH_ARM_MACH_DAVINCI_TIME_H
-#define __ARCH_ARM_MACH_DAVINCI_TIME_H
-
-#define DAVINCI_TIMER1_BASE		(IO_PHYS + 0x21800)
-
-enum {
-	T0_BOT,
-	T0_TOP,
-	T1_BOT,
-	T1_TOP,
-	NUM_TIMERS
-};
-
-#define IS_TIMER1(id)		(id & 0x2)
-#define IS_TIMER0(id)		(!IS_TIMER1(id))
-#define IS_TIMER_TOP(id)	((id & 0x1))
-#define IS_TIMER_BOT(id)	(!IS_TIMER_TOP(id))
-
-#define ID_TO_TIMER(id)		(IS_TIMER1(id) != 0)
-
-extern struct davinci_timer_instance davinci_timer_instance[];
-
-#endif /* __ARCH_ARM_MACH_DAVINCI_TIME_H */
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
deleted file mode 100644
index 740410a3bb6a..000000000000
--- a/arch/arm/mach-davinci/time.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * DaVinci timer subsystem
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/sched_clock.h>
-
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-
-#include <mach/cputype.h>
-#include <mach/hardware.h>
-#include <mach/time.h>
-
-static struct clock_event_device clockevent_davinci;
-static unsigned int davinci_clock_tick_rate;
-
-/*
- * This driver configures the 2 64-bit count-up timers as 4 independent
- * 32-bit count-up timers used as follows:
- */
-
-enum {
-	TID_CLOCKEVENT,
-	TID_CLOCKSOURCE,
-};
-
-/* Timer register offsets */
-#define PID12			0x0
-#define TIM12			0x10
-#define TIM34			0x14
-#define PRD12			0x18
-#define PRD34			0x1c
-#define TCR			0x20
-#define TGCR			0x24
-#define WDTCR			0x28
-
-/* Offsets of the 8 compare registers */
-#define	CMP12_0			0x60
-#define	CMP12_1			0x64
-#define	CMP12_2			0x68
-#define	CMP12_3			0x6c
-#define	CMP12_4			0x70
-#define	CMP12_5			0x74
-#define	CMP12_6			0x78
-#define	CMP12_7			0x7c
-
-/* Timer register bitfields */
-#define TCR_ENAMODE_DISABLE          0x0
-#define TCR_ENAMODE_ONESHOT          0x1
-#define TCR_ENAMODE_PERIODIC         0x2
-#define TCR_ENAMODE_MASK             0x3
-
-#define TGCR_TIMMODE_SHIFT           2
-#define TGCR_TIMMODE_64BIT_GP        0x0
-#define TGCR_TIMMODE_32BIT_UNCHAINED 0x1
-#define TGCR_TIMMODE_64BIT_WDOG      0x2
-#define TGCR_TIMMODE_32BIT_CHAINED   0x3
-
-#define TGCR_TIM12RS_SHIFT           0
-#define TGCR_TIM34RS_SHIFT           1
-#define TGCR_RESET                   0x0
-#define TGCR_UNRESET                 0x1
-#define TGCR_RESET_MASK              0x3
-
-struct timer_s {
-	char *name;
-	unsigned int id;
-	unsigned long period;
-	unsigned long opts;
-	unsigned long flags;
-	void __iomem *base;
-	unsigned long tim_off;
-	unsigned long prd_off;
-	unsigned long enamode_shift;
-	struct irqaction irqaction;
-};
-static struct timer_s timers[];
-
-/* values for 'opts' field of struct timer_s */
-#define TIMER_OPTS_DISABLED		0x01
-#define TIMER_OPTS_ONESHOT		0x02
-#define TIMER_OPTS_PERIODIC		0x04
-#define TIMER_OPTS_STATE_MASK		0x07
-
-#define TIMER_OPTS_USE_COMPARE		0x80000000
-#define USING_COMPARE(t)		((t)->opts & TIMER_OPTS_USE_COMPARE)
-
-static char *id_to_name[] = {
-	[T0_BOT]	= "timer0_0",
-	[T0_TOP]	= "timer0_1",
-	[T1_BOT]	= "timer1_0",
-	[T1_TOP]	= "timer1_1",
-};
-
-static int timer32_config(struct timer_s *t)
-{
-	u32 tcr;
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
-
-	if (USING_COMPARE(t)) {
-		struct davinci_timer_instance *dtip =
-				soc_info->timer_info->timers;
-		int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id);
-
-		/*
-		 * Next interrupt should be the current time reg value plus
-		 * the new period (using 32-bit unsigned addition/wrapping
-		 * to 0 on overflow).  This assumes that the clocksource
-		 * is setup to count to 2^32-1 before wrapping around to 0.
-		 */
-		__raw_writel(__raw_readl(t->base + t->tim_off) + t->period,
-			t->base + dtip[event_timer].cmp_off);
-	} else {
-		tcr = __raw_readl(t->base + TCR);
-
-		/* disable timer */
-		tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
-		__raw_writel(tcr, t->base + TCR);
-
-		/* reset counter to zero, set new period */
-		__raw_writel(0, t->base + t->tim_off);
-		__raw_writel(t->period, t->base + t->prd_off);
-
-		/* Set enable mode */
-		if (t->opts & TIMER_OPTS_ONESHOT)
-			tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
-		else if (t->opts & TIMER_OPTS_PERIODIC)
-			tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
-
-		__raw_writel(tcr, t->base + TCR);
-	}
-	return 0;
-}
-
-static inline u32 timer32_read(struct timer_s *t)
-{
-	return __raw_readl(t->base + t->tim_off);
-}
-
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = &clockevent_davinci;
-
-	evt->event_handler(evt);
-	return IRQ_HANDLED;
-}
-
-/* called when 32-bit counter wraps */
-static irqreturn_t freerun_interrupt(int irq, void *dev_id)
-{
-	return IRQ_HANDLED;
-}
-
-static struct timer_s timers[] = {
-	[TID_CLOCKEVENT] = {
-		.name      = "clockevent",
-		.opts      = TIMER_OPTS_DISABLED,
-		.irqaction = {
-			.flags   = IRQF_TIMER,
-			.handler = timer_interrupt,
-		}
-	},
-	[TID_CLOCKSOURCE] = {
-		.name       = "free-run counter",
-		.period     = ~0,
-		.opts       = TIMER_OPTS_PERIODIC,
-		.irqaction = {
-			.flags   = IRQF_TIMER,
-			.handler = freerun_interrupt,
-		}
-	},
-};
-
-static void __init timer_init(void)
-{
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
-	struct davinci_timer_instance *dtip = soc_info->timer_info->timers;
-	void __iomem *base[2];
-	int i;
-
-	/* Global init of each 64-bit timer as a whole */
-	for(i=0; i<2; i++) {
-		u32 tgcr;
-
-		base[i] = ioremap(dtip[i].base, SZ_4K);
-		if (WARN_ON(!base[i]))
-			continue;
-
-		/* Disabled, Internal clock source */
-		__raw_writel(0, base[i] + TCR);
-
-		/* reset both timers, no pre-scaler for timer34 */
-		tgcr = 0;
-		__raw_writel(tgcr, base[i] + TGCR);
-
-		/* Set both timers to unchained 32-bit */
-		tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT;
-		__raw_writel(tgcr, base[i] + TGCR);
-
-		/* Unreset timers */
-		tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
-			(TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
-		__raw_writel(tgcr, base[i] + TGCR);
-
-		/* Init both counters to zero */
-		__raw_writel(0, base[i] + TIM12);
-		__raw_writel(0, base[i] + TIM34);
-	}
-
-	/* Init of each timer as a 32-bit timer */
-	for (i=0; i< ARRAY_SIZE(timers); i++) {
-		struct timer_s *t = &timers[i];
-		int timer = ID_TO_TIMER(t->id);
-		u32 irq;
-
-		t->base = base[timer];
-		if (!t->base)
-			continue;
-
-		if (IS_TIMER_BOT(t->id)) {
-			t->enamode_shift = 6;
-			t->tim_off = TIM12;
-			t->prd_off = PRD12;
-			irq = dtip[timer].bottom_irq;
-		} else {
-			t->enamode_shift = 22;
-			t->tim_off = TIM34;
-			t->prd_off = PRD34;
-			irq = dtip[timer].top_irq;
-		}
-
-		/* Register interrupt */
-		t->irqaction.name = t->name;
-		t->irqaction.dev_id = (void *)t;
-
-		if (t->irqaction.handler != NULL) {
-			irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq;
-			setup_irq(irq, &t->irqaction);
-		}
-	}
-}
-
-/*
- * clocksource
- */
-static u64 read_cycles(struct clocksource *cs)
-{
-	struct timer_s *t = &timers[TID_CLOCKSOURCE];
-
-	return (cycles_t)timer32_read(t);
-}
-
-static struct clocksource clocksource_davinci = {
-	.rating		= 300,
-	.read		= read_cycles,
-	.mask		= CLOCKSOURCE_MASK(32),
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
- * Overwrite weak default sched_clock with something more precise
- */
-static u64 notrace davinci_read_sched_clock(void)
-{
-	return timer32_read(&timers[TID_CLOCKSOURCE]);
-}
-
-/*
- * clockevent
- */
-static int davinci_set_next_event(unsigned long cycles,
-				  struct clock_event_device *evt)
-{
-	struct timer_s *t = &timers[TID_CLOCKEVENT];
-
-	t->period = cycles;
-	timer32_config(t);
-	return 0;
-}
-
-static int davinci_shutdown(struct clock_event_device *evt)
-{
-	struct timer_s *t = &timers[TID_CLOCKEVENT];
-
-	t->opts &= ~TIMER_OPTS_STATE_MASK;
-	t->opts |= TIMER_OPTS_DISABLED;
-	return 0;
-}
-
-static int davinci_set_oneshot(struct clock_event_device *evt)
-{
-	struct timer_s *t = &timers[TID_CLOCKEVENT];
-
-	t->opts &= ~TIMER_OPTS_STATE_MASK;
-	t->opts |= TIMER_OPTS_ONESHOT;
-	return 0;
-}
-
-static int davinci_set_periodic(struct clock_event_device *evt)
-{
-	struct timer_s *t = &timers[TID_CLOCKEVENT];
-
-	t->period = davinci_clock_tick_rate / (HZ);
-	t->opts &= ~TIMER_OPTS_STATE_MASK;
-	t->opts |= TIMER_OPTS_PERIODIC;
-	timer32_config(t);
-	return 0;
-}
-
-static struct clock_event_device clockevent_davinci = {
-	.features		= CLOCK_EVT_FEAT_PERIODIC |
-				  CLOCK_EVT_FEAT_ONESHOT,
-	.set_next_event		= davinci_set_next_event,
-	.set_state_shutdown	= davinci_shutdown,
-	.set_state_periodic	= davinci_set_periodic,
-	.set_state_oneshot	= davinci_set_oneshot,
-};
-
-void __init davinci_timer_init(struct clk *timer_clk)
-{
-	struct davinci_soc_info *soc_info = &davinci_soc_info;
-	unsigned int clockevent_id;
-	unsigned int clocksource_id;
-	int i;
-
-	clockevent_id = soc_info->timer_info->clockevent_id;
-	clocksource_id = soc_info->timer_info->clocksource_id;
-
-	timers[TID_CLOCKEVENT].id = clockevent_id;
-	timers[TID_CLOCKSOURCE].id = clocksource_id;
-
-	/*
-	 * If using same timer for both clock events & clocksource,
-	 * a compare register must be used to generate an event interrupt.
-	 * This is equivalent to a oneshot timer only (not periodic).
-	 */
-	if (clockevent_id == clocksource_id) {
-		struct davinci_timer_instance *dtip =
-				soc_info->timer_info->timers;
-		int event_timer = ID_TO_TIMER(clockevent_id);
-
-		/* Only bottom timers can use compare regs */
-		if (IS_TIMER_TOP(clockevent_id))
-			pr_warn("%s: Invalid use of system timers.  Results unpredictable.\n",
-				__func__);
-		else if ((dtip[event_timer].cmp_off == 0)
-				|| (dtip[event_timer].cmp_irq == 0))
-			pr_warn("%s: Invalid timer instance setup.  Results unpredictable.\n",
-				__func__);
-		else {
-			timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
-			clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
-		}
-	}
-
-	BUG_ON(IS_ERR(timer_clk));
-	clk_prepare_enable(timer_clk);
-
-	/* init timer hw */
-	timer_init();
-
-	davinci_clock_tick_rate = clk_get_rate(timer_clk);
-
-	/* setup clocksource */
-	clocksource_davinci.name = id_to_name[clocksource_id];
-	if (clocksource_register_hz(&clocksource_davinci,
-				    davinci_clock_tick_rate))
-		pr_err("%s: can't register clocksource!\n",
-		       clocksource_davinci.name);
-
-	sched_clock_register(davinci_read_sched_clock, 32,
-			  davinci_clock_tick_rate);
-
-	/* setup clockevent */
-	clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id];
-
-	clockevent_davinci.cpumask = cpumask_of(0);
-	clockevents_config_and_register(&clockevent_davinci,
-					davinci_clock_tick_rate, 1, 0xfffffffe);
-
-	for (i=0; i< ARRAY_SIZE(timers); i++)
-		timer32_config(&timers[i]);
-}
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
@ 2019-12-16 17:58   ` David Lechner
  2019-12-17  8:00     ` Bartosz Golaszewski
  2019-12-18  9:28   ` Sekhar Nori
  1 sibling, 1 reply; 9+ messages in thread
From: David Lechner @ 2019-12-16 17:58 UTC (permalink / raw)
  To: Bartosz Golaszewski, Sekhar Nori, Daniel Lezcano,
	Thomas Gleixner, Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

On 12/13/19 10:24 AM, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> The DM365 platform has a strange quirk (only present when using ancient
> u-boot - mainline u-boot v2013.01 and later works fine) where if we
> enable the second half of the timer in periodic mode before we do its
> initialization - the time won't start flowing and we can't boot.
> 
> When using more recent u-boot, we can enable the timer, then reinitialize
> it and all works fine.
> 
> I've been unable to figure out why that is, but a workaround for this
> is straightforward - just cache the enable bits for tim34.


I had a hard time groking this code. See suggested changes below for
something that would make the intention more clear (to me at least).


> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>   drivers/clocksource/timer-davinci.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clocksource/timer-davinci.c b/drivers/clocksource/timer-davinci.c
> index 62745c962049..1c22443acaeb 100644
> --- a/drivers/clocksource/timer-davinci.c
> +++ b/drivers/clocksource/timer-davinci.c
> @@ -64,6 +64,8 @@ static struct {
>   	unsigned int tim_off;
>   } davinci_clocksource;
>   
> +static unsigned int davinci_clocksource_tim32_mode;

static unsigned bool davinci_clocksource_initialized;

> +
>   static struct davinci_clockevent *
>   to_davinci_clockevent(struct clock_event_device *clockevent)
>   {
> @@ -94,7 +96,7 @@ static void davinci_tim12_shutdown(void __iomem *base)
>   	 * halves. In this case TIM34 runs in periodic mode and we must
>   	 * not modify it.
>   	 */
> -	tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
> +	tcr |= davinci_clocksource_tim32_mode <<
>   		DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;

	if (davinci_clocksource_initialized)
		tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
			DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;

>   
>   	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
> @@ -107,7 +109,7 @@ static void davinci_tim12_set_oneshot(void __iomem *base)
>   	tcr = DAVINCI_TIMER_ENAMODE_ONESHOT <<
>   		DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;
>   	/* Same as above. */
> -	tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
> +	tcr |= davinci_clocksource_tim32_mode <<
>   		DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;

	if (davinci_clocksource_initialized)
		tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
			DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;

>   
>   	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
> @@ -206,6 +208,8 @@ static void davinci_clocksource_init_tim34(void __iomem *base)
>   	writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34);
>   	writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34);
>   	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
> +
> +	davinci_clocksource_tim32_mode = DAVINCI_TIMER_ENAMODE_PERIODIC;


	davinci_clocksource_initialized  = true;

>   }
>   
>   /*
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-16 17:58   ` David Lechner
@ 2019-12-17  8:00     ` Bartosz Golaszewski
  2019-12-17 17:01       ` David Lechner
  0 siblings, 1 reply; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-17  8:00 UTC (permalink / raw)
  To: David Lechner
  Cc: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, Kevin Hilman,
	Linux ARM, Linux Kernel Mailing List, Bartosz Golaszewski

pon., 16 gru 2019 o 18:58 David Lechner <david@lechnology.com> napisał(a):
>
> >
> > +static unsigned int davinci_clocksource_tim32_mode;
>
> static unsigned bool davinci_clocksource_initialized;
>
> > +
> >   static struct davinci_clockevent *
> >   to_davinci_clockevent(struct clock_event_device *clockevent)
> >   {
> > @@ -94,7 +96,7 @@ static void davinci_tim12_shutdown(void __iomem *base)
> >        * halves. In this case TIM34 runs in periodic mode and we must
> >        * not modify it.
> >        */
> > -     tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
> > +     tcr |= davinci_clocksource_tim32_mode <<
> >               DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
>
>         if (davinci_clocksource_initialized)
>                 tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
>                         DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;

I thought about doing this initially, but then figured this code would
be called a lot, so why not avoid branching and just store the right
value? Alternatively we can do:

    if (likely(davinci_clocksource_initialized)
        ....

Bart

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-17  8:00     ` Bartosz Golaszewski
@ 2019-12-17 17:01       ` David Lechner
  0 siblings, 0 replies; 9+ messages in thread
From: David Lechner @ 2019-12-17 17:01 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Sekhar Nori, Daniel Lezcano, Thomas Gleixner, Kevin Hilman,
	Linux ARM, Linux Kernel Mailing List, Bartosz Golaszewski

On 12/17/19 2:00 AM, Bartosz Golaszewski wrote:
> pon., 16 gru 2019 o 18:58 David Lechner <david@lechnology.com> napisał(a):
>>
>>>
>>> +static unsigned int davinci_clocksource_tim32_mode;
>>
>> static unsigned bool davinci_clocksource_initialized;
>>
>>> +
>>>    static struct davinci_clockevent *
>>>    to_davinci_clockevent(struct clock_event_device *clockevent)
>>>    {
>>> @@ -94,7 +96,7 @@ static void davinci_tim12_shutdown(void __iomem *base)
>>>         * halves. In this case TIM34 runs in periodic mode and we must
>>>         * not modify it.
>>>         */
>>> -     tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
>>> +     tcr |= davinci_clocksource_tim32_mode <<
>>>                DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
>>
>>          if (davinci_clocksource_initialized)
>>                  tcr |= DAVINCI_TIMER_ENAMODE_PERIODIC <<
>>                          DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
> 
> I thought about doing this initially, but then figured this code would
> be called a lot, so why not avoid branching and just store the right
> value? Alternatively we can do:
> 
>      if (likely(davinci_clocksource_initialized)
>          ....
> 

Unless there is a measurable performance difference, I think it
would be better with if/likely.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
  2019-12-16 17:58   ` David Lechner
@ 2019-12-18  9:28   ` Sekhar Nori
  2019-12-19  8:59     ` Bartosz Golaszewski
  1 sibling, 1 reply; 9+ messages in thread
From: Sekhar Nori @ 2019-12-18  9:28 UTC (permalink / raw)
  To: Bartosz Golaszewski, Daniel Lezcano, Thomas Gleixner,
	David Lechner, Kevin Hilman
  Cc: linux-arm-kernel, linux-kernel, Bartosz Golaszewski

Hi Bart,

On 13/12/19 9:54 PM, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> The DM365 platform has a strange quirk (only present when using ancient
> u-boot - mainline u-boot v2013.01 and later works fine) where if we
> enable the second half of the timer in periodic mode before we do its
> initialization - the time won't start flowing and we can't boot.
> 
> When using more recent u-boot, we can enable the timer, then reinitialize
> it and all works fine.
> 
> I've been unable to figure out why that is, but a workaround for this
> is straightforward - just cache the enable bits for tim34.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Timer Global Control Register (TGCR) has bits to reset both halves of
timer. Does placing both halves in reset, waiting a bit (say 10ms) and
then taking them out of reset help solve the this problem?

Also, there are LPSCs controlling the timers. As an experiment, can you
see if using LPSC_STATE_SWRSTDISABLE instead of LPSC_STATE_DISABLE in
davinci_lpsc_clk_disable() and then doing a clk_disable() + clk_enable()
on timer can get the timer out of this bad state.

We need some way for Linux to start on a clean state after bootloader is
done. And trying to reset the timer before use seems to be a better way
to accomplish it.

I assume the original code was just lucky in not hitting this case?

Thanks,
Sekhar

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC
  2019-12-18  9:28   ` Sekhar Nori
@ 2019-12-19  8:59     ` Bartosz Golaszewski
  0 siblings, 0 replies; 9+ messages in thread
From: Bartosz Golaszewski @ 2019-12-19  8:59 UTC (permalink / raw)
  To: Sekhar Nori
  Cc: Daniel Lezcano, Thomas Gleixner, David Lechner, Kevin Hilman,
	Linux ARM, Linux Kernel Mailing List, Bartosz Golaszewski

śr., 18 gru 2019 o 10:28 Sekhar Nori <nsekhar@ti.com> napisał(a):
>
> Hi Bart,
>
> On 13/12/19 9:54 PM, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > The DM365 platform has a strange quirk (only present when using ancient
> > u-boot - mainline u-boot v2013.01 and later works fine) where if we
> > enable the second half of the timer in periodic mode before we do its
> > initialization - the time won't start flowing and we can't boot.
> >
> > When using more recent u-boot, we can enable the timer, then reinitialize
> > it and all works fine.
> >
> > I've been unable to figure out why that is, but a workaround for this
> > is straightforward - just cache the enable bits for tim34.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Timer Global Control Register (TGCR) has bits to reset both halves of
> timer. Does placing both halves in reset, waiting a bit (say 10ms) and
> then taking them out of reset help solve the this problem?
>

No, it doesn't change anything. On u-boot present on my dm365-evm,
tim34 is not in reset when we get to linux, while tim12 is in reset,
but putting tim34 in reset in linux doesn't seem to change anything.

> Also, there are LPSCs controlling the timers. As an experiment, can you
> see if using LPSC_STATE_SWRSTDISABLE instead of LPSC_STATE_DISABLE in
> davinci_lpsc_clk_disable() and then doing a clk_disable() + clk_enable()
> on timer can get the timer out of this bad state.

I tried several combinations of this e.g. normal prepare_enable ->
disable -> enable, disable -> enable, disable -> delay -> enable etc.
and neither worked.

>
> We need some way for Linux to start on a clean state after bootloader is
> done. And trying to reset the timer before use seems to be a better way
> to accomplish it.
>
> I assume the original code was just lucky in not hitting this case?
>

I guess so. It used to re-read the registers instead of assuming
certain values. When I did it too, there was no problem, it's only
when we dropped re-reading that this must have appeared.

Bart

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-12-19  9:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-13 16:24 [PATCH 0/3] ARM: davinci: convert dm365 to using the new clocksource driver Bartosz Golaszewski
2019-12-13 16:24 ` [PATCH 1/3] clocksource: davinci: work around a clocksource problem on dm365 SoC Bartosz Golaszewski
2019-12-16 17:58   ` David Lechner
2019-12-17  8:00     ` Bartosz Golaszewski
2019-12-17 17:01       ` David Lechner
2019-12-18  9:28   ` Sekhar Nori
2019-12-19  8:59     ` Bartosz Golaszewski
2019-12-13 16:24 ` [PATCH 2/3] ARM: davinci: dm365: switch to using the clocksource driver Bartosz Golaszewski
2019-12-13 16:24 ` [PATCH 3/3] ARM: davinci: remove legacy timer support Bartosz Golaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).