Skip to contentSkip to conversation

ARM: imx: move timer driver into drivers/clocksource

PATCH New shawnguo at kernel.org 4 participants 19 messages May 15, 2015 – May 19, 2015

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover ARM: imx: move timer driver into drivers/clocksource

From: Shawn Guo <[email protected]>

The series cleans up i.MX timer driver regarding those cpu_is_xxx() usage by introducing gpt device type, and then moves the driver into drivers/clocksource.

Shawn Guo (9):
ARM: imx: move timer resources into a structure
ARM: imx: define an enum for gpt timer device type
ARM: imx: initialize gpt device type for DT boot
ARM: imx: setup tctl register in device specific function
ARM: imx: set up set_next_event hook in imx_timer_data_init()
ARM: imx: define gpt register offset per device type
ARM: imx: provide gpt device specific irq functions
ARM: imx: remove platform headers from timer driver
ARM: imx: move timer driver into drivers/clocksource

 arch/arm/mach-imx/Makefile      |   2 +-
 arch/arm/mach-imx/time.c        | 388 -------------------------------
 drivers/clk/imx/clk-imx1.c      |   3 +-
 drivers/clk/imx/clk-imx21.c     |   3 +-
 drivers/clk/imx/clk-imx27.c     |   3 +-
 drivers/clk/imx/clk-imx31.c     |   3 +-
 drivers/clk/imx/clk-imx35.c     |   3 +-
 drivers/clk/imx/clk.h           |   7 -
 drivers/clocksource/Makefile    |   1 +
 drivers/clocksource/timer-imx.c | 493 ++++++++++++++++++++++++++++++++++++++++
 include/soc/imx/timer.h         |  26 +++
 11 files changed, 531 insertions(+), 401 deletions(-)
 delete mode 100644 arch/arm/mach-imx/time.c
 create mode 100644 drivers/clocksource/timer-imx.c
 create mode 100644 include/soc/imx/timer.h
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/9 ARM: imx: move timer resources into a structure

From: Shawn Guo <[email protected]>

Instead of passing around as argument, let's move timer resources like irq and clocks together with base address into a data structure, and reference the resources from the struct variable directly to simplify the function call interface.

---
 arch/arm/mach-imx/time.c | 119 ++++++++++++++++++++++++-----------------------
 1 file changed, 61 insertions(+), 58 deletions(-)
arch/arm/mach-imx/time.c +61 -58
index ab5ee1c445f3..8ad7cb2a7f08 100644
@@ -84,27 +84,34 @@
 static struct clock_event_device clockevent_mxc;
 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
-static void __iomem *timer_base;
+struct imx_timer {
+	void __iomem *base;
+	int irq;
+	struct clk *clk_per;
+	struct clk *clk_ipg;
+};
+
+static struct imx_timer imxtm;
 
 static inline void gpt_irq_disable(void)
 {
 	unsigned int tmp;
 
 	if (timer_is_v2())
-		__raw_writel(0, timer_base + V2_IR);
+		__raw_writel(0, imxtm.base + V2_IR);
 	else {
-		tmp = __raw_readl(timer_base + MXC_TCTL);
-		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
+		tmp = __raw_readl(imxtm.base + MXC_TCTL);
+		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, imxtm.base + MXC_TCTL);
 	}
 }
 
 static inline void gpt_irq_enable(void)
 {
 	if (timer_is_v2())
-		__raw_writel(1<<0, timer_base + V2_IR);
+		__raw_writel(1<<0, imxtm.base + V2_IR);
 	else {
-		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
-			timer_base + MXC_TCTL);
+		__raw_writel(__raw_readl(imxtm.base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+			imxtm.base + MXC_TCTL);
 	}
 }
 
@@ -112,12 +119,12 @@ static void gpt_irq_acknowledge(void)
 {
 	if (timer_is_v1()) {
 		if (cpu_is_mx1())
-			__raw_writel(0, timer_base + MX1_2_TSTAT);
+			__raw_writel(0, imxtm.base + MX1_2_TSTAT);
 		else
 			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
-				timer_base + MX1_2_TSTAT);
+				imxtm.base + MX1_2_TSTAT);
 	} else if (timer_is_v2())
-		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
+		__raw_writel(V2_TSTAT_OF1, imxtm.base + V2_TSTAT);
 }
 
 static void __iomem *sched_clock_reg;
@@ -134,10 +141,10 @@ static unsigned long imx_read_current_timer(void)
 	return __raw_readl(sched_clock_reg);
 }
 
-static int __init mxc_clocksource_init(struct clk *timer_clk)
+static int __init mxc_clocksource_init(void)
 {
-	unsigned int c = clk_get_rate(timer_clk);
-	void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
+	unsigned int c = clk_get_rate(imxtm.clk_per);
+	void __iomem *reg = imxtm.base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
 
 	imx_delay_timer.read_current_timer = &imx_read_current_timer;
 	imx_delay_timer.freq = c;
@@ -157,11 +164,11 @@ static int mx1_2_set_next_event(unsigned long evt,
 {
 	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + MX1_2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
+	__raw_writel(tcmp, imxtm.base + MX1_2_TCMP);
 
-	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
+	return (int)(tcmp - __raw_readl(imxtm.base + MX1_2_TCN)) < 0 ?
 				-ETIME : 0;
 }
 
@@ -170,12 +177,12 @@ static int v2_set_next_event(unsigned long evt,
 {
 	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + V2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + V2_TCMP);
+	__raw_writel(tcmp, imxtm.base + V2_TCMP);
 
 	return evt < 0x7fffffff &&
-		(int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
+		(int)(tcmp - __raw_readl(imxtm.base + V2_TCN)) < 0 ?
 				-ETIME : 0;
 }
 
@@ -206,11 +213,11 @@ static void mxc_set_mode(enum clock_event_mode mode,
 	if (mode != clockevent_mode) {
 		/* Set event time into far-far future */
 		if (timer_is_v2())
-			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
-					timer_base + V2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + V2_TCN) - 3,
+					imxtm.base + V2_TCMP);
 		else
-			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
-					timer_base + MX1_2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + MX1_2_TCN) - 3,
+					imxtm.base + MX1_2_TCMP);
 
 		/* Clear pending interrupt */
 		gpt_irq_acknowledge();
@@ -259,9 +266,9 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
 	uint32_t tstat;
 
 	if (timer_is_v2())
-		tstat = __raw_readl(timer_base + V2_TSTAT);
+		tstat = __raw_readl(imxtm.base + V2_TSTAT);
 	else
-		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
+		tstat = __raw_readl(imxtm.base + MX1_2_TSTAT);
 
 	gpt_irq_acknowledge();
 
@@ -284,49 +291,48 @@ static struct clock_event_device clockevent_mxc = {
 	.rating		= 200,
 };
 
-static int __init mxc_clockevent_init(struct clk *timer_clk)
+static int __init mxc_clockevent_init(void)
 {
 	if (timer_is_v2())
 		clockevent_mxc.set_next_event = v2_set_next_event;
 
 	clockevent_mxc.cpumask = cpumask_of(0);
 	clockevents_config_and_register(&clockevent_mxc,
-					clk_get_rate(timer_clk),
+					clk_get_rate(imxtm.clk_per),
 					0xff, 0xfffffffe);
 
 	return 0;
 }
 
-static void __init _mxc_timer_init(int irq,
-				   struct clk *clk_per, struct clk *clk_ipg)
+static void __init _mxc_timer_init(void)
 {
 	uint32_t tctl_val;
 
-	if (IS_ERR(clk_per)) {
+	if (IS_ERR(imxtm.clk_per)) {
 		pr_err("i.MX timer: unable to get clk\n");
 		return;
 	}
 
-	if (!IS_ERR(clk_ipg))
-		clk_prepare_enable(clk_ipg);
+	if (!IS_ERR(imxtm.clk_ipg))
+		clk_prepare_enable(imxtm.clk_ipg);
 
-	clk_prepare_enable(clk_per);
+	clk_prepare_enable(imxtm.clk_per);
 
 	/*
 	 * Initialise to a known state (all timers off, and timing reset)
 	 */
 
-	__raw_writel(0, timer_base + MXC_TCTL);
-	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
+	__raw_writel(0, imxtm.base + MXC_TCTL);
+	__raw_writel(0, imxtm.base + MXC_TPRER); /* see datasheet note */
 
 	if (timer_is_v2()) {
 		tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
-		if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+		if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8) {
 			tctl_val |= V2_TCTL_CLK_OSC_DIV8;
 			if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
 				/* 24 / 8 = 3 MHz */
 				__raw_writel(7 << V2_TPRER_PRE24M,
-					timer_base + MXC_TPRER);
+					imxtm.base + MXC_TPRER);
 				tctl_val |= V2_TCTL_24MEN;
 			}
 		} else {
@@ -336,47 +342,44 @@ static void __init _mxc_timer_init(int irq,
 		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
 	}
 
-	__raw_writel(tctl_val, timer_base + MXC_TCTL);
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
 
 	/* init and register the timer to the framework */
-	mxc_clocksource_init(clk_per);
-	mxc_clockevent_init(clk_per);
+	mxc_clocksource_init();
+	mxc_clockevent_init();
 
 	/* Make irqs happen */
-	setup_irq(irq, &mxc_timer_irq);
+	setup_irq(imxtm.irq, &mxc_timer_irq);
 }
 
 void __init mxc_timer_init(unsigned long pbase, int irq)
 {
-	struct clk *clk_per = clk_get_sys("imx-gpt.0", "per");
-	struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
+	imxtm.clk_per = clk_get_sys("imx-gpt.0", "per");
+	imxtm.clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
 
-	timer_base = ioremap(pbase, SZ_4K);
-	BUG_ON(!timer_base);
+	imxtm.base = ioremap(pbase, SZ_4K);
+	BUG_ON(!imxtm.base);
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
 }
 
 static void __init mxc_timer_init_dt(struct device_node *np)
 {
-	struct clk *clk_per, *clk_ipg;
-	int irq;
-
-	if (timer_base)
+	if (imxtm.base)
 		return;
 
-	timer_base = of_iomap(np, 0);
-	WARN_ON(!timer_base);
-	irq = irq_of_parse_and_map(np, 0);
+	imxtm.base = of_iomap(np, 0);
+	WARN_ON(!imxtm.base);
+	imxtm.irq = irq_of_parse_and_map(np, 0);
 
-	clk_ipg = of_clk_get_by_name(np, "ipg");
+	imxtm.clk_ipg = of_clk_get_by_name(np, "ipg");
 
 	/* Try osc_per first, and fall back to per otherwise */
-	clk_per = of_clk_get_by_name(np, "osc_per");
-	if (IS_ERR(clk_per))
-		clk_per = of_clk_get_by_name(np, "per");
+	imxtm.clk_per = of_clk_get_by_name(np, "osc_per");
+	if (IS_ERR(imxtm.clk_per))
+		imxtm.clk_per = of_clk_get_by_name(np, "per");
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
 }
 CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
Signature · 1 line
1.9.1
#2 lore raw

PATCH 1/9 ARM: imx: move timer resources into a structure

Quoted 28 lines

-----Original Message-----
From: shawnguo at kernel.org [mailto:shawnguo at kernel.org]
Sent: 2015?5?15? 3:12
To: linux-arm-kernel at lists.infradead.org
Cc: kernel at pengutronix.de; Daniel Lezcano; Wang Shenwei-B38339; Shawn Guo
Subject: [PATCH 1/9] ARM: imx: move timer resources into a structure

From: Shawn Guo <[email protected]>

Instead of passing around as argument, let's move timer resources like irq and clocks together with base address into a data structure, and reference the resources from the struct variable directly to simplify the function call interface.

---
 arch/arm/mach-imx/time.c | 119 ++++++++++++++++++++++++-----------------------
 1 file changed, 61 insertions(+), 58 deletions(-)
arch/arm/mach-imx/time.c index renamed from arch/arm/mach-imx/time.c +0 -0

ab5ee1c445f3..8ad7cb2a7f08 100644

arch/arm/mach-imx/time.c +0 -0
@@ -84,27 +84,34 @@
 static struct clock_event_device clockevent_mxc;  static enum
 clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 

arch/arm/mach-imx/time.c line 95

Quoted 10 lines
arch/arm/mach-imx/time.c +8 -1
-static void __iomem *timer_base;
+struct imx_timer {
+	void __iomem *base;
+	int irq;
+	struct clk *clk_per;
+	struct clk *clk_ipg;
+};
+
+static struct imx_timer imxtm;
 

Since the changes still used a global variable to hold the information, it doesn't take advantage of what the clocksource framework provides, and make the driver unable to support multi-instances.

Regards,
Shenwei

Quoted 245 lines
arch/arm/mach-imx/time.c +22 -22
 static inline void gpt_irq_disable(void)  {
 	unsigned int tmp;
 
 	if (timer_is_v2())
-		__raw_writel(0, timer_base + V2_IR);
+		__raw_writel(0, imxtm.base + V2_IR);
 	else {
-		tmp = __raw_readl(timer_base + MXC_TCTL);
-		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
+		tmp = __raw_readl(imxtm.base + MXC_TCTL);
+		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, imxtm.base + MXC_TCTL);
 	}
 }
 
 static inline void gpt_irq_enable(void)  {
 	if (timer_is_v2())
-		__raw_writel(1<<0, timer_base + V2_IR);
+		__raw_writel(1<<0, imxtm.base + V2_IR);
 	else {
-		__raw_writel(__raw_readl(timer_base + MXC_TCTL) |
 MX1_2_TCTL_IRQEN,
-			timer_base + MXC_TCTL);
+		__raw_writel(__raw_readl(imxtm.base + MXC_TCTL) |
 MX1_2_TCTL_IRQEN,
+			imxtm.base + MXC_TCTL);
 	}
 }
 
@@ -112,12 +119,12 @@ static void gpt_irq_acknowledge(void)  {
 	if (timer_is_v1()) {
 		if (cpu_is_mx1())
-			__raw_writel(0, timer_base + MX1_2_TSTAT);
+			__raw_writel(0, imxtm.base + MX1_2_TSTAT);
 		else
 			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
-				timer_base + MX1_2_TSTAT);
+				imxtm.base + MX1_2_TSTAT);
 	} else if (timer_is_v2())
-		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
+		__raw_writel(V2_TSTAT_OF1, imxtm.base + V2_TSTAT);
 }
 
 static void __iomem *sched_clock_reg;
@@ -134,10 +141,10 @@ static unsigned long imx_read_current_timer(void)
 	return __raw_readl(sched_clock_reg);
 }
 
-static int __init mxc_clocksource_init(struct clk *timer_clk)
+static int __init mxc_clocksource_init(void)
 {
-	unsigned int c = clk_get_rate(timer_clk);
-	void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
+	unsigned int c = clk_get_rate(imxtm.clk_per);
+	void __iomem *reg = imxtm.base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
 
 	imx_delay_timer.read_current_timer = &imx_read_current_timer;
 	imx_delay_timer.freq = c;
@@ -157,11 +164,11 @@ static int mx1_2_set_next_event(unsigned long evt,
 {
 	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + MX1_2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
+	__raw_writel(tcmp, imxtm.base + MX1_2_TCMP);
 
-	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
+	return (int)(tcmp - __raw_readl(imxtm.base + MX1_2_TCN)) < 0 ?
 				-ETIME : 0;
 }
 
@@ -170,12 +177,12 @@ static int v2_set_next_event(unsigned long evt,  {
 	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + V2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + V2_TCMP);
+	__raw_writel(tcmp, imxtm.base + V2_TCMP);
 
 	return evt < 0x7fffffff &&
-		(int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
+		(int)(tcmp - __raw_readl(imxtm.base + V2_TCN)) < 0 ?
 				-ETIME : 0;
 }
 
@@ -206,11 +213,11 @@ static void mxc_set_mode(enum clock_event_mode
 mode,
 	if (mode != clockevent_mode) {
 		/* Set event time into far-far future */
 		if (timer_is_v2())
-			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
-					timer_base + V2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + V2_TCN) - 3,
+					imxtm.base + V2_TCMP);
 		else
-			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
-					timer_base + MX1_2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + MX1_2_TCN) - 3,
+					imxtm.base + MX1_2_TCMP);
 
 		/* Clear pending interrupt */
arch/arm/mach-imx/time.c +31 -36
 		gpt_irq_acknowledge();
@@ -259,9 +266,9 @@ static irqreturn_t mxc_timer_interrupt(int irq, void
 *dev_id)
 	uint32_t tstat;
 
 	if (timer_is_v2())
-		tstat = __raw_readl(timer_base + V2_TSTAT);
+		tstat = __raw_readl(imxtm.base + V2_TSTAT);
 	else
-		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
+		tstat = __raw_readl(imxtm.base + MX1_2_TSTAT);
 
 	gpt_irq_acknowledge();
@@ -284,49 +291,48 @@ static struct clock_event_device clockevent_mxc = {
 	.rating		= 200,
 };
 
-static int __init mxc_clockevent_init(struct clk *timer_clk)
+static int __init mxc_clockevent_init(void)
 {
 	if (timer_is_v2())
 		clockevent_mxc.set_next_event = v2_set_next_event;
 
 	clockevent_mxc.cpumask = cpumask_of(0);
 	clockevents_config_and_register(&clockevent_mxc,
-					clk_get_rate(timer_clk),
+					clk_get_rate(imxtm.clk_per),
 					0xff, 0xfffffffe);
 
 	return 0;
 }
 
-static void __init _mxc_timer_init(int irq,
-				   struct clk *clk_per, struct clk *clk_ipg)
+static void __init _mxc_timer_init(void)
 {
 	uint32_t tctl_val;
 
-	if (IS_ERR(clk_per)) {
+	if (IS_ERR(imxtm.clk_per)) {
 		pr_err("i.MX timer: unable to get clk\n");
 		return;
 	}
 
-	if (!IS_ERR(clk_ipg))
-		clk_prepare_enable(clk_ipg);
+	if (!IS_ERR(imxtm.clk_ipg))
+		clk_prepare_enable(imxtm.clk_ipg);
 
-	clk_prepare_enable(clk_per);
+	clk_prepare_enable(imxtm.clk_per);
 
 	/*
 	 * Initialise to a known state (all timers off, and timing reset)
 	 */
 
-	__raw_writel(0, timer_base + MXC_TCTL);
-	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
+	__raw_writel(0, imxtm.base + MXC_TCTL);
+	__raw_writel(0, imxtm.base + MXC_TPRER); /* see datasheet note */
 
 	if (timer_is_v2()) {
 		tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
-		if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+		if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8) {
 			tctl_val |= V2_TCTL_CLK_OSC_DIV8;
 			if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
 				/* 24 / 8 = 3 MHz */
 				__raw_writel(7 << V2_TPRER_PRE24M,
-					timer_base + MXC_TPRER);
+					imxtm.base + MXC_TPRER);
 				tctl_val |= V2_TCTL_24MEN;
 			}
 		} else {
@@ -336,47 +342,44 @@ static void __init _mxc_timer_init(int irq,
 		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 |
 MXC_TCTL_TEN;
 	}
 
-	__raw_writel(tctl_val, timer_base + MXC_TCTL);
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
 
 	/* init and register the timer to the framework */
-	mxc_clocksource_init(clk_per);
-	mxc_clockevent_init(clk_per);
+	mxc_clocksource_init();
+	mxc_clockevent_init();
 
 	/* Make irqs happen */
-	setup_irq(irq, &mxc_timer_irq);
+	setup_irq(imxtm.irq, &mxc_timer_irq);
 }
 
 void __init mxc_timer_init(unsigned long pbase, int irq)  {
-	struct clk *clk_per = clk_get_sys("imx-gpt.0", "per");
-	struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
+	imxtm.clk_per = clk_get_sys("imx-gpt.0", "per");
+	imxtm.clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
 
-	timer_base = ioremap(pbase, SZ_4K);
-	BUG_ON(!timer_base);
+	imxtm.base = ioremap(pbase, SZ_4K);
+	BUG_ON(!imxtm.base);
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
 }
 
 static void __init mxc_timer_init_dt(struct device_node *np)  {
-	struct clk *clk_per, *clk_ipg;
-	int irq;
-
-	if (timer_base)
+	if (imxtm.base)
 		return;
 
-	timer_base = of_iomap(np, 0);
-	WARN_ON(!timer_base);
-	irq = irq_of_parse_and_map(np, 0);
+	imxtm.base = of_iomap(np, 0);
+	WARN_ON(!imxtm.base);
+	imxtm.irq = irq_of_parse_and_map(np, 0);
 
-	clk_ipg = of_clk_get_by_name(np, "ipg");
+	imxtm.clk_ipg = of_clk_get_by_name(np, "ipg");
 
 	/* Try osc_per first, and fall back to per otherwise */
-	clk_per = of_clk_get_by_name(np, "osc_per");
-	if (IS_ERR(clk_per))
-		clk_per = of_clk_get_by_name(np, "per");
+	imxtm.clk_per = of_clk_get_by_name(np, "osc_per");
+	if (IS_ERR(imxtm.clk_per))
+		imxtm.clk_per = of_clk_get_by_name(np, "per");
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
 }
 CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
--

1.9.1

author
#3 lore raw

PATCH 1/9 ARM: imx: move timer resources into a structure

Quoted 28 lines · Shenwei Wang
Quoted 28 lines

-----Original Message-----
From: shawnguo at kernel.org [mailto:shawnguo at kernel.org]
Sent: 2015?5?15? 3:12
To: linux-arm-kernel at lists.infradead.org
Cc: kernel at pengutronix.de; Daniel Lezcano; Wang Shenwei-B38339; Shawn Guo
Subject: [PATCH 1/9] ARM: imx: move timer resources into a structure

From: Shawn Guo <[email protected]>

Instead of passing around as argument, let's move timer resources like irq and clocks together with base address into a data structure, and reference the resources from the struct variable directly to simplify the function call interface.

---
 arch/arm/mach-imx/time.c | 119 ++++++++++++++++++++++++-----------------------
 1 file changed, 61 insertions(+), 58 deletions(-)
arch/arm/mach-imx/time.c index renamed from arch/arm/mach-imx/time.c +0 -0

ab5ee1c445f3..8ad7cb2a7f08 100644

arch/arm/mach-imx/time.c +0 -0
@@ -84,27 +84,34 @@
 static struct clock_event_device clockevent_mxc;  static enum
 clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
Quoted 12 lines

arch/arm/mach-imx/time.c line 95

Quoted 10 lines
arch/arm/mach-imx/time.c +8 -1
-static void __iomem *timer_base;
+struct imx_timer {
+	void __iomem *base;
+	int irq;
+	struct clk *clk_per;
+	struct clk *clk_ipg;
+};
+
+static struct imx_timer imxtm;
 

Since the changes still used a global variable to hold the information, it doesn't take advantage of what the clocksource framework provides, and make the driver unable to support multi-instances.

The goal of the series is to clean up cpu_is_xxx usages, and move the driver into drivers/clocksource. The multi-instances can be supported later when we see a need for that.

Shawn

#4 lore raw

PATCH 1/9 ARM: imx: move timer resources into a structure

In reply to shawnguo at kernel.org
Quoted 8 lines · shawnguo at kernel.org

From: Shawn Guo <[email protected]>

Instead of passing around as argument, let's move timer resources like irq and clocks together with base address into a data structure, and reference the resources from the struct variable directly to simplify the function call interface.

I would be nice to embed the clockevent_mxc variable in the structure as well and use container_of to retrieve the structure from the struct clockevent.

The struct clockevent can be the unified parameter across the different functions.

Refer to drivers/clocksource/rockchip_timer.c as an example.

Quoted 267 lines
---
  arch/arm/mach-imx/time.c | 119 ++++++++++++++++++++++++-----------------------
  1 file changed, 61 insertions(+), 58 deletions(-)
arch/arm/mach-imx/time.c +61 -58
index ab5ee1c445f3..8ad7cb2a7f08 100644
@@ -84,27 +84,34 @@
  static struct clock_event_device clockevent_mxc;
  static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
-static void __iomem *timer_base;
+struct imx_timer {
+	void __iomem *base;
+	int irq;
+	struct clk *clk_per;
+	struct clk *clk_ipg;
+};
+
+static struct imx_timer imxtm;
 
  static inline void gpt_irq_disable(void)
  {
  	unsigned int tmp;
 
  	if (timer_is_v2())
-		__raw_writel(0, timer_base + V2_IR);
+		__raw_writel(0, imxtm.base + V2_IR);
  	else {
-		tmp = __raw_readl(timer_base + MXC_TCTL);
-		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
+		tmp = __raw_readl(imxtm.base + MXC_TCTL);
+		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, imxtm.base + MXC_TCTL);
  	}
  }
 
  static inline void gpt_irq_enable(void)
  {
  	if (timer_is_v2())
-		__raw_writel(1<<0, timer_base + V2_IR);
+		__raw_writel(1<<0, imxtm.base + V2_IR);
  	else {
-		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
-			timer_base + MXC_TCTL);
+		__raw_writel(__raw_readl(imxtm.base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+			imxtm.base + MXC_TCTL);
  	}
  }
 
@@ -112,12 +119,12 @@ static void gpt_irq_acknowledge(void)
  {
  	if (timer_is_v1()) {
  		if (cpu_is_mx1())
-			__raw_writel(0, timer_base + MX1_2_TSTAT);
+			__raw_writel(0, imxtm.base + MX1_2_TSTAT);
  		else
  			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
-				timer_base + MX1_2_TSTAT);
+				imxtm.base + MX1_2_TSTAT);
  	} else if (timer_is_v2())
-		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
+		__raw_writel(V2_TSTAT_OF1, imxtm.base + V2_TSTAT);
  }
 
  static void __iomem *sched_clock_reg;
@@ -134,10 +141,10 @@ static unsigned long imx_read_current_timer(void)
  	return __raw_readl(sched_clock_reg);
  }
 
-static int __init mxc_clocksource_init(struct clk *timer_clk)
+static int __init mxc_clocksource_init(void)
  {
-	unsigned int c = clk_get_rate(timer_clk);
-	void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
+	unsigned int c = clk_get_rate(imxtm.clk_per);
+	void __iomem *reg = imxtm.base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
 
  	imx_delay_timer.read_current_timer = &imx_read_current_timer;
  	imx_delay_timer.freq = c;
@@ -157,11 +164,11 @@ static int mx1_2_set_next_event(unsigned long evt,
  {
  	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + MX1_2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
+	__raw_writel(tcmp, imxtm.base + MX1_2_TCMP);
 
-	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
+	return (int)(tcmp - __raw_readl(imxtm.base + MX1_2_TCN)) < 0 ?
  				-ETIME : 0;
  }
 
@@ -170,12 +177,12 @@ static int v2_set_next_event(unsigned long evt,
  {
  	unsigned long tcmp;
 
-	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
+	tcmp = __raw_readl(imxtm.base + V2_TCN) + evt;
 
-	__raw_writel(tcmp, timer_base + V2_TCMP);
+	__raw_writel(tcmp, imxtm.base + V2_TCMP);
 
  	return evt < 0x7fffffff &&
-		(int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
+		(int)(tcmp - __raw_readl(imxtm.base + V2_TCN)) < 0 ?
  				-ETIME : 0;
  }
 
@@ -206,11 +213,11 @@ static void mxc_set_mode(enum clock_event_mode mode,
  	if (mode != clockevent_mode) {
  		/* Set event time into far-far future */
  		if (timer_is_v2())
-			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
-					timer_base + V2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + V2_TCN) - 3,
+					imxtm.base + V2_TCMP);
  		else
-			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
-					timer_base + MX1_2_TCMP);
+			__raw_writel(__raw_readl(imxtm.base + MX1_2_TCN) - 3,
+					imxtm.base + MX1_2_TCMP);
 
  		/* Clear pending interrupt */
  		gpt_irq_acknowledge();
@@ -259,9 +266,9 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
  	uint32_t tstat;
 
  	if (timer_is_v2())
-		tstat = __raw_readl(timer_base + V2_TSTAT);
+		tstat = __raw_readl(imxtm.base + V2_TSTAT);
  	else
-		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
+		tstat = __raw_readl(imxtm.base + MX1_2_TSTAT);
 
  	gpt_irq_acknowledge();
 
@@ -284,49 +291,48 @@ static struct clock_event_device clockevent_mxc = {
  	.rating		= 200,
  };
 
-static int __init mxc_clockevent_init(struct clk *timer_clk)
+static int __init mxc_clockevent_init(void)
  {
  	if (timer_is_v2())
  		clockevent_mxc.set_next_event = v2_set_next_event;
 
  	clockevent_mxc.cpumask = cpumask_of(0);
  	clockevents_config_and_register(&clockevent_mxc,
-					clk_get_rate(timer_clk),
+					clk_get_rate(imxtm.clk_per),
  					0xff, 0xfffffffe);
 
  	return 0;
  }
 
-static void __init _mxc_timer_init(int irq,
-				   struct clk *clk_per, struct clk *clk_ipg)
+static void __init _mxc_timer_init(void)
  {
  	uint32_t tctl_val;
 
-	if (IS_ERR(clk_per)) {
+	if (IS_ERR(imxtm.clk_per)) {
  		pr_err("i.MX timer: unable to get clk\n");
  		return;
  	}
 
-	if (!IS_ERR(clk_ipg))
-		clk_prepare_enable(clk_ipg);
+	if (!IS_ERR(imxtm.clk_ipg))
+		clk_prepare_enable(imxtm.clk_ipg);
 
-	clk_prepare_enable(clk_per);
+	clk_prepare_enable(imxtm.clk_per);
 
  	/*
  	 * Initialise to a known state (all timers off, and timing reset)
  	 */
 
-	__raw_writel(0, timer_base + MXC_TCTL);
-	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
+	__raw_writel(0, imxtm.base + MXC_TCTL);
+	__raw_writel(0, imxtm.base + MXC_TPRER); /* see datasheet note */
 
  	if (timer_is_v2()) {
  		tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
-		if (clk_get_rate(clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+		if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8) {
  			tctl_val |= V2_TCTL_CLK_OSC_DIV8;
  			if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
  				/* 24 / 8 = 3 MHz */
  				__raw_writel(7 << V2_TPRER_PRE24M,
-					timer_base + MXC_TPRER);
+					imxtm.base + MXC_TPRER);
  				tctl_val |= V2_TCTL_24MEN;
  			}
  		} else {
@@ -336,47 +342,44 @@ static void __init _mxc_timer_init(int irq,
  		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
  	}
 
-	__raw_writel(tctl_val, timer_base + MXC_TCTL);
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
 
  	/* init and register the timer to the framework */
-	mxc_clocksource_init(clk_per);
-	mxc_clockevent_init(clk_per);
+	mxc_clocksource_init();
+	mxc_clockevent_init();
 
  	/* Make irqs happen */
-	setup_irq(irq, &mxc_timer_irq);
+	setup_irq(imxtm.irq, &mxc_timer_irq);
  }
 
  void __init mxc_timer_init(unsigned long pbase, int irq)
  {
-	struct clk *clk_per = clk_get_sys("imx-gpt.0", "per");
-	struct clk *clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
+	imxtm.clk_per = clk_get_sys("imx-gpt.0", "per");
+	imxtm.clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
 
-	timer_base = ioremap(pbase, SZ_4K);
-	BUG_ON(!timer_base);
+	imxtm.base = ioremap(pbase, SZ_4K);
+	BUG_ON(!imxtm.base);
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
  }
 
  static void __init mxc_timer_init_dt(struct device_node *np)
  {
-	struct clk *clk_per, *clk_ipg;
-	int irq;
-
-	if (timer_base)
+	if (imxtm.base)
  		return;
 
-	timer_base = of_iomap(np, 0);
-	WARN_ON(!timer_base);
-	irq = irq_of_parse_and_map(np, 0);
+	imxtm.base = of_iomap(np, 0);
+	WARN_ON(!imxtm.base);
+	imxtm.irq = irq_of_parse_and_map(np, 0);
 
-	clk_ipg = of_clk_get_by_name(np, "ipg");
+	imxtm.clk_ipg = of_clk_get_by_name(np, "ipg");
 
  	/* Try osc_per first, and fall back to per otherwise */
-	clk_per = of_clk_get_by_name(np, "osc_per");
-	if (IS_ERR(clk_per))
-		clk_per = of_clk_get_by_name(np, "per");
+	imxtm.clk_per = of_clk_get_by_name(np, "osc_per");
+	if (IS_ERR(imxtm.clk_per))
+		imxtm.clk_per = of_clk_get_by_name(np, "per");
 
-	_mxc_timer_init(irq, clk_per, clk_ipg);
+	_mxc_timer_init();
  }
  CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
  CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
Signature · 5 lines
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
author
#5 lore raw

PATCH 1/9 ARM: imx: move timer resources into a structure

Quoted 10 lines · Daniel Lezcano
Quoted 8 lines · shawnguo at kernel.org

From: Shawn Guo <[email protected]>

Instead of passing around as argument, let's move timer resources like irq and clocks together with base address into a data structure, and reference the resources from the struct variable directly to simplify the function call interface.

Quoted 8 lines

I would be nice to embed the clockevent_mxc variable in the structure as well and use container_of to retrieve the structure from the struct clockevent.

The struct clockevent can be the unified parameter across the different functions.

Refer to drivers/clocksource/rockchip_timer.c as an example.

Okay, thanks for the example. I will add a patch to do that.

Shawn

#6 lore raw

PATCH 2/9 ARM: imx: define an enum for gpt timer device type

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

Define an enum for gpt timer device type in include/soc/imx/timer.h to tell the gpt block differences among SoCs. Update non-DT users (clock drivers) to pass the device type.

As we now have include/soc/imx/timer.h, the declaration of mxc_timer_init() is moved into there as the best fit.

---
 arch/arm/mach-imx/time.c    |  6 +++++-
 drivers/clk/imx/clk-imx1.c  |  3 ++-
 drivers/clk/imx/clk-imx21.c |  3 ++-
 drivers/clk/imx/clk-imx27.c |  3 ++-
 drivers/clk/imx/clk-imx31.c |  3 ++-
 drivers/clk/imx/clk-imx35.c |  3 ++-
 drivers/clk/imx/clk.h       |  7 -------
 include/soc/imx/timer.h     | 26 ++++++++++++++++++++++++++
 8 files changed, 41 insertions(+), 13 deletions(-)
 create mode 100644 include/soc/imx/timer.h
arch/arm/mach-imx/time.c +5 -1
index 8ad7cb2a7f08..5241a173fd60 100644
@@ -31,6 +31,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <soc/imx/timer.h>
 
 #include <asm/mach/time.h>
 
@@ -85,6 +86,7 @@ static struct clock_event_device clockevent_mxc;
 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
 struct imx_timer {
+	enum imx_gpt_type type;
 	void __iomem *base;
 	int irq;
 	struct clk *clk_per;
@@ -352,7 +354,7 @@ static void __init _mxc_timer_init(void)
 	setup_irq(imxtm.irq, &mxc_timer_irq);
 }
 
-void __init mxc_timer_init(unsigned long pbase, int irq)
+void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
 {
 	imxtm.clk_per = clk_get_sys("imx-gpt.0", "per");
 	imxtm.clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
@@ -360,6 +362,8 @@ void __init mxc_timer_init(unsigned long pbase, int irq)
 	imxtm.base = ioremap(pbase, SZ_4K);
 	BUG_ON(!imxtm.base);
 
+	imxtm.type = type;
+
 	_mxc_timer_init();
 }
 
drivers/clk/imx/clk-imx1.c +2 -1
index c9812dbacac2..c2647fa19f28 100644
@@ -23,6 +23,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <dt-bindings/clock/imx1-clock.h>
+#include <soc/imx/timer.h>
 #include <asm/irq.h>
 
 #include "clk.h"
@@ -102,7 +103,7 @@ int __init mx1_clocks_init(unsigned long fref)
 	clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ipg", "imx1-fb.0");
 	clk_register_clkdev(clk[IMX1_CLK_DUMMY], "ahb", "imx1-fb.0");
 
-	mxc_timer_init(MX1_TIM1_BASE_ADDR, MX1_TIM1_INT);
+	mxc_timer_init(MX1_TIM1_BASE_ADDR, MX1_TIM1_INT, GPT_TYPE_IMX1);
 
 	return 0;
 }
drivers/clk/imx/clk-imx21.c +2 -1
index 0ca842cf4ca7..dba987e3b89f 100644
@@ -15,6 +15,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <dt-bindings/clock/imx21-clock.h>
+#include <soc/imx/timer.h>
 #include <asm/irq.h>
 
 #include "clk.h"
@@ -156,7 +157,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href)
 	clk_register_clkdev(clk[IMX21_CLK_I2C_GATE], NULL, "imx21-i2c.0");
 	clk_register_clkdev(clk[IMX21_CLK_OWIRE_GATE], NULL, "mxc_w1.0");
 
-	mxc_timer_init(MX21_GPT1_BASE_ADDR, MX21_INT_GPT1);
+	mxc_timer_init(MX21_GPT1_BASE_ADDR, MX21_INT_GPT1, GPT_TYPE_IMX21);
 
 	return 0;
 }
drivers/clk/imx/clk-imx27.c +2 -1
index df2dfc081c71..d9d50d54ef2a 100644
@@ -6,6 +6,7 @@
 #include <linux/of_address.h>
 #include <dt-bindings/clock/imx27-clock.h>
 #include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
 #include <asm/irq.h>
 
 #include "clk.h"
@@ -233,7 +234,7 @@ int __init mx27_clocks_init(unsigned long fref)
 	clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "ahb", "m2m-emmaprp.0");
 	clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "ipg", "m2m-emmaprp.0");
 
-	mxc_timer_init(MX27_GPT1_BASE_ADDR, MX27_INT_GPT1);
+	mxc_timer_init(MX27_GPT1_BASE_ADDR, MX27_INT_GPT1, GPT_TYPE_IMX21);
 
 	return 0;
 }
drivers/clk/imx/clk-imx31.c +2 -1
index a55290c1c264..fe66c40b7be2 100644
@@ -22,6 +22,7 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
 #include <asm/irq.h>
 
 #include "clk.h"
@@ -198,7 +199,7 @@ int __init mx31_clocks_init(unsigned long fref)
 	mx31_revision();
 	clk_disable_unprepare(clk[iim_gate]);
 
-	mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT);
+	mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31);
 
 	return 0;
 }
drivers/clk/imx/clk-imx35.c +2 -1
index f2f3b8164f7b..69138ba3dec7 100644
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/err.h>
 #include <soc/imx/revision.h>
+#include <soc/imx/timer.h>
 #include <asm/irq.h>
 
 #include "clk.h"
@@ -293,7 +294,7 @@ int __init mx35_clocks_init(void)
 
 	imx_print_silicon_rev("i.MX35", mx35_revision());
 
-	mxc_timer_init(MX35_GPT1_BASE_ADDR, MX35_INT_GPT);
+	mxc_timer_init(MX35_GPT1_BASE_ADDR, MX35_INT_GPT, GPT_TYPE_IMX31);
 
 	return 0;
 }
drivers/clk/imx/clk.h +0 -7
index 6bae5374dc83..b5297e457a8e 100644
@@ -6,13 +6,6 @@
 
 extern spinlock_t imx_ccm_lock;
 
-/*
- * This is a stop-gap solution for clock drivers like imx1/imx21 which call
- * mxc_timer_init() to initialize timer for non-DT boot.  It can be removed
- * when these legacy non-DT support is converted or dropped.
- */
-void mxc_timer_init(unsigned long pbase, int irq);
-
 void imx_check_clocks(struct clk *clks[], unsigned int count);
 
 extern void imx_cscmr1_fixup(u32 *val);
include/soc/imx/timer.h new file +26 -0
new file mode 100644
index 000000000000..bbbafd65f464
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SOC_IMX_TIMER_H__
+#define __SOC_IMX_TIMER_H__
+
+enum imx_gpt_type {
+	GPT_TYPE_IMX1,		/* i.MX1 */
+	GPT_TYPE_IMX21,		/* i.MX21/27 */
+	GPT_TYPE_IMX31,		/* i.MX31/35/25/37/51/6Q */
+	GPT_TYPE_IMX6DL,	/* i.MX6DL/SX/SL */
+};
+
+/*
+ * This is a stop-gap solution for clock drivers like imx1/imx21 which call
+ * mxc_timer_init() to initialize timer for non-DT boot.  It can be removed
+ * when these legacy non-DT support is converted or dropped.
+ */
+void mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type);
+
+#endif  /* __SOC_IMX_TIMER_H__ */
Signature · 1 line
1.9.1
#7 lore raw

PATCH 2/9 ARM: imx: define an enum for gpt timer device type

Quoted 31 lines

-----Original Message-----
From: shawnguo at kernel.org [mailto:shawnguo at kernel.org]
Sent: 2015?5?15? 3:12
To: linux-arm-kernel at lists.infradead.org
Cc: kernel at pengutronix.de; Daniel Lezcano; Wang Shenwei-B38339; Shawn Guo
Subject: [PATCH 2/9] ARM: imx: define an enum for gpt timer device type

From: Shawn Guo <[email protected]>

Define an enum for gpt timer device type in include/soc/imx/timer.h to tell the gpt block differences among SoCs. Update non-DT users (clock drivers) to pass the device type.

As we now have include/soc/imx/timer.h, the declaration of mxc_timer_init() is moved into there as the best fit.

000000000000..bbbafd65f464

include/soc/imx/timer.h new file +8 -0
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+

include/soc/imx/timer.h line 18

Quoted 10 lines
include/soc/imx/timer.h new file +10 -0
+#ifndef __SOC_IMX_TIMER_H__
+#define __SOC_IMX_TIMER_H__
+
+enum imx_gpt_type {
+	GPT_TYPE_IMX1,		/* i.MX1 */
+	GPT_TYPE_IMX21,		/* i.MX21/27 */
+	GPT_TYPE_IMX31,		/* i.MX31/35/25/37/51/6Q */
+	GPT_TYPE_IMX6DL,	/* i.MX6DL/SX/SL */
+};
+

Since there is only one type of GPT IP block with different versions, I think to use the word of "GPT_VER_xxx" would make sense.

Regards,
Shenwei

Quoted 13 lines
include/soc/imx/timer.h new file +11 -1
+/*
+ * This is a stop-gap solution for clock drivers like imx1/imx21 which
+call
+ * mxc_timer_init() to initialize timer for non-DT boot.  It can be
+removed
+ * when these legacy non-DT support is converted or dropped.
+ */
+void mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type
+type);
+
+#endif  /* __SOC_IMX_TIMER_H__ */
--

1.9.1

#8 lore raw

PATCH 3/9 ARM: imx: initialize gpt device type for DT boot

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

Use different initialization function in CLOCKSOURCE_OF_DECLARE() to initialize gpt device type for DT boot.

---
 arch/arm/mach-imx/time.c | 44 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 8 deletions(-)
arch/arm/mach-imx/time.c +36 -8
index 5241a173fd60..ed01813cfc76 100644
@@ -385,11 +385,39 @@ static void __init mxc_timer_init_dt(struct device_node *np)
 
 	_mxc_timer_init();
 }
-CLOCKSOURCE_OF_DECLARE(mx1_timer, "fsl,imx1-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx25_timer, "fsl,imx25-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx50_timer, "fsl,imx50-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx51_timer, "fsl,imx51-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx53_timer, "fsl,imx53-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6q_timer, "fsl,imx6q-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6sl_timer, "fsl,imx6sl-gpt", mxc_timer_init_dt);
-CLOCKSOURCE_OF_DECLARE(mx6sx_timer, "fsl,imx6sx-gpt", mxc_timer_init_dt);
+
+static void __init imx1_timer_init_dt(struct device_node *np)
+{
+	imxtm.type = GPT_TYPE_IMX1;
+	mxc_timer_init_dt(np);
+}
+
+static void __init imx21_timer_init_dt(struct device_node *np)
+{
+	imxtm.type = GPT_TYPE_IMX21;
+	mxc_timer_init_dt(np);
+}
+
+static void __init imx31_timer_init_dt(struct device_node *np)
+{
+	imxtm.type = GPT_TYPE_IMX31;
+	mxc_timer_init_dt(np);
+}
+
+static void __init imx6dl_timer_init_dt(struct device_node *np)
+{
+	imxtm.type = GPT_TYPE_IMX6DL;
+	mxc_timer_init_dt(np);
+}
+
+CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
Signature · 1 line
1.9.1
#9 lore raw

PATCH 4/9 ARM: imx: setup tctl register in device specific function

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

It creates device speicific function hook gpt_setup_tctl to set up gpt TCTL register.

---
 arch/arm/mach-imx/time.c | 81 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 62 insertions(+), 19 deletions(-)
arch/arm/mach-imx/time.c +62 -19
index ed01813cfc76..c86e25922eb4 100644
@@ -91,6 +91,7 @@ struct imx_timer {
 	int irq;
 	struct clk *clk_per;
 	struct clk *clk_ipg;
+	void (*gpt_setup_tctl)(void);
 };
 
 static struct imx_timer imxtm;
@@ -306,9 +307,68 @@ static int __init mxc_clockevent_init(void)
 	return 0;
 }
 
+static void imx1_gpt_setup_tctl(void)
+{
+	u32 tctl_val;
+
+	tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+}
+#define imx21_gpt_setup_tctl imx1_gpt_setup_tctl
+
+static void imx31_gpt_setup_tctl(void)
+{
+	u32 tctl_val;
+
+	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+	if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8)
+		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+	else
+		tctl_val |= V2_TCTL_CLK_PER;
+
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+}
+
+static void imx6dl_gpt_setup_tctl(void)
+{
+	u32 tctl_val;
+
+	tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
+	if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8) {
+		tctl_val |= V2_TCTL_CLK_OSC_DIV8;
+		/* 24 / 8 = 3 MHz */
+		__raw_writel(7 << V2_TPRER_PRE24M, imxtm.base + MXC_TPRER);
+		tctl_val |= V2_TCTL_24MEN;
+	} else {
+		tctl_val |= V2_TCTL_CLK_PER;
+	}
+
+	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+}
+
+static void __init imx_timer_data_init(void)
+{
+	switch (imxtm.type) {
+	case GPT_TYPE_IMX1:
+		imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
+		break;
+	case GPT_TYPE_IMX21:
+		imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
+		break;
+	case GPT_TYPE_IMX31:
+		imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
+		break;
+	case GPT_TYPE_IMX6DL:
+		imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
+		break;
+	default:
+		BUG();
+	}
+}
+
 static void __init _mxc_timer_init(void)
 {
-	uint32_t tctl_val;
+	imx_timer_data_init();
 
 	if (IS_ERR(imxtm.clk_per)) {
 		pr_err("i.MX timer: unable to get clk\n");
@@ -327,24 +387,7 @@ static void __init _mxc_timer_init(void)
 	__raw_writel(0, imxtm.base + MXC_TCTL);
 	__raw_writel(0, imxtm.base + MXC_TPRER); /* see datasheet note */
 
-	if (timer_is_v2()) {
-		tctl_val = V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
-		if (clk_get_rate(imxtm.clk_per) == V2_TIMER_RATE_OSC_DIV8) {
-			tctl_val |= V2_TCTL_CLK_OSC_DIV8;
-			if (cpu_is_imx6dl() || cpu_is_imx6sx()) {
-				/* 24 / 8 = 3 MHz */
-				__raw_writel(7 << V2_TPRER_PRE24M,
-					imxtm.base + MXC_TPRER);
-				tctl_val |= V2_TCTL_24MEN;
-			}
-		} else {
-			tctl_val |= V2_TCTL_CLK_PER;
-		}
-	} else {
-		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
-	}
-
-	__raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+	imxtm.gpt_setup_tctl();
 
 	/* init and register the timer to the framework */
 	mxc_clocksource_init();
Signature · 1 line
1.9.1
#10 lore raw

PATCH 4/9 ARM: imx: setup tctl register in device specific function

arch/arm/mach-imx/time.c static int __init mxc_clockevent_init(void) · line 316

Quoted 10 lines · On Friday 15 May 2015 16:11:42 shawnguo at kernel.org wrote:

}

arch/arm/mach-imx/time.c +7 -0
+static void imx1_gpt_setup_tctl(void)
+{
+       u32 tctl_val;
+
+       tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+       __raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+}

Could you add another upfront patch to convert all the __raw_readl/__raw_writel to readl_relaxed/writel_relaxed?

It would be nice if the driver was endian-safe by the time it gets moved to drivers/clocksource, and you don't add any unsafe accesses for the changed code.

Arnd

author
#11 lore raw

PATCH 4/9 ARM: imx: setup tctl register in device specific function

Quoted 15 lines · Arnd Bergmann

arch/arm/mach-imx/time.c static int __init mxc_clockevent_init(void) · line 316

Quoted 10 lines · On Friday 15 May 2015 16:11:42 shawnguo at kernel.org wrote:

}

arch/arm/mach-imx/time.c +7 -0
+static void imx1_gpt_setup_tctl(void)
+{
+       u32 tctl_val;
+
+       tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
+       __raw_writel(tctl_val, imxtm.base + MXC_TCTL);
+}

Could you add another upfront patch to convert all the __raw_readl/__raw_writel to readl_relaxed/writel_relaxed?

Quoted 3 lines

It would be nice if the driver was endian-safe by the time it gets moved to drivers/clocksource, and you don't add any unsafe accesses for the changed code.

Make sense. Will do.

Shawn

#12 lore raw

PATCH 5/9 ARM: imx: set up set_next_event hook in imx_timer_data_init()

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

Function imx_timer_data_init() was there for setting up device specific data, so let's move the setup of set_next_event hook into there.

---
 arch/arm/mach-imx/time.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm/mach-imx/time.c +4 -4
index c86e25922eb4..d79a00e24084 100644
@@ -290,15 +290,11 @@ static struct clock_event_device clockevent_mxc = {
 	.name		= "mxc_timer1",
 	.features	= CLOCK_EVT_FEAT_ONESHOT,
 	.set_mode	= mxc_set_mode,
-	.set_next_event	= mx1_2_set_next_event,
 	.rating		= 200,
 };
 
 static int __init mxc_clockevent_init(void)
 {
-	if (timer_is_v2())
-		clockevent_mxc.set_next_event = v2_set_next_event;
-
 	clockevent_mxc.cpumask = cpumask_of(0);
 	clockevents_config_and_register(&clockevent_mxc,
 					clk_get_rate(imxtm.clk_per),
@@ -351,15 +347,19 @@ static void __init imx_timer_data_init(void)
 	switch (imxtm.type) {
 	case GPT_TYPE_IMX1:
 		imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
+		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX21:
 		imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
+		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX31:
 		imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
+		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
 	case GPT_TYPE_IMX6DL:
 		imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
+		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
 	default:
 		BUG();
Signature · 1 line
1.9.1
#13 lore raw

PATCH 6/9 ARM: imx: define gpt register offset per device type

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

It initializes offset of gpt registers TSTAT, TCN and TCMP per device type, so that the access to these registers can be unified.

---
 arch/arm/mach-imx/time.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)
arch/arm/mach-imx/time.c +19 -12
index d79a00e24084..5908e78d9552 100644
@@ -91,6 +91,9 @@ struct imx_timer {
 	int irq;
 	struct clk *clk_per;
 	struct clk *clk_ipg;
+	int reg_tstat;
+	int reg_tcn;
+	int reg_tcmp;
 	void (*gpt_setup_tctl)(void);
 };
 
@@ -147,7 +150,7 @@ static unsigned long imx_read_current_timer(void)
 static int __init mxc_clocksource_init(void)
 {
 	unsigned int c = clk_get_rate(imxtm.clk_per);
-	void __iomem *reg = imxtm.base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
+	void __iomem *reg = imxtm.base + imxtm.reg_tcn;
 
 	imx_delay_timer.read_current_timer = &imx_read_current_timer;
 	imx_delay_timer.freq = c;
@@ -214,13 +217,8 @@ static void mxc_set_mode(enum clock_event_mode mode,
 	gpt_irq_disable();
 
 	if (mode != clockevent_mode) {
-		/* Set event time into far-far future */
-		if (timer_is_v2())
-			__raw_writel(__raw_readl(imxtm.base + V2_TCN) - 3,
-					imxtm.base + V2_TCMP);
-		else
-			__raw_writel(__raw_readl(imxtm.base + MX1_2_TCN) - 3,
-					imxtm.base + MX1_2_TCMP);
+		__raw_writel(__raw_readl(imxtm.base + imxtm.reg_tcn) - 3,
+					imxtm.base + imxtm.reg_tcmp);
 
 		/* Clear pending interrupt */
 		gpt_irq_acknowledge();
@@ -268,10 +266,7 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
 	struct clock_event_device *evt = &clockevent_mxc;
 	uint32_t tstat;
 
-	if (timer_is_v2())
-		tstat = __raw_readl(imxtm.base + V2_TSTAT);
-	else
-		tstat = __raw_readl(imxtm.base + MX1_2_TSTAT);
+	tstat = __raw_readl(imxtm.base + imxtm.reg_tstat);
 
 	gpt_irq_acknowledge();
 
@@ -346,18 +341,30 @@ static void __init imx_timer_data_init(void)
 {
 	switch (imxtm.type) {
 	case GPT_TYPE_IMX1:
+		imxtm.reg_tstat = MX1_2_TSTAT;
+		imxtm.reg_tcn = MX1_2_TCN;
+		imxtm.reg_tcmp = MX1_2_TCMP;
 		imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
 		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX21:
+		imxtm.reg_tstat = MX1_2_TSTAT;
+		imxtm.reg_tcn = MX1_2_TCN;
+		imxtm.reg_tcmp = MX1_2_TCMP;
 		imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
 		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX31:
+		imxtm.reg_tstat = V2_TSTAT;
+		imxtm.reg_tcn = V2_TCN;
+		imxtm.reg_tcmp = V2_TCMP;
 		imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
 		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
 	case GPT_TYPE_IMX6DL:
+		imxtm.reg_tstat = V2_TSTAT;
+		imxtm.reg_tcn = V2_TCN;
+		imxtm.reg_tcmp = V2_TCMP;
 		imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
 		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
Signature · 1 line
1.9.1
#14 lore raw

PATCH 6/9 ARM: imx: define gpt register offset per device type

Quoted 21 lines · On Friday 15 May 2015 16:11:44 shawnguo at kernel.org wrote:
 {
        switch (imxtm.type) {
        case GPT_TYPE_IMX1:
arch/arm/mach-imx/time.c +9 -0
+               imxtm.reg_tstat = MX1_2_TSTAT;
+               imxtm.reg_tcn = MX1_2_TCN;
+               imxtm.reg_tcmp = MX1_2_TCMP;
                imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
                clockevent_mxc.set_next_event = mx1_2_set_next_event;
                break;
        case GPT_TYPE_IMX21:
+               imxtm.reg_tstat = MX1_2_TSTAT;
+               imxtm.reg_tcn = MX1_2_TCN;
+               imxtm.reg_tcmp = MX1_2_TCMP;
                imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
                clockevent_mxc.set_next_event = mx1_2_set_next_event;
                break;
        case GPT_TYPE_IMX31:
+               imxtm.reg_tstat = V2_TSTAT;
+               imxtm.reg_tcn = V2_TCN;
+               imxtm.reg_tcmp = V2_TCMP;

arch/arm/mach-imx/time.c static void __init imx_timer_data_init(void) · line 370

Quoted 10 lines
arch/arm/mach-imx/time.c +3 -0
                imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
                clockevent_mxc.set_next_event = v2_set_next_event;
                break;
        case GPT_TYPE_IMX6DL:
+               imxtm.reg_tstat = V2_TSTAT;
+               imxtm.reg_tcn = V2_TCN;
+               imxtm.reg_tcmp = V2_TCMP;
                imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
                clockevent_mxc.set_next_event = v2_set_next_event;
                break;

Hi Shawn,

I think this could be expressed in a nicer way by defining a structure that contains all the settings you derive from the type here, and then setting a pointer to that structure based on the compatible string.

Arnd

author
#15 lore raw

PATCH 6/9 ARM: imx: define gpt register offset per device type

Quoted 33 lines · Arnd Bergmann
Quoted 21 lines · On Friday 15 May 2015 16:11:44 shawnguo at kernel.org wrote:
 {
        switch (imxtm.type) {
        case GPT_TYPE_IMX1:
arch/arm/mach-imx/time.c +9 -0
+               imxtm.reg_tstat = MX1_2_TSTAT;
+               imxtm.reg_tcn = MX1_2_TCN;
+               imxtm.reg_tcmp = MX1_2_TCMP;
                imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
                clockevent_mxc.set_next_event = mx1_2_set_next_event;
                break;
        case GPT_TYPE_IMX21:
+               imxtm.reg_tstat = MX1_2_TSTAT;
+               imxtm.reg_tcn = MX1_2_TCN;
+               imxtm.reg_tcmp = MX1_2_TCMP;
                imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
                clockevent_mxc.set_next_event = mx1_2_set_next_event;
                break;
        case GPT_TYPE_IMX31:
+               imxtm.reg_tstat = V2_TSTAT;
+               imxtm.reg_tcn = V2_TCN;
+               imxtm.reg_tcmp = V2_TCMP;

arch/arm/mach-imx/time.c static void __init imx_timer_data_init(void) · line 370

Quoted 10 lines
arch/arm/mach-imx/time.c +3 -0
                imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
                clockevent_mxc.set_next_event = v2_set_next_event;
                break;
        case GPT_TYPE_IMX6DL:
+               imxtm.reg_tstat = V2_TSTAT;
+               imxtm.reg_tcn = V2_TCN;
+               imxtm.reg_tcmp = V2_TCMP;
                imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
                clockevent_mxc.set_next_event = v2_set_next_event;
                break;
Quoted 5 lines

Hi Shawn,

I think this could be expressed in a nicer way by defining a structure that contains all the settings you derive from the type here, and then setting a pointer to that structure based on the compatible string.

Yeah, good suggestion. Will change.

Shawn

#16 lore raw

PATCH 7/9 ARM: imx: provide gpt device specific irq functions

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

It splits irq enable/disable/acknowledge operations into device specific functions to get proper hook called in the correct context.

---
 arch/arm/mach-imx/time.c | 76 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 51 insertions(+), 25 deletions(-)
arch/arm/mach-imx/time.c +51 -25
index 5908e78d9552..174c553a3bb7 100644
@@ -95,44 +95,58 @@ struct imx_timer {
 	int reg_tcn;
 	int reg_tcmp;
 	void (*gpt_setup_tctl)(void);
+	void (*gpt_irq_enable)(void);
+	void (*gpt_irq_disable)(void);
+	void (*gpt_irq_acknowledge)(void);
 };
 
 static struct imx_timer imxtm;
 
-static inline void gpt_irq_disable(void)
+static void imx1_gpt_irq_disable(void)
 {
 	unsigned int tmp;
 
-	if (timer_is_v2())
-		__raw_writel(0, imxtm.base + V2_IR);
-	else {
-		tmp = __raw_readl(imxtm.base + MXC_TCTL);
-		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, imxtm.base + MXC_TCTL);
-	}
+	tmp = __raw_readl(imxtm.base + MXC_TCTL);
+	__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, imxtm.base + MXC_TCTL);
+}
+#define imx21_gpt_irq_disable imx1_gpt_irq_disable
+
+static void imx31_gpt_irq_disable(void)
+{
+	__raw_writel(0, imxtm.base + V2_IR);
 }
+#define imx6dl_gpt_irq_disable imx31_gpt_irq_disable
 
-static inline void gpt_irq_enable(void)
+static void imx1_gpt_irq_enable(void)
 {
-	if (timer_is_v2())
-		__raw_writel(1<<0, imxtm.base + V2_IR);
-	else {
-		__raw_writel(__raw_readl(imxtm.base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
+	__raw_writel(__raw_readl(imxtm.base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
 			imxtm.base + MXC_TCTL);
-	}
+}
+#define imx21_gpt_irq_enable imx1_gpt_irq_enable
+
+static void imx31_gpt_irq_enable(void)
+{
+	__raw_writel(1<<0, imxtm.base + V2_IR);
+}
+#define imx6dl_gpt_irq_enable imx31_gpt_irq_enable
+
+static void imx1_gpt_irq_acknowledge(void)
+{
+	__raw_writel(0, imxtm.base + MX1_2_TSTAT);
 }
 
-static void gpt_irq_acknowledge(void)
+static void imx21_gpt_irq_acknowledge(void)
 {
-	if (timer_is_v1()) {
-		if (cpu_is_mx1())
-			__raw_writel(0, imxtm.base + MX1_2_TSTAT);
-		else
-			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
+	__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
 				imxtm.base + MX1_2_TSTAT);
-	} else if (timer_is_v2())
-		__raw_writel(V2_TSTAT_OF1, imxtm.base + V2_TSTAT);
 }
 
+static void imx31_gpt_irq_acknowledge(void)
+{
+	__raw_writel(V2_TSTAT_OF1, imxtm.base + V2_TSTAT);
+}
+#define imx6dl_gpt_irq_acknowledge imx31_gpt_irq_acknowledge
+
 static void __iomem *sched_clock_reg;
 
 static u64 notrace mxc_read_sched_clock(void)
@@ -214,14 +228,14 @@ static void mxc_set_mode(enum clock_event_mode mode,
 	local_irq_save(flags);
 
 	/* Disable interrupt in GPT module */
-	gpt_irq_disable();
+	imxtm.gpt_irq_disable();
 
 	if (mode != clockevent_mode) {
 		__raw_writel(__raw_readl(imxtm.base + imxtm.reg_tcn) - 3,
 					imxtm.base + imxtm.reg_tcmp);
 
 		/* Clear pending interrupt */
-		gpt_irq_acknowledge();
+		imxtm.gpt_irq_acknowledge();
 	}
 
 #ifdef DEBUG
@@ -247,7 +261,7 @@ static void mxc_set_mode(enum clock_event_mode mode,
 	 * mode switching
 	 */
 		local_irq_save(flags);
-		gpt_irq_enable();
+		imxtm.gpt_irq_enable();
 		local_irq_restore(flags);
 		break;
 	case CLOCK_EVT_MODE_SHUTDOWN:
@@ -268,7 +282,7 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
 
 	tstat = __raw_readl(imxtm.base + imxtm.reg_tstat);
 
-	gpt_irq_acknowledge();
+	imxtm.gpt_irq_acknowledge();
 
 	evt->event_handler(evt);
 
@@ -345,6 +359,9 @@ static void __init imx_timer_data_init(void)
 		imxtm.reg_tcn = MX1_2_TCN;
 		imxtm.reg_tcmp = MX1_2_TCMP;
 		imxtm.gpt_setup_tctl = imx1_gpt_setup_tctl;
+		imxtm.gpt_irq_enable = imx1_gpt_irq_enable;
+		imxtm.gpt_irq_disable = imx1_gpt_irq_disable;
+		imxtm.gpt_irq_acknowledge = imx1_gpt_irq_acknowledge;
 		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX21:
@@ -352,6 +369,9 @@ static void __init imx_timer_data_init(void)
 		imxtm.reg_tcn = MX1_2_TCN;
 		imxtm.reg_tcmp = MX1_2_TCMP;
 		imxtm.gpt_setup_tctl = imx21_gpt_setup_tctl;
+		imxtm.gpt_irq_enable = imx21_gpt_irq_enable;
+		imxtm.gpt_irq_disable = imx21_gpt_irq_disable;
+		imxtm.gpt_irq_acknowledge = imx21_gpt_irq_acknowledge;
 		clockevent_mxc.set_next_event = mx1_2_set_next_event;
 		break;
 	case GPT_TYPE_IMX31:
@@ -359,6 +379,9 @@ static void __init imx_timer_data_init(void)
 		imxtm.reg_tcn = V2_TCN;
 		imxtm.reg_tcmp = V2_TCMP;
 		imxtm.gpt_setup_tctl = imx31_gpt_setup_tctl;
+		imxtm.gpt_irq_enable = imx31_gpt_irq_enable;
+		imxtm.gpt_irq_disable = imx31_gpt_irq_disable;
+		imxtm.gpt_irq_acknowledge = imx31_gpt_irq_acknowledge;
 		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
 	case GPT_TYPE_IMX6DL:
@@ -366,6 +389,9 @@ static void __init imx_timer_data_init(void)
 		imxtm.reg_tcn = V2_TCN;
 		imxtm.reg_tcmp = V2_TCMP;
 		imxtm.gpt_setup_tctl = imx6dl_gpt_setup_tctl;
+		imxtm.gpt_irq_enable = imx6dl_gpt_irq_enable;
+		imxtm.gpt_irq_disable = imx6dl_gpt_irq_disable;
+		imxtm.gpt_irq_acknowledge = imx6dl_gpt_irq_acknowledge;
 		clockevent_mxc.set_next_event = v2_set_next_event;
 		break;
 	default:
Signature · 1 line
1.9.1
#17 lore raw

PATCH 8/9 ARM: imx: remove platform headers from timer driver

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

With the cleanup done before, the platform specific headers now can be removed.

---
 arch/arm/mach-imx/time.c | 6 ------
 1 file changed, 6 deletions(-)
arch/arm/mach-imx/time.c +0 -6
index 174c553a3bb7..ecf043f6c6fd 100644
@@ -35,9 +35,6 @@
 
 #include <asm/mach/time.h>
 
-#include "common.h"
-#include "hardware.h"
-
 /*
  * There are 4 versions of the timer hardware on Freescale MXC hardware.
  *  - MX1/MXL
@@ -79,9 +76,6 @@
 
 #define V2_TIMER_RATE_OSC_DIV8	3000000
 
-#define timer_is_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
-#define timer_is_v2()	(!timer_is_v1())
-
 static struct clock_event_device clockevent_mxc;
 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
 
Signature · 1 line
1.9.1
#18 lore raw

PATCH 9/9 ARM: imx: move timer driver into drivers/clocksource

In reply to shawnguo at kernel.org

From: Shawn Guo <[email protected]>

After the cleanup on imx timer driver, now it's ready to be moved into drivers/clocksource/. Let's do it.

---
 arch/arm/mach-imx/Makefile                                  | 2 +-
 drivers/clocksource/Makefile                                | 1 +
 arch/arm/mach-imx/time.c => drivers/clocksource/timer-imx.c | 0
 3 files changed, 2 insertions(+), 1 deletion(-)
 rename arch/arm/mach-imx/time.c => drivers/clocksource/timer-imx.c (100%)
arch/arm/mach-imx/Makefile +1 -1
index 40df12af5036..0ac47955f3e1 100644
@@ -1,4 +1,4 @@
-obj-y := time.o cpu.o system.o irq-common.o
+obj-y := cpu.o system.o irq-common.o
 
 obj-$(CONFIG_SOC_IMX1) += mm-imx1.o
 obj-$(CONFIG_SOC_IMX21) += mm-imx21.o
drivers/clocksource/Makefile +1 -0
index 5b85f6adb258..5c5a89479631 100644
@@ -52,3 +52,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= timer-integrator-ap.o
 obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
 obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
 obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
+obj-$(CONFIG_ARCH_MXC)			+= timer-imx.o
drivers/clocksource/timer-imx.c renamed from arch/arm/mach-imx/time.c +0 -0
similarity index 100%
rename from arch/arm/mach-imx/time.c
rename to drivers/clocksource/timer-imx.c
Signature · 1 line
1.9.1