linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
@ 2018-06-11 15:49 Clément Péron
  2018-06-11 15:49 ` [PATCH v7 1/5] clk: imx6: add EPIT clock support Clément Péron
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:49 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Clément Peron <clement.peron@devialet.com>

As suggested in the commit message we have added the device tree support,
proper bindings and we moved the driver into the correct folder.

Moreover we made some changes like use of relaxed IO accesor,
implement sched_clock, delay_timer and reduce the clockevents min_delta.

Changes since v6:
-fix indent

Changes since v5:
- change epit to timer in doc example
- fix typo in imx6sl.dtsi

Changes since v4:
- removed ipg clk
- change in dt epit to timer
- add introduction in doc
- add all compatibles in doc
- update epit entry for other i.MX device-trees

Changes since v3:
- Clean Kconfig
- Rename imx6q-epit to imx31-epit
- Update doc and bindings
- Indent and fix

Changes since v2 (Thanks Fabio Estevam):
- Removed unused ckil clock
- Add out_iounmap
- Check and handle if clk_prepare_enable failed
- Fix comment typo

Changes since v1 (Thanks Vladimir Zapolskiy):
- Add OF dependency in Kconfig
- Sort header
- Use BIT macro
- Remove useless comments
- Fix incorrect indent
- Fix memory leak
- Add check and handle possible returned error

Clément Peron (2):
  ARM: imx: remove inexistant EPIT timer init
  dt-bindings: timer: add i.MX EPIT timer binding

Colin Didier (3):
  clk: imx6: add EPIT clock support
  clocksource: add driver for i.MX EPIT timer
  ARM: dts: imx: add missing compatible and clock properties for EPIT

 .../devicetree/bindings/timer/fsl,imxepit.txt |  21 ++
 arch/arm/boot/dts/imx25.dtsi                  |   8 +-
 arch/arm/boot/dts/imx6qdl.dtsi                |  10 +-
 arch/arm/boot/dts/imx6sl.dtsi                 |  10 +-
 arch/arm/boot/dts/imx6sx.dtsi                 |  10 +-
 arch/arm/boot/dts/imx6ul.dtsi                 |  10 +-
 arch/arm/mach-imx/common.h                    |   1 -
 drivers/clk/imx/clk-imx6q.c                   |   2 +
 drivers/clocksource/Kconfig                   |  11 +
 drivers/clocksource/Makefile                  |   1 +
 drivers/clocksource/timer-imx-epit.c          | 265 ++++++++++++++++++
 include/dt-bindings/clock/imx6qdl-clock.h     |   4 +-
 12 files changed, 341 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,imxepit.txt
 create mode 100644 drivers/clocksource/timer-imx-epit.c

-- 
2.17.1

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

* [PATCH v7 1/5] clk: imx6: add EPIT clock support
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
@ 2018-06-11 15:49 ` Clément Péron
  2018-06-11 15:49 ` [PATCH v7 2/5] ARM: imx: remove inexistant EPIT timer init Clément Péron
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:49 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Colin Didier <colin.didier@devialet.com>

Ignore this Patch, already merged in clk-next

Signed-off-by: Colin Didier <colin.didier@devialet.com>
Signed-off-by: Clément Peron <clement.peron@devialet.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 drivers/clk/imx/clk-imx6q.c               | 2 ++
 include/dt-bindings/clock/imx6qdl-clock.h | 4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 8d518ad5dc13..b9ea7037e193 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -753,6 +753,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	else
 		clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
 	clk[IMX6QDL_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x6c, 10);
+	clk[IMX6QDL_CLK_EPIT1]        = imx_clk_gate2("epit1",         "ipg",               base + 0x6c, 12);
+	clk[IMX6QDL_CLK_EPIT2]        = imx_clk_gate2("epit2",         "ipg",               base + 0x6c, 14);
 	clk[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
 	clk[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
 	clk[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h
index da59fd9cdb5e..7ad171b8f3bf 100644
--- a/include/dt-bindings/clock/imx6qdl-clock.h
+++ b/include/dt-bindings/clock/imx6qdl-clock.h
@@ -271,6 +271,8 @@
 #define IMX6QDL_CLK_PRE_AXI			258
 #define IMX6QDL_CLK_MLB_SEL			259
 #define IMX6QDL_CLK_MLB_PODF			260
-#define IMX6QDL_CLK_END				261
+#define IMX6QDL_CLK_EPIT1			261
+#define IMX6QDL_CLK_EPIT2			262
+#define IMX6QDL_CLK_END				263
 
 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
-- 
2.17.1

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

* [PATCH v7 2/5] ARM: imx: remove inexistant EPIT timer init
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
  2018-06-11 15:49 ` [PATCH v7 1/5] clk: imx6: add EPIT clock support Clément Péron
@ 2018-06-11 15:49 ` Clément Péron
  2018-06-11 15:49 ` [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding Clément Péron
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:49 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Clément Peron <clement.peron@devialet.com>

i.MX EPIT timer has been removed but not the init function declaration.

Signed-off-by: Clément Peron <clement.peron@devialet.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
Tested-by: Vladimir Zapolskiy <vz@mleia.com>
---
 arch/arm/mach-imx/common.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index c8d68e918b2f..18aae76fa2da 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -38,7 +38,6 @@ void imx21_soc_init(void);
 void imx27_soc_init(void);
 void imx31_soc_init(void);
 void imx35_soc_init(void);
-void epit_timer_init(void __iomem *base, int irq);
 int mx21_clocks_init(unsigned long lref, unsigned long fref);
 int mx27_clocks_init(unsigned long fref);
 int mx31_clocks_init(unsigned long fref);
-- 
2.17.1

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

* [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
  2018-06-11 15:49 ` [PATCH v7 1/5] clk: imx6: add EPIT clock support Clément Péron
  2018-06-11 15:49 ` [PATCH v7 2/5] ARM: imx: remove inexistant EPIT timer init Clément Péron
@ 2018-06-11 15:49 ` Clément Péron
  2018-06-12 18:27   ` Rob Herring
  2018-06-11 15:50 ` [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer Clément Péron
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:49 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Clément Peron <clement.peron@devialet.com>

Add devicetree binding document for NXP's i.MX SoC specific
EPIT timer driver.

Signed-off-by: Clément Peron <clement.peron@devialet.com>
Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
---
 .../devicetree/bindings/timer/fsl,imxepit.txt | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/fsl,imxepit.txt

diff --git a/Documentation/devicetree/bindings/timer/fsl,imxepit.txt b/Documentation/devicetree/bindings/timer/fsl,imxepit.txt
new file mode 100644
index 000000000000..819d6458a860
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,imxepit.txt
@@ -0,0 +1,21 @@
+Binding for the i.MX Enhanced Periodic Interrupt Timer (EPIT)
+
+The Enhanced Periodic Interrupt Timer (EPIT) is a 32-bit set-and-forget timer
+that is capable of providing precise interrupts at regular intervals with
+minimal processor intervention.
+
+Required properties:
+- compatible: should be "fsl,<chip>-epit", "fsl,imx31-epit" where <chip> is
+  imx25, imx6qdl, imx6sl, imx6sul or imx6sx.
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: Should contain EPIT controller interrupt
+- clocks : The clock provided by the SoC to drive the timer.
+
+Example for i.MX6QDL:
+	epit1: timer@20d0000 {
+		compatible = "fsl,imx6qdl-epit", "fsl,imx31-epit";
+		reg = <0x020d0000 0x4000>;
+		interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks IMX6QDL_CLK_EPIT1>;
+	};
-- 
2.17.1

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

* [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
                   ` (2 preceding siblings ...)
  2018-06-11 15:49 ` [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding Clément Péron
@ 2018-06-11 15:50 ` Clément Péron
  2018-07-10 16:20   ` Daniel Lezcano
  2018-06-11 15:50 ` [PATCH v7 5/5] ARM: dts: imx: add missing compatible and clock properties for EPIT Clément Péron
  2018-07-10 14:55 ` [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
  5 siblings, 1 reply; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:50 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Colin Didier <colin.didier@devialet.com>

Add driver for NXP's EPIT timer used in i.MX SoC.

Signed-off-by: Colin Didier <colin.didier@devialet.com>
Signed-off-by: Clément Peron <clement.peron@devialet.com>
Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
Tested-by: Vladimir Zapolskiy <vz@mleia.com>
---
 drivers/clocksource/Kconfig          |  11 ++
 drivers/clocksource/Makefile         |   1 +
 drivers/clocksource/timer-imx-epit.c | 265 +++++++++++++++++++++++++++
 3 files changed, 277 insertions(+)
 create mode 100644 drivers/clocksource/timer-imx-epit.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 8e8a09755d10..790478afd02c 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -576,6 +576,17 @@ config H8300_TPU
 	  This enables the clocksource for the H8300 platform with the
 	  H8S2678 cpu.
 
+config CLKSRC_IMX_EPIT
+	bool "Clocksource using i.MX EPIT"
+	depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
+	select CLKSRC_MMIO
+	help
+	  This enables EPIT support available on some i.MX platforms.
+	  Normally you don't have a reason to do so as the EPIT has
+	  the same features and uses the same clocks as the GPT.
+	  Anyway, on some systems the GPT may be in use for other
+	  purposes.
+
 config CLKSRC_IMX_GPT
 	bool "Clocksource using i.MX GPT" if COMPILE_TEST
 	depends on ARM && CLKDEV_LOOKUP
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 00caf37e52f9..d9426f69ec69 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER)	+= timer-integrator-ap.o
 obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
 obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
 obj-$(CONFIG_CLKSRC_TANGO_XTAL)		+= tango_xtal.o
+obj-$(CONFIG_CLKSRC_IMX_EPIT)		+= timer-imx-epit.o
 obj-$(CONFIG_CLKSRC_IMX_GPT)		+= timer-imx-gpt.o
 obj-$(CONFIG_CLKSRC_IMX_TPM)		+= timer-imx-tpm.o
 obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
diff --git a/drivers/clocksource/timer-imx-epit.c b/drivers/clocksource/timer-imx-epit.c
new file mode 100644
index 000000000000..7f1c8e2e00aa
--- /dev/null
+++ b/drivers/clocksource/timer-imx-epit.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * i.MX EPIT Timer
+ *
+ * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
+ * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
+
+#define EPITCR				0x00
+#define EPITSR				0x04
+#define EPITLR				0x08
+#define EPITCMPR			0x0c
+#define EPITCNR				0x10
+
+#define EPITCR_EN			BIT(0)
+#define EPITCR_ENMOD			BIT(1)
+#define EPITCR_OCIEN			BIT(2)
+#define EPITCR_RLD			BIT(3)
+#define EPITCR_PRESC(x)			(((x) & 0xfff) << 4)
+#define EPITCR_SWR			BIT(16)
+#define EPITCR_IOVW			BIT(17)
+#define EPITCR_DBGEN			BIT(18)
+#define EPITCR_WAITEN			BIT(19)
+#define EPITCR_RES			BIT(20)
+#define EPITCR_STOPEN			BIT(21)
+#define EPITCR_OM_DISCON		(0 << 22)
+#define EPITCR_OM_TOGGLE		(1 << 22)
+#define EPITCR_OM_CLEAR			(2 << 22)
+#define EPITCR_OM_SET			(3 << 22)
+#define EPITCR_CLKSRC_OFF		(0 << 24)
+#define EPITCR_CLKSRC_PERIPHERAL	(1 << 24)
+#define EPITCR_CLKSRC_REF_HIGH		(2 << 24)
+#define EPITCR_CLKSRC_REF_LOW		(3 << 24)
+
+#define EPITSR_OCIF			BIT(0)
+
+struct epit_timer {
+	void __iomem *base;
+	int irq;
+	struct clk *clk;
+	struct clock_event_device ced;
+	struct irqaction act;
+};
+
+static void __iomem *sched_clock_reg;
+
+static inline struct epit_timer *to_epit_timer(struct clock_event_device *ced)
+{
+	return container_of(ced, struct epit_timer, ced);
+}
+
+static inline void epit_irq_disable(struct epit_timer *epittm)
+{
+	u32 val;
+
+	val = readl_relaxed(epittm->base + EPITCR);
+	writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
+}
+
+static inline void epit_irq_enable(struct epit_timer *epittm)
+{
+	u32 val;
+
+	val = readl_relaxed(epittm->base + EPITCR);
+	writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
+}
+
+static void epit_irq_acknowledge(struct epit_timer *epittm)
+{
+	writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
+}
+
+static u64 notrace epit_read_sched_clock(void)
+{
+	return ~readl_relaxed(sched_clock_reg);
+}
+
+static int epit_set_next_event(unsigned long cycles,
+			       struct clock_event_device *ced)
+{
+	struct epit_timer *epittm = to_epit_timer(ced);
+	unsigned long tcmp;
+
+	tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
+	writel_relaxed(tcmp, epittm->base + EPITCMPR);
+
+	return 0;
+}
+
+/* Left event sources disabled, no more interrupts appear */
+static int epit_shutdown(struct clock_event_device *ced)
+{
+	struct epit_timer *epittm = to_epit_timer(ced);
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call epit_set_next_event()
+	 */
+	local_irq_save(flags);
+
+	/* Disable interrupt in EPIT module */
+	epit_irq_disable(epittm);
+
+	/* Clear pending interrupt */
+	epit_irq_acknowledge(epittm);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static int epit_set_oneshot(struct clock_event_device *ced)
+{
+	struct epit_timer *epittm = to_epit_timer(ced);
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call epit_set_next_event()
+	 */
+	local_irq_save(flags);
+
+	/* Disable interrupt in EPIT module */
+	epit_irq_disable(epittm);
+
+	/* Clear pending interrupt, only while switching mode */
+	if (!clockevent_state_oneshot(ced))
+		epit_irq_acknowledge(epittm);
+
+	/*
+	 * Do not put overhead of interrupt enable/disable into
+	 * epit_set_next_event(), the core has about 4 minutes
+	 * to call epit_set_next_event() or shutdown clock after
+	 * mode switching
+	 */
+	epit_irq_enable(epittm);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ced = dev_id;
+	struct epit_timer *epittm = to_epit_timer(ced);
+
+	epit_irq_acknowledge(epittm);
+
+	ced->event_handler(ced);
+
+	return IRQ_HANDLED;
+}
+
+static int __init epit_clocksource_init(struct epit_timer *epittm)
+{
+	unsigned int c = clk_get_rate(epittm->clk);
+
+	sched_clock_reg = epittm->base + EPITCNR;
+	sched_clock_register(epit_read_sched_clock, 32, c);
+
+	return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c, 200, 32,
+				     clocksource_mmio_readl_down);
+}
+
+static int __init epit_clockevent_init(struct epit_timer *epittm)
+{
+	struct clock_event_device *ced = &epittm->ced;
+	struct irqaction *act = &epittm->act;
+
+	ced->name = "epit";
+	ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
+	ced->set_state_shutdown = epit_shutdown;
+	ced->tick_resume = epit_shutdown;
+	ced->set_state_oneshot = epit_set_oneshot;
+	ced->set_next_event = epit_set_next_event;
+	ced->rating = 200;
+	ced->cpumask = cpumask_of(0);
+	ced->irq = epittm->irq;
+	clockevents_config_and_register(ced, clk_get_rate(epittm->clk),
+					0xff, 0xfffffffe);
+
+	act->name = "i.MX EPIT Timer Tick",
+	act->flags = IRQF_TIMER | IRQF_IRQPOLL;
+	act->handler = epit_timer_interrupt;
+	act->dev_id = ced;
+
+	/* Make irqs happen */
+	return setup_irq(epittm->irq, act);
+}
+
+static int __init epit_timer_init(struct device_node *np)
+{
+	struct epit_timer *epittm;
+	int ret;
+
+	epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
+	if (!epittm)
+		return -ENOMEM;
+
+	epittm->base = of_iomap(np, 0);
+	if (!epittm->base) {
+		ret = -ENXIO;
+		goto out_kfree;
+	}
+
+	epittm->irq = irq_of_parse_and_map(np, 0);
+	if (!epittm->irq) {
+		ret = -EINVAL;
+		goto out_iounmap;
+	}
+
+	/* Get EPIT clock */
+	epittm->clk = of_clk_get(np, 0);
+	if (IS_ERR(epittm->clk)) {
+		pr_err("i.MX EPIT: unable to get clk\n");
+		ret = PTR_ERR(epittm->clk);
+		goto out_iounmap;
+	}
+
+	ret = clk_prepare_enable(epittm->clk);
+	if (ret) {
+		pr_err("i.MX EPIT: unable to prepare+enable clk\n");
+		goto out_iounmap;
+	}
+
+	/* Initialise to a known state (all timers off, and timing reset) */
+	writel_relaxed(0x0, epittm->base + EPITCR);
+	writel_relaxed(0xffffffff, epittm->base + EPITLR);
+	writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
+		       epittm->base + EPITCR);
+
+	ret = epit_clocksource_init(epittm);
+	if (ret) {
+		pr_err("i.MX EPIT: failed to init clocksource\n");
+		goto out_clk_disable;
+	}
+
+	ret = epit_clockevent_init(epittm);
+	if (ret) {
+		pr_err("i.MX EPIT: failed to init clockevent\n");
+		goto out_clk_disable;
+	}
+
+	return 0;
+
+out_clk_disable:
+	clk_disable_unprepare(epittm->clk);
+out_iounmap:
+	iounmap(epittm->base);
+out_kfree:
+	kfree(epittm);
+
+	return ret;
+}
+TIMER_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit_timer_init);
-- 
2.17.1

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

* [PATCH v7 5/5] ARM: dts: imx: add missing compatible and clock properties for EPIT
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
                   ` (3 preceding siblings ...)
  2018-06-11 15:50 ` [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer Clément Péron
@ 2018-06-11 15:50 ` Clément Péron
  2018-07-10 14:55 ` [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
  5 siblings, 0 replies; 17+ messages in thread
From: Clément Péron @ 2018-06-11 15:50 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

From: Colin Didier <colin.didier@devialet.com>

Add missing compatible and clock properties for EPIT node.

Signed-off-by: Colin Didier <colin.didier@devialet.com>
Signed-off-by: Clément Peron <clement.peron@devialet.com>
Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
---
 arch/arm/boot/dts/imx25.dtsi   |  8 ++++++--
 arch/arm/boot/dts/imx6qdl.dtsi | 10 ++++++++--
 arch/arm/boot/dts/imx6sl.dtsi  | 10 ++++++++--
 arch/arm/boot/dts/imx6sx.dtsi  | 10 ++++++++--
 arch/arm/boot/dts/imx6ul.dtsi  | 10 ++++++++--
 5 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi
index cf70df20b19c..15fd4308dad8 100644
--- a/arch/arm/boot/dts/imx25.dtsi
+++ b/arch/arm/boot/dts/imx25.dtsi
@@ -396,15 +396,19 @@
 			};
 
 			epit1: timer@53f94000 {
-				compatible = "fsl,imx25-epit";
+				compatible = "fsl,imx25-epit", "fsl,imx31-epit";
 				reg = <0x53f94000 0x4000>;
 				interrupts = <28>;
+				clocks = <&clks 83>;
+				status = "disabled";
 			};
 
 			epit2: timer@53f98000 {
-				compatible = "fsl,imx25-epit";
+				compatible = "fsl,imx25-epit", "fsl,imx31-epit";
 				reg = <0x53f98000 0x4000>;
 				interrupts = <27>;
+				clocks = <&clks 84>;
+				status = "disabled";
 			};
 
 			gpio4: gpio@53f9c000 {
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index c003e62bf290..65c4ee07454c 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -843,14 +843,20 @@
 				};
 			};
 
-			epit1: epit@20d0000 { /* EPIT1 */
+			epit1: timer@20d0000 {
+				compatible = "fsl,imx6qdl-epit", "fsl,imx31-epit";
 				reg = <0x020d0000 0x4000>;
 				interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6QDL_CLK_EPIT1>;
+				status = "disabled";
 			};
 
-			epit2: epit@20d4000 { /* EPIT2 */
+			epit2: timer@20d4000 {
+				compatible = "fsl,imx6qdl-epit", "fsl,imx31-epit";
 				reg = <0x020d4000 0x4000>;
 				interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6QDL_CLK_EPIT2>;
+				status = "disabled";
 			};
 
 			src: src@20d8000 {
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index ab6a7e2e7e8f..d63f8ebbc8a1 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -671,14 +671,20 @@
 				};
 			};
 
-			epit1: epit@20d0000 {
+			epit1: timer@20d0000 {
+				compatible = "fsl,imx6sl-epit", "fsl,imx31-epit";
 				reg = <0x020d0000 0x4000>;
 				interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6SL_CLK_EPIT1>;
+				status = "disabled";
 			};
 
-			epit2: epit@20d4000 {
+			epit2: timer@20d4000 {
+				compatible = "fsl,imx6sl-epit", "fsl,imx31-epit";
 				reg = <0x020d4000 0x4000>;
 				interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6SL_CLK_EPIT2>;
+				status = "disabled";
 			};
 
 			src: src@20d8000 {
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 49c7205b8db8..2b30559d3270 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -736,14 +736,20 @@
 				};
 			};
 
-			epit1: epit@20d0000 {
+			epit1: timer@20d0000 {
+				compatible = "fsl,imx6sx-epit", "fsl,imx31-epit";
 				reg = <0x020d0000 0x4000>;
 				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6SX_CLK_EPIT1>;
+				status = "disabled";
 			};
 
-			epit2: epit@20d4000 {
+			epit2: timer@20d4000 {
+				compatible = "fsl,imx6sx-epit", "fsl,imx31-epit";
 				reg = <0x020d4000 0x4000>;
 				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6SX_CLK_EPIT2>;
+				status = "disabled";
 			};
 
 			src: src@20d8000 {
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 1241972b16ba..d5f765da1ee2 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -658,14 +658,20 @@
 				};
 			};
 
-			epit1: epit@20d0000 {
+			epit1: timer@20d0000 {
+				compatible = "fsl,imx6ul-epit", "fsl,imx31-epit";
 				reg = <0x020d0000 0x4000>;
 				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6UL_CLK_EPIT1>;
+				status = "disabled";
 			};
 
-			epit2: epit@20d4000 {
+			epit2: timer@20d4000 {
+				compatible = "fsl,imx6ul-epit", "fsl,imx31-epit";
 				reg = <0x020d4000 0x4000>;
 				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks IMX6UL_CLK_EPIT2>;
+				status = "disabled";
 			};
 
 			src: src@20d8000 {
-- 
2.17.1

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

* Re: [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding
  2018-06-11 15:49 ` [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding Clément Péron
@ 2018-06-12 18:27   ` Rob Herring
  0 siblings, 0 replies; 17+ messages in thread
From: Rob Herring @ 2018-06-12 18:27 UTC (permalink / raw)
  To: Clément Péron
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

On Mon, Jun 11, 2018 at 05:49:59PM +0200, Clément Péron wrote:
> From: Clément Peron <clement.peron@devialet.com>
> 
> Add devicetree binding document for NXP's i.MX SoC specific
> EPIT timer driver.
> 
> Signed-off-by: Clément Peron <clement.peron@devialet.com>
> Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
>  .../devicetree/bindings/timer/fsl,imxepit.txt | 21 +++++++++++++++++++
>  1 file changed, 21 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/fsl,imxepit.txt

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
                   ` (4 preceding siblings ...)
  2018-06-11 15:50 ` [PATCH v7 5/5] ARM: dts: imx: add missing compatible and clock properties for EPIT Clément Péron
@ 2018-07-10 14:55 ` Clément Péron
  2018-07-10 14:58   ` Daniel Lezcano
  2018-07-10 15:12   ` Daniel Lezcano
  5 siblings, 2 replies; 17+ messages in thread
From: Clément Péron @ 2018-07-10 14:55 UTC (permalink / raw)
  To: Colin Didier, linux-arm-kernel, devicetree, linux-kernel
  Cc: Stefan Agner, Daniel Lezcano, Thomas Gleixner, Fabio Estevam,
	Vladimir Zapolskiy, Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

Hi,

Is there still some remark against merging this ?

Thanks,
Clement

On Mon, 11 Jun 2018 at 17:50, Clément Péron <peron.clem@gmail.com> wrote:
>
> From: Clément Peron <clement.peron@devialet.com>
>
> As suggested in the commit message we have added the device tree support,
> proper bindings and we moved the driver into the correct folder.
>
> Moreover we made some changes like use of relaxed IO accesor,
> implement sched_clock, delay_timer and reduce the clockevents min_delta.
>
> Changes since v6:
> -fix indent
>
> Changes since v5:
> - change epit to timer in doc example
> - fix typo in imx6sl.dtsi
>
> Changes since v4:
> - removed ipg clk
> - change in dt epit to timer
> - add introduction in doc
> - add all compatibles in doc
> - update epit entry for other i.MX device-trees
>
> Changes since v3:
> - Clean Kconfig
> - Rename imx6q-epit to imx31-epit
> - Update doc and bindings
> - Indent and fix
>
> Changes since v2 (Thanks Fabio Estevam):
> - Removed unused ckil clock
> - Add out_iounmap
> - Check and handle if clk_prepare_enable failed
> - Fix comment typo
>
> Changes since v1 (Thanks Vladimir Zapolskiy):
> - Add OF dependency in Kconfig
> - Sort header
> - Use BIT macro
> - Remove useless comments
> - Fix incorrect indent
> - Fix memory leak
> - Add check and handle possible returned error
>
> Clément Peron (2):
>   ARM: imx: remove inexistant EPIT timer init
>   dt-bindings: timer: add i.MX EPIT timer binding
>
> Colin Didier (3):
>   clk: imx6: add EPIT clock support
>   clocksource: add driver for i.MX EPIT timer
>   ARM: dts: imx: add missing compatible and clock properties for EPIT
>
>  .../devicetree/bindings/timer/fsl,imxepit.txt |  21 ++
>  arch/arm/boot/dts/imx25.dtsi                  |   8 +-
>  arch/arm/boot/dts/imx6qdl.dtsi                |  10 +-
>  arch/arm/boot/dts/imx6sl.dtsi                 |  10 +-
>  arch/arm/boot/dts/imx6sx.dtsi                 |  10 +-
>  arch/arm/boot/dts/imx6ul.dtsi                 |  10 +-
>  arch/arm/mach-imx/common.h                    |   1 -
>  drivers/clk/imx/clk-imx6q.c                   |   2 +
>  drivers/clocksource/Kconfig                   |  11 +
>  drivers/clocksource/Makefile                  |   1 +
>  drivers/clocksource/timer-imx-epit.c          | 265 ++++++++++++++++++
>  include/dt-bindings/clock/imx6qdl-clock.h     |   4 +-
>  12 files changed, 341 insertions(+), 12 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/timer/fsl,imxepit.txt
>  create mode 100644 drivers/clocksource/timer-imx-epit.c
>
> --
> 2.17.1
>

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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-07-10 14:55 ` [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
@ 2018-07-10 14:58   ` Daniel Lezcano
  2018-07-10 15:12   ` Daniel Lezcano
  1 sibling, 0 replies; 17+ messages in thread
From: Daniel Lezcano @ 2018-07-10 14:58 UTC (permalink / raw)
  To: Clément Péron, Colin Didier, linux-arm-kernel,
	devicetree, linux-kernel
  Cc: Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

On 10/07/2018 16:55, Clément Péron wrote:
> Hi,
> 
> Is there still some remark against merging this ?

Thanks for the heads up.


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


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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-07-10 14:55 ` [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
  2018-07-10 14:58   ` Daniel Lezcano
@ 2018-07-10 15:12   ` Daniel Lezcano
  2018-07-10 15:22     ` Clément Péron
  1 sibling, 1 reply; 17+ messages in thread
From: Daniel Lezcano @ 2018-07-10 15:12 UTC (permalink / raw)
  To: Clément Péron, Colin Didier, linux-arm-kernel,
	devicetree, linux-kernel
  Cc: Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

On 10/07/2018 16:55, Clément Péron wrote:
> Hi,
> 
> Is there still some remark against merging this ?

How do you want this to be merged ?

Shall I take the two patches related to the timer ? Or Ack them ?

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


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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-07-10 15:12   ` Daniel Lezcano
@ 2018-07-10 15:22     ` Clément Péron
  2018-07-10 15:37       ` Daniel Lezcano
  0 siblings, 1 reply; 17+ messages in thread
From: Clément Péron @ 2018-07-10 15:22 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

Hi Daniel,

On Tue, 10 Jul 2018 at 17:12, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>
> On 10/07/2018 16:55, Clément Péron wrote:
> > Hi,
> >
> > Is there still some remark against merging this ?
>
> How do you want this to be merged ?
>
> Shall I take the two patches related to the timer ? Or Ack them ?

I'm not an expert on how submitting patches works, it's the first
driver I submit.

But as this has been tested and no NXP team member seems against I
would be happy to see this patch merged.

Thanks,
Clement

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

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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-07-10 15:22     ` Clément Péron
@ 2018-07-10 15:37       ` Daniel Lezcano
  2018-07-10 16:05         ` Clément Péron
  0 siblings, 1 reply; 17+ messages in thread
From: Daniel Lezcano @ 2018-07-10 15:37 UTC (permalink / raw)
  To: Clément Péron
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

On 10/07/2018 17:22, Clément Péron wrote:
> Hi Daniel,
> 
> On Tue, 10 Jul 2018 at 17:12, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>>
>> On 10/07/2018 16:55, Clément Péron wrote:
>>> Hi,
>>>
>>> Is there still some remark against merging this ?
>>
>> How do you want this to be merged ?
>>
>> Shall I take the two patches related to the timer ? Or Ack them ?
> 
> I'm not an expert on how submitting patches works, it's the first
> driver I submit.

Ok, so usually this is what happens when there is a set of changes:

 1.  they all touch the same subsystem (eg. drivers/clocksource), you
just send all the patches to the maintainer(s) + mailing list + related
people

 2. they touch different subsystems:

   2.1) the changes are not connected (not related together), you have
to split in smaller parts and send the patches to the right subsystem
maintainer (so falling back to 1.)

   2.2) the changes are connected:

      2.2.1) Ask all the different subsystem maintainers to acknowledge
the changes and submit the patches to arm-soc@

      2.2.2) Ask each maintainer to take their part if the changes are
connected but not interdependent (patches individually won't break the
system)


You are in the 2.2) situation. My question is do you want 2.2.1) or 2.2.2) ?


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


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

* Re: [PATCH v7 0/5] Reintroduce i.MX EPIT Timer
  2018-07-10 15:37       ` Daniel Lezcano
@ 2018-07-10 16:05         ` Clément Péron
  0 siblings, 0 replies; 17+ messages in thread
From: Clément Péron @ 2018-07-10 16:05 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

HI Daniel,


On Tue, 10 Jul 2018 at 17:37, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>
> On 10/07/2018 17:22, Clément Péron wrote:
> > Hi Daniel,
> >
> > On Tue, 10 Jul 2018 at 17:12, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
> >>
> >> On 10/07/2018 16:55, Clément Péron wrote:
> >>> Hi,
> >>>
> >>> Is there still some remark against merging this ?
> >>
> >> How do you want this to be merged ?
> >>
> >> Shall I take the two patches related to the timer ? Or Ack them ?
> >
> > I'm not an expert on how submitting patches works, it's the first
> > driver I submit.
>
> Ok, so usually this is what happens when there is a set of changes:
>
>  1.  they all touch the same subsystem (eg. drivers/clocksource), you
> just send all the patches to the maintainer(s) + mailing list + related
> people
>
>  2. they touch different subsystems:
>
>    2.1) the changes are not connected (not related together), you have
> to split in smaller parts and send the patches to the right subsystem
> maintainer (so falling back to 1.)
>
>    2.2) the changes are connected:
>
>       2.2.1) Ask all the different subsystem maintainers to acknowledge
> the changes and submit the patches to arm-soc@
>
>       2.2.2) Ask each maintainer to take their part if the changes are
> connected but not interdependent (patches individually won't break the
> system)
>
>
> You are in the 2.2) situation. My question is do you want 2.2.1) or 2.2.2) ?

Thanks for the explanation, I think in 2.2.1 as I still need an Ack
for the "ARM: dts" patch

Regards,
Clement

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

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

* Re: [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer
  2018-06-11 15:50 ` [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer Clément Péron
@ 2018-07-10 16:20   ` Daniel Lezcano
  2018-11-04 16:07     ` Clément Péron
  0 siblings, 1 reply; 17+ messages in thread
From: Daniel Lezcano @ 2018-07-10 16:20 UTC (permalink / raw)
  To: Clément Péron, Colin Didier, linux-arm-kernel,
	devicetree, linux-kernel
  Cc: Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team, Clément Peron

On 11/06/2018 17:50, Clément Péron wrote:
> From: Colin Didier <colin.didier@devialet.com>
> 
> Add driver for NXP's EPIT timer used in i.MX SoC.

Give a description on how works this timer.


> Signed-off-by: Colin Didier <colin.didier@devialet.com>
> Signed-off-by: Clément Peron <clement.peron@devialet.com>
> Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> Tested-by: Vladimir Zapolskiy <vz@mleia.com>
> ---
>  drivers/clocksource/Kconfig          |  11 ++
>  drivers/clocksource/Makefile         |   1 +
>  drivers/clocksource/timer-imx-epit.c | 265 +++++++++++++++++++++++++++
>  3 files changed, 277 insertions(+)
>  create mode 100644 drivers/clocksource/timer-imx-epit.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 8e8a09755d10..790478afd02c 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -576,6 +576,17 @@ config H8300_TPU
>  	  This enables the clocksource for the H8300 platform with the
>  	  H8S2678 cpu.
>  
> +config CLKSRC_IMX_EPIT
> +	bool "Clocksource using i.MX EPIT"
> +	depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
> +	select CLKSRC_MMIO
> +	help
> +	  This enables EPIT support available on some i.MX platforms.
> +	  Normally you don't have a reason to do so as the EPIT has
> +	  the same features and uses the same clocks as the GPT.
> +	  Anyway, on some systems the GPT may be in use for other
> +	  purposes.
> +
>  config CLKSRC_IMX_GPT
>  	bool "Clocksource using i.MX GPT" if COMPILE_TEST
>  	depends on ARM && CLKDEV_LOOKUP
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 00caf37e52f9..d9426f69ec69 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER)	+= timer-integrator-ap.o
>  obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
>  obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
>  obj-$(CONFIG_CLKSRC_TANGO_XTAL)		+= tango_xtal.o
> +obj-$(CONFIG_CLKSRC_IMX_EPIT)		+= timer-imx-epit.o
>  obj-$(CONFIG_CLKSRC_IMX_GPT)		+= timer-imx-gpt.o
>  obj-$(CONFIG_CLKSRC_IMX_TPM)		+= timer-imx-tpm.o
>  obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
> diff --git a/drivers/clocksource/timer-imx-epit.c b/drivers/clocksource/timer-imx-epit.c
> new file mode 100644
> index 000000000000..7f1c8e2e00aa
> --- /dev/null
> +++ b/drivers/clocksource/timer-imx-epit.c
> @@ -0,0 +1,265 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * i.MX EPIT Timer
> + *
> + * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
> + * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
> + * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/sched_clock.h>
> +#include <linux/slab.h>
> +
> +#define EPITCR				0x00
> +#define EPITSR				0x04
> +#define EPITLR				0x08
> +#define EPITCMPR			0x0c
> +#define EPITCNR				0x10
> +
> +#define EPITCR_EN			BIT(0)
> +#define EPITCR_ENMOD			BIT(1)
> +#define EPITCR_OCIEN			BIT(2)
> +#define EPITCR_RLD			BIT(3)
> +#define EPITCR_PRESC(x)			(((x) & 0xfff) << 4)
> +#define EPITCR_SWR			BIT(16)
> +#define EPITCR_IOVW			BIT(17)
> +#define EPITCR_DBGEN			BIT(18)
> +#define EPITCR_WAITEN			BIT(19)
> +#define EPITCR_RES			BIT(20)
> +#define EPITCR_STOPEN			BIT(21)
> +#define EPITCR_OM_DISCON		(0 << 22)
> +#define EPITCR_OM_TOGGLE		(1 << 22)
> +#define EPITCR_OM_CLEAR			(2 << 22)
> +#define EPITCR_OM_SET			(3 << 22)
> +#define EPITCR_CLKSRC_OFF		(0 << 24)
> +#define EPITCR_CLKSRC_PERIPHERAL	(1 << 24)
> +#define EPITCR_CLKSRC_REF_HIGH		(2 << 24)
> +#define EPITCR_CLKSRC_REF_LOW		(3 << 24)
> +
> +#define EPITSR_OCIF			BIT(0)
> +
> +struct epit_timer {
> +	void __iomem *base;
> +	int irq;
> +	struct clk *clk;
> +	struct clock_event_device ced;
> +	struct irqaction act;
> +};
> +
> +static void __iomem *sched_clock_reg;
> +
> +static inline struct epit_timer *to_epit_timer(struct clock_event_device *ced)
> +{
> +	return container_of(ced, struct epit_timer, ced);
> +}
> +
> +static inline void epit_irq_disable(struct epit_timer *epittm)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(epittm->base + EPITCR);
> +	writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
> +}
> +
> +static inline void epit_irq_enable(struct epit_timer *epittm)
> +{
> +	u32 val;
> +
> +	val = readl_relaxed(epittm->base + EPITCR);
> +	writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
> +}
> +
> +static void epit_irq_acknowledge(struct epit_timer *epittm)
> +{
> +	writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
> +}
> +
> +static u64 notrace epit_read_sched_clock(void)
> +{
> +	return ~readl_relaxed(sched_clock_reg);
> +}
> +
> +static int epit_set_next_event(unsigned long cycles,
> +			       struct clock_event_device *ced)
> +{
> +	struct epit_timer *epittm = to_epit_timer(ced);
> +	unsigned long tcmp;
> +
> +	tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
> +	writel_relaxed(tcmp, epittm->base + EPITCMPR);
> +
> +	return 0;
> +}
> +
> +/* Left event sources disabled, no more interrupts appear */
> +static int epit_shutdown(struct clock_event_device *ced)
> +{
> +	struct epit_timer *epittm = to_epit_timer(ced);
> +	unsigned long flags;
> +
> +	/*
> +	 * The timer interrupt generation is disabled at least
> +	 * for enough time to call epit_set_next_event()
> +	 */
> +	local_irq_save(flags);

This is not necessary. This function is called with interrupt disabled.

> +	/* Disable interrupt in EPIT module */
> +	epit_irq_disable(epittm);
> +
> +	/* Clear pending interrupt */
> +	epit_irq_acknowledge(epittm);

No irq ack is needed here. Neither disabling the interrupt.

Why not just stop the counter ?

> +	local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static int epit_set_oneshot(struct clock_event_device *ced)
> +{
> +	struct epit_timer *epittm = to_epit_timer(ced);
> +	unsigned long flags;
> +
> +	/*
> +	 * The timer interrupt generation is disabled at least
> +	 * for enough time to call epit_set_next_event()
> +	 */
> +	local_irq_save(flags);

This is not necessary. This function is called with interrupt disabled.

> +	/* Disable interrupt in EPIT module */
> +	epit_irq_disable(epittm);
> +
> +	/* Clear pending interrupt, only while switching mode */
> +	if (!clockevent_state_oneshot(ced))
> +		epit_irq_acknowledge(epittm);

Why do you need to ack the interrupt here ?

> +	/*
> +	 * Do not put overhead of interrupt enable/disable into
> +	 * epit_set_next_event(), the core has about 4 minutes
> +	 * to call epit_set_next_event() or shutdown clock after
> +	 * mode switching
> +	 */
> +	epit_irq_enable(epittm);
> +	local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *ced = dev_id;
> +	struct epit_timer *epittm = to_epit_timer(ced);
> +
> +	epit_irq_acknowledge(epittm);
> +
> +	ced->event_handler(ced);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int __init epit_clocksource_init(struct epit_timer *epittm)
> +{
> +	unsigned int c = clk_get_rate(epittm->clk);
> +
> +	sched_clock_reg = epittm->base + EPITCNR;
> +	sched_clock_register(epit_read_sched_clock, 32, c);
> +
> +	return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c, 200, 32,
> +				     clocksource_mmio_readl_down);
> +}
> +
> +static int __init epit_clockevent_init(struct epit_timer *epittm)
> +{
> +	struct clock_event_device *ced = &epittm->ced;
> +	struct irqaction *act = &epittm->act;
> +
> +	ced->name = "epit";
> +	ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
> +	ced->set_state_shutdown = epit_shutdown;
> +	ced->tick_resume = epit_shutdown;
> +	ced->set_state_oneshot = epit_set_oneshot;
> +	ced->set_next_event = epit_set_next_event;
> +	ced->rating = 200;
> +	ced->cpumask = cpumask_of(0);
> +	ced->irq = epittm->irq;
> +	clockevents_config_and_register(ced, clk_get_rate(epittm->clk),
> +					0xff, 0xfffffffe);
> +
> +	act->name = "i.MX EPIT Timer Tick",
> +	act->flags = IRQF_TIMER | IRQF_IRQPOLL;
> +	act->handler = epit_timer_interrupt;
> +	act->dev_id = ced;
> +
> +	/* Make irqs happen */
> +	return setup_irq(epittm->irq, act);
> +}
> +
> +static int __init epit_timer_init(struct device_node *np)
> +{
> +	struct epit_timer *epittm;
> +	int ret;
> +
> +	epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
> +	if (!epittm)
> +		return -ENOMEM;
> +
> +	epittm->base = of_iomap(np, 0);
> +	if (!epittm->base) {
> +		ret = -ENXIO;
> +		goto out_kfree;
> +	}
> +
> +	epittm->irq = irq_of_parse_and_map(np, 0);
> +	if (!epittm->irq) {
> +		ret = -EINVAL;
> +		goto out_iounmap;
> +	}
> +
> +	/* Get EPIT clock */
> +	epittm->clk = of_clk_get(np, 0);
> +	if (IS_ERR(epittm->clk)) {
> +		pr_err("i.MX EPIT: unable to get clk\n");
> +		ret = PTR_ERR(epittm->clk);
> +		goto out_iounmap;
> +	}
> +
> +	ret = clk_prepare_enable(epittm->clk);
> +	if (ret) {
> +		pr_err("i.MX EPIT: unable to prepare+enable clk\n");
> +		goto out_iounmap;
> +	}

Please replace all the above with the timer-of API as:

https://patchwork.kernel.org/patch/10510443/


> +	/* Initialise to a known state (all timers off, and timing reset) */
> +	writel_relaxed(0x0, epittm->base + EPITCR);
> +	writel_relaxed(0xffffffff, epittm->base + EPITLR);
> +	writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
> +		       epittm->base + EPITCR);
> +
> +	ret = epit_clocksource_init(epittm);
> +	if (ret) {
> +		pr_err("i.MX EPIT: failed to init clocksource\n");
> +		goto out_clk_disable;
> +	}
> +
> +	ret = epit_clockevent_init(epittm);
> +	if (ret) {
> +		pr_err("i.MX EPIT: failed to init clockevent\n");
> +		goto out_clk_disable;
> +	}
> +
> +	return 0;
> +
> +out_clk_disable:
> +	clk_disable_unprepare(epittm->clk);
> +out_iounmap:
> +	iounmap(epittm->base);
> +out_kfree:
> +	kfree(epittm);
> +
> +	return ret;
> +}
> +TIMER_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit_timer_init);
> 


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


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

* Re: [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer
  2018-07-10 16:20   ` Daniel Lezcano
@ 2018-11-04 16:07     ` Clément Péron
  2018-11-05 11:48       ` Daniel Lezcano
  0 siblings, 1 reply; 17+ messages in thread
From: Clément Péron @ 2018-11-04 16:07 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team

Hi Daniel,

Thanks for the review and sorry for the delay.

On Tue, 10 Jul 2018 at 18:20, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>
> On 11/06/2018 17:50, Clément Péron wrote:
> > From: Colin Didier <colin.didier@devialet.com>
> >
> > Add driver for NXP's EPIT timer used in i.MX SoC.
>
> Give a description on how works this timer.
Ok,

>
>
> > Signed-off-by: Colin Didier <colin.didier@devialet.com>
> > Signed-off-by: Clément Peron <clement.peron@devialet.com>
> > Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> > Tested-by: Vladimir Zapolskiy <vz@mleia.com>
> > ---
> >  drivers/clocksource/Kconfig          |  11 ++
> >  drivers/clocksource/Makefile         |   1 +
> >  drivers/clocksource/timer-imx-epit.c | 265 +++++++++++++++++++++++++++
> >  3 files changed, 277 insertions(+)
> >  create mode 100644 drivers/clocksource/timer-imx-epit.c
> >
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index 8e8a09755d10..790478afd02c 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -576,6 +576,17 @@ config H8300_TPU
> >         This enables the clocksource for the H8300 platform with the
> >         H8S2678 cpu.
> >
> > +config CLKSRC_IMX_EPIT
> > +     bool "Clocksource using i.MX EPIT"
> > +     depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
> > +     select CLKSRC_MMIO
> > +     help
> > +       This enables EPIT support available on some i.MX platforms.
> > +       Normally you don't have a reason to do so as the EPIT has
> > +       the same features and uses the same clocks as the GPT.
> > +       Anyway, on some systems the GPT may be in use for other
> > +       purposes.
> > +
> >  config CLKSRC_IMX_GPT
> >       bool "Clocksource using i.MX GPT" if COMPILE_TEST
> >       depends on ARM && CLKDEV_LOOKUP
> > diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> > index 00caf37e52f9..d9426f69ec69 100644
> > --- a/drivers/clocksource/Makefile
> > +++ b/drivers/clocksource/Makefile
> > @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER)   += timer-integrator-ap.o
> >  obj-$(CONFIG_CLKSRC_VERSATILE)               += versatile.o
> >  obj-$(CONFIG_CLKSRC_MIPS_GIC)                += mips-gic-timer.o
> >  obj-$(CONFIG_CLKSRC_TANGO_XTAL)              += tango_xtal.o
> > +obj-$(CONFIG_CLKSRC_IMX_EPIT)                += timer-imx-epit.o
> >  obj-$(CONFIG_CLKSRC_IMX_GPT)         += timer-imx-gpt.o
> >  obj-$(CONFIG_CLKSRC_IMX_TPM)         += timer-imx-tpm.o
> >  obj-$(CONFIG_ASM9260_TIMER)          += asm9260_timer.o
> > diff --git a/drivers/clocksource/timer-imx-epit.c b/drivers/clocksource/timer-imx-epit.c
> > new file mode 100644
> > index 000000000000..7f1c8e2e00aa
> > --- /dev/null
> > +++ b/drivers/clocksource/timer-imx-epit.c
> > @@ -0,0 +1,265 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * i.MX EPIT Timer
> > + *
> > + * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
> > + * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
> > + * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/clockchips.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/sched_clock.h>
> > +#include <linux/slab.h>
> > +
> > +#define EPITCR                               0x00
> > +#define EPITSR                               0x04
> > +#define EPITLR                               0x08
> > +#define EPITCMPR                     0x0c
> > +#define EPITCNR                              0x10
> > +
> > +#define EPITCR_EN                    BIT(0)
> > +#define EPITCR_ENMOD                 BIT(1)
> > +#define EPITCR_OCIEN                 BIT(2)
> > +#define EPITCR_RLD                   BIT(3)
> > +#define EPITCR_PRESC(x)                      (((x) & 0xfff) << 4)
> > +#define EPITCR_SWR                   BIT(16)
> > +#define EPITCR_IOVW                  BIT(17)
> > +#define EPITCR_DBGEN                 BIT(18)
> > +#define EPITCR_WAITEN                        BIT(19)
> > +#define EPITCR_RES                   BIT(20)
> > +#define EPITCR_STOPEN                        BIT(21)
> > +#define EPITCR_OM_DISCON             (0 << 22)
> > +#define EPITCR_OM_TOGGLE             (1 << 22)
> > +#define EPITCR_OM_CLEAR                      (2 << 22)
> > +#define EPITCR_OM_SET                        (3 << 22)
> > +#define EPITCR_CLKSRC_OFF            (0 << 24)
> > +#define EPITCR_CLKSRC_PERIPHERAL     (1 << 24)
> > +#define EPITCR_CLKSRC_REF_HIGH               (2 << 24)
> > +#define EPITCR_CLKSRC_REF_LOW                (3 << 24)
> > +
> > +#define EPITSR_OCIF                  BIT(0)
> > +
> > +struct epit_timer {
> > +     void __iomem *base;
> > +     int irq;
> > +     struct clk *clk;
> > +     struct clock_event_device ced;
> > +     struct irqaction act;
> > +};
> > +
> > +static void __iomem *sched_clock_reg;
> > +
> > +static inline struct epit_timer *to_epit_timer(struct clock_event_device *ced)
> > +{
> > +     return container_of(ced, struct epit_timer, ced);
> > +}
> > +
> > +static inline void epit_irq_disable(struct epit_timer *epittm)
> > +{
> > +     u32 val;
> > +
> > +     val = readl_relaxed(epittm->base + EPITCR);
> > +     writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
> > +}
> > +
> > +static inline void epit_irq_enable(struct epit_timer *epittm)
> > +{
> > +     u32 val;
> > +
> > +     val = readl_relaxed(epittm->base + EPITCR);
> > +     writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
> > +}
> > +
> > +static void epit_irq_acknowledge(struct epit_timer *epittm)
> > +{
> > +     writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
> > +}
> > +
> > +static u64 notrace epit_read_sched_clock(void)
> > +{
> > +     return ~readl_relaxed(sched_clock_reg);
> > +}
> > +
> > +static int epit_set_next_event(unsigned long cycles,
> > +                            struct clock_event_device *ced)
> > +{
> > +     struct epit_timer *epittm = to_epit_timer(ced);
> > +     unsigned long tcmp;
> > +
> > +     tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
> > +     writel_relaxed(tcmp, epittm->base + EPITCMPR);
> > +
> > +     return 0;
> > +}
> > +
> > +/* Left event sources disabled, no more interrupts appear */
> > +static int epit_shutdown(struct clock_event_device *ced)
> > +{
> > +     struct epit_timer *epittm = to_epit_timer(ced);
> > +     unsigned long flags;
> > +
> > +     /*
> > +      * The timer interrupt generation is disabled at least
> > +      * for enough time to call epit_set_next_event()
> > +      */
> > +     local_irq_save(flags);
>
> This is not necessary. This function is called with interrupt disabled.

I took this from the i.MX GPT Timer :
https://elixir.bootlin.com/linux/latest/source/drivers/clocksource/timer-imx-gpt.c#L208

Do you think i should also fix on the imx gpt timer ?

>
> > +     /* Disable interrupt in EPIT module */
> > +     epit_irq_disable(epittm);
> > +
> > +     /* Clear pending interrupt */
> > +     epit_irq_acknowledge(epittm);
>
> No irq ack is needed here. Neither disabling the interrupt.
Is it done by the framework ?

I took also this from the IMX GPT driver

>
> Why not just stop the counter ?
I will check the datasheet.
>
> > +     local_irq_restore(flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static int epit_set_oneshot(struct clock_event_device *ced)
> > +{
> > +     struct epit_timer *epittm = to_epit_timer(ced);
> > +     unsigned long flags;
> > +
> > +     /*
> > +      * The timer interrupt generation is disabled at least
> > +      * for enough time to call epit_set_next_event()
> > +      */
> > +     local_irq_save(flags);
>
> This is not necessary. This function is called with interrupt disabled.
>
> > +     /* Disable interrupt in EPIT module */
> > +     epit_irq_disable(epittm);
> > +
> > +     /* Clear pending interrupt, only while switching mode */
> > +     if (!clockevent_state_oneshot(ced))
> > +             epit_irq_acknowledge(epittm);
>
> Why do you need to ack the interrupt here ?
>
> > +     /*
> > +      * Do not put overhead of interrupt enable/disable into
> > +      * epit_set_next_event(), the core has about 4 minutes
> > +      * to call epit_set_next_event() or shutdown clock after
> > +      * mode switching
> > +      */
> > +     epit_irq_enable(epittm);
> > +     local_irq_restore(flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
> > +{
> > +     struct clock_event_device *ced = dev_id;
> > +     struct epit_timer *epittm = to_epit_timer(ced);
> > +
> > +     epit_irq_acknowledge(epittm);
> > +
> > +     ced->event_handler(ced);
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +static int __init epit_clocksource_init(struct epit_timer *epittm)
> > +{
> > +     unsigned int c = clk_get_rate(epittm->clk);
> > +
> > +     sched_clock_reg = epittm->base + EPITCNR;
> > +     sched_clock_register(epit_read_sched_clock, 32, c);
> > +
> > +     return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c, 200, 32,
> > +                                  clocksource_mmio_readl_down);
> > +}
> > +
> > +static int __init epit_clockevent_init(struct epit_timer *epittm)
> > +{
> > +     struct clock_event_device *ced = &epittm->ced;
> > +     struct irqaction *act = &epittm->act;
> > +
> > +     ced->name = "epit";
> > +     ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
> > +     ced->set_state_shutdown = epit_shutdown;
> > +     ced->tick_resume = epit_shutdown;
> > +     ced->set_state_oneshot = epit_set_oneshot;
> > +     ced->set_next_event = epit_set_next_event;
> > +     ced->rating = 200;
> > +     ced->cpumask = cpumask_of(0);
> > +     ced->irq = epittm->irq;
> > +     clockevents_config_and_register(ced, clk_get_rate(epittm->clk),
> > +                                     0xff, 0xfffffffe);
> > +
> > +     act->name = "i.MX EPIT Timer Tick",
> > +     act->flags = IRQF_TIMER | IRQF_IRQPOLL;
> > +     act->handler = epit_timer_interrupt;
> > +     act->dev_id = ced;
> > +
> > +     /* Make irqs happen */
> > +     return setup_irq(epittm->irq, act);
> > +}
> > +
> > +static int __init epit_timer_init(struct device_node *np)
> > +{
> > +     struct epit_timer *epittm;
> > +     int ret;
> > +
> > +     epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
> > +     if (!epittm)
> > +             return -ENOMEM;
> > +
> > +     epittm->base = of_iomap(np, 0);
> > +     if (!epittm->base) {
> > +             ret = -ENXIO;
> > +             goto out_kfree;
> > +     }
> > +
> > +     epittm->irq = irq_of_parse_and_map(np, 0);
> > +     if (!epittm->irq) {
> > +             ret = -EINVAL;
> > +             goto out_iounmap;
> > +     }
> > +
> > +     /* Get EPIT clock */
> > +     epittm->clk = of_clk_get(np, 0);
> > +     if (IS_ERR(epittm->clk)) {
> > +             pr_err("i.MX EPIT: unable to get clk\n");
> > +             ret = PTR_ERR(epittm->clk);
> > +             goto out_iounmap;
> > +     }
> > +
> > +     ret = clk_prepare_enable(epittm->clk);
> > +     if (ret) {
> > +             pr_err("i.MX EPIT: unable to prepare+enable clk\n");
> > +             goto out_iounmap;
> > +     }
>
> Please replace all the above with the timer-of API as:
Ok I will,

Thanks
Clement

>
> https://patchwork.kernel.org/patch/10510443/
>
>
> > +     /* Initialise to a known state (all timers off, and timing reset) */
> > +     writel_relaxed(0x0, epittm->base + EPITCR);
> > +     writel_relaxed(0xffffffff, epittm->base + EPITLR);
> > +     writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
> > +                    epittm->base + EPITCR);
> > +
> > +     ret = epit_clocksource_init(epittm);
> > +     if (ret) {
> > +             pr_err("i.MX EPIT: failed to init clocksource\n");
> > +             goto out_clk_disable;
> > +     }
> > +
> > +     ret = epit_clockevent_init(epittm);
> > +     if (ret) {
> > +             pr_err("i.MX EPIT: failed to init clockevent\n");
> > +             goto out_clk_disable;
> > +     }
> > +
> > +     return 0;
> > +
> > +out_clk_disable:
> > +     clk_disable_unprepare(epittm->clk);
> > +out_iounmap:
> > +     iounmap(epittm->base);
> > +out_kfree:
> > +     kfree(epittm);
> > +
> > +     return ret;
> > +}
> > +TIMER_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit_timer_init);
> >
>
>
> --
>  <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
>

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

* Re: [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer
  2018-11-04 16:07     ` Clément Péron
@ 2018-11-05 11:48       ` Daniel Lezcano
  2018-11-08 13:25         ` Clément Péron
  0 siblings, 1 reply; 17+ messages in thread
From: Daniel Lezcano @ 2018-11-05 11:48 UTC (permalink / raw)
  To: Clément Péron
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team


Hi Clément,

On 04/11/2018 17:07, Clément Péron wrote:
> Hi Daniel,
> 
> Thanks for the review and sorry for the delay.

no problem.

> On Tue, 10 Jul 2018 at 18:20, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>>
>> On 11/06/2018 17:50, Clément Péron wrote:
>>> From: Colin Didier <colin.didier@devialet.com>
>>>
>>> Add driver for NXP's EPIT timer used in i.MX SoC.
>>
>> Give a description on how works this timer.
> Ok,
> 
>>
>>
>>> Signed-off-by: Colin Didier <colin.didier@devialet.com>
>>> Signed-off-by: Clément Peron <clement.peron@devialet.com>
>>> Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
>>> Tested-by: Vladimir Zapolskiy <vz@mleia.com>
>>> ---
>>>  drivers/clocksource/Kconfig          |  11 ++
>>>  drivers/clocksource/Makefile         |   1 +
>>>  drivers/clocksource/timer-imx-epit.c | 265 +++++++++++++++++++++++++++
>>>  3 files changed, 277 insertions(+)
>>>  create mode 100644 drivers/clocksource/timer-imx-epit.c
>>>
>>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>>> index 8e8a09755d10..790478afd02c 100644
>>> --- a/drivers/clocksource/Kconfig
>>> +++ b/drivers/clocksource/Kconfig
>>> @@ -576,6 +576,17 @@ config H8300_TPU
>>>         This enables the clocksource for the H8300 platform with the
>>>         H8S2678 cpu.
>>>
>>> +config CLKSRC_IMX_EPIT
>>> +     bool "Clocksource using i.MX EPIT"
>>> +     depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
>>> +     select CLKSRC_MMIO
>>> +     help
>>> +       This enables EPIT support available on some i.MX platforms.
>>> +       Normally you don't have a reason to do so as the EPIT has
>>> +       the same features and uses the same clocks as the GPT.
>>> +       Anyway, on some systems the GPT may be in use for other
>>> +       purposes.
>>> +
>>>  config CLKSRC_IMX_GPT
>>>       bool "Clocksource using i.MX GPT" if COMPILE_TEST
>>>       depends on ARM && CLKDEV_LOOKUP
>>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>>> index 00caf37e52f9..d9426f69ec69 100644
>>> --- a/drivers/clocksource/Makefile
>>> +++ b/drivers/clocksource/Makefile
>>> @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER)   += timer-integrator-ap.o
>>>  obj-$(CONFIG_CLKSRC_VERSATILE)               += versatile.o
>>>  obj-$(CONFIG_CLKSRC_MIPS_GIC)                += mips-gic-timer.o
>>>  obj-$(CONFIG_CLKSRC_TANGO_XTAL)              += tango_xtal.o
>>> +obj-$(CONFIG_CLKSRC_IMX_EPIT)                += timer-imx-epit.o
>>>  obj-$(CONFIG_CLKSRC_IMX_GPT)         += timer-imx-gpt.o
>>>  obj-$(CONFIG_CLKSRC_IMX_TPM)         += timer-imx-tpm.o
>>>  obj-$(CONFIG_ASM9260_TIMER)          += asm9260_timer.o
>>> diff --git a/drivers/clocksource/timer-imx-epit.c b/drivers/clocksource/timer-imx-epit.c
>>> new file mode 100644
>>> index 000000000000..7f1c8e2e00aa
>>> --- /dev/null
>>> +++ b/drivers/clocksource/timer-imx-epit.c
>>> @@ -0,0 +1,265 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * i.MX EPIT Timer
>>> + *
>>> + * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
>>> + * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
>>> + * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/clockchips.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/sched_clock.h>
>>> +#include <linux/slab.h>
>>> +
>>> +#define EPITCR                               0x00
>>> +#define EPITSR                               0x04
>>> +#define EPITLR                               0x08
>>> +#define EPITCMPR                     0x0c
>>> +#define EPITCNR                              0x10
>>> +
>>> +#define EPITCR_EN                    BIT(0)
>>> +#define EPITCR_ENMOD                 BIT(1)
>>> +#define EPITCR_OCIEN                 BIT(2)
>>> +#define EPITCR_RLD                   BIT(3)
>>> +#define EPITCR_PRESC(x)                      (((x) & 0xfff) << 4)
>>> +#define EPITCR_SWR                   BIT(16)
>>> +#define EPITCR_IOVW                  BIT(17)
>>> +#define EPITCR_DBGEN                 BIT(18)
>>> +#define EPITCR_WAITEN                        BIT(19)
>>> +#define EPITCR_RES                   BIT(20)
>>> +#define EPITCR_STOPEN                        BIT(21)
>>> +#define EPITCR_OM_DISCON             (0 << 22)
>>> +#define EPITCR_OM_TOGGLE             (1 << 22)
>>> +#define EPITCR_OM_CLEAR                      (2 << 22)
>>> +#define EPITCR_OM_SET                        (3 << 22)
>>> +#define EPITCR_CLKSRC_OFF            (0 << 24)
>>> +#define EPITCR_CLKSRC_PERIPHERAL     (1 << 24)
>>> +#define EPITCR_CLKSRC_REF_HIGH               (2 << 24)
>>> +#define EPITCR_CLKSRC_REF_LOW                (3 << 24)
>>> +
>>> +#define EPITSR_OCIF                  BIT(0)
>>> +
>>> +struct epit_timer {
>>> +     void __iomem *base;
>>> +     int irq;
>>> +     struct clk *clk;
>>> +     struct clock_event_device ced;
>>> +     struct irqaction act;
>>> +};
>>> +
>>> +static void __iomem *sched_clock_reg;
>>> +
>>> +static inline struct epit_timer *to_epit_timer(struct clock_event_device *ced)
>>> +{
>>> +     return container_of(ced, struct epit_timer, ced);
>>> +}
>>> +
>>> +static inline void epit_irq_disable(struct epit_timer *epittm)
>>> +{
>>> +     u32 val;
>>> +
>>> +     val = readl_relaxed(epittm->base + EPITCR);
>>> +     writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
>>> +}
>>> +
>>> +static inline void epit_irq_enable(struct epit_timer *epittm)
>>> +{
>>> +     u32 val;
>>> +
>>> +     val = readl_relaxed(epittm->base + EPITCR);
>>> +     writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
>>> +}
>>> +
>>> +static void epit_irq_acknowledge(struct epit_timer *epittm)
>>> +{
>>> +     writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
>>> +}
>>> +
>>> +static u64 notrace epit_read_sched_clock(void)
>>> +{
>>> +     return ~readl_relaxed(sched_clock_reg);
>>> +}
>>> +
>>> +static int epit_set_next_event(unsigned long cycles,
>>> +                            struct clock_event_device *ced)
>>> +{
>>> +     struct epit_timer *epittm = to_epit_timer(ced);
>>> +     unsigned long tcmp;
>>> +
>>> +     tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
>>> +     writel_relaxed(tcmp, epittm->base + EPITCMPR);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +/* Left event sources disabled, no more interrupts appear */
>>> +static int epit_shutdown(struct clock_event_device *ced)
>>> +{
>>> +     struct epit_timer *epittm = to_epit_timer(ced);
>>> +     unsigned long flags;
>>> +
>>> +     /*
>>> +      * The timer interrupt generation is disabled at least
>>> +      * for enough time to call epit_set_next_event()
>>> +      */
>>> +     local_irq_save(flags);
>>
>> This is not necessary. This function is called with interrupt disabled.
> 
> I took this from the i.MX GPT Timer :
> https://elixir.bootlin.com/linux/latest/source/drivers/clocksource/timer-imx-gpt.c#L208
> 
> Do you think i should also fix on the imx gpt timer ?

Yes, the pointed code is 10 years old, so if you are willing to do the
changes in a separate patchset, that would be nice.

>>> +     /* Disable interrupt in EPIT module */
>>> +     epit_irq_disable(epittm);
>>> +
>>> +     /* Clear pending interrupt */
>>> +     epit_irq_acknowledge(epittm);
>>
>> No irq ack is needed here. Neither disabling the interrupt.
> Is it done by the framework ?
> 
> I took also this from the IMX GPT driver

If we reach this point of code with a pending timer interrupt, that
means it should be processed after the clockevent shutdown path is
finished. Otherwise it is like we cancel the timer on the back of the
system.

>> Why not just stop the counter ?
> I will check the datasheet.
>>> +     local_irq_restore(flags);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int epit_set_oneshot(struct clock_event_device *ced)
>>> +{
>>> +     struct epit_timer *epittm = to_epit_timer(ced);
>>> +     unsigned long flags;
>>> +
>>> +     /*
>>> +      * The timer interrupt generation is disabled at least
>>> +      * for enough time to call epit_set_next_event()
>>> +      */
>>> +     local_irq_save(flags);
>>
>> This is not necessary. This function is called with interrupt disabled.
>>
>>> +     /* Disable interrupt in EPIT module */
>>> +     epit_irq_disable(epittm);
>>> +
>>> +     /* Clear pending interrupt, only while switching mode */
>>> +     if (!clockevent_state_oneshot(ced))
>>> +             epit_irq_acknowledge(epittm);
>>
>> Why do you need to ack the interrupt here ?
>>
>>> +     /*
>>> +      * Do not put overhead of interrupt enable/disable into
>>> +      * epit_set_next_event(), the core has about 4 minutes
>>> +      * to call epit_set_next_event() or shutdown clock after
>>> +      * mode switching
>>> +      */
>>> +     epit_irq_enable(epittm);
>>> +     local_irq_restore(flags);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
>>> +{
>>> +     struct clock_event_device *ced = dev_id;
>>> +     struct epit_timer *epittm = to_epit_timer(ced);
>>> +
>>> +     epit_irq_acknowledge(epittm);
>>> +
>>> +     ced->event_handler(ced);
>>> +
>>> +     return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int __init epit_clocksource_init(struct epit_timer *epittm)
>>> +{
>>> +     unsigned int c = clk_get_rate(epittm->clk);
>>> +
>>> +     sched_clock_reg = epittm->base + EPITCNR;
>>> +     sched_clock_register(epit_read_sched_clock, 32, c);
>>> +
>>> +     return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c, 200, 32,
>>> +                                  clocksource_mmio_readl_down);
>>> +}
>>> +
>>> +static int __init epit_clockevent_init(struct epit_timer *epittm)
>>> +{
>>> +     struct clock_event_device *ced = &epittm->ced;
>>> +     struct irqaction *act = &epittm->act;
>>> +
>>> +     ced->name = "epit";
>>> +     ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
>>> +     ced->set_state_shutdown = epit_shutdown;
>>> +     ced->tick_resume = epit_shutdown;
>>> +     ced->set_state_oneshot = epit_set_oneshot;
>>> +     ced->set_next_event = epit_set_next_event;
>>> +     ced->rating = 200;
>>> +     ced->cpumask = cpumask_of(0);
>>> +     ced->irq = epittm->irq;
>>> +     clockevents_config_and_register(ced, clk_get_rate(epittm->clk),
>>> +                                     0xff, 0xfffffffe);
>>> +
>>> +     act->name = "i.MX EPIT Timer Tick",
>>> +     act->flags = IRQF_TIMER | IRQF_IRQPOLL;
>>> +     act->handler = epit_timer_interrupt;
>>> +     act->dev_id = ced;
>>> +
>>> +     /* Make irqs happen */
>>> +     return setup_irq(epittm->irq, act);
>>> +}
>>> +
>>> +static int __init epit_timer_init(struct device_node *np)
>>> +{
>>> +     struct epit_timer *epittm;
>>> +     int ret;
>>> +
>>> +     epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
>>> +     if (!epittm)
>>> +             return -ENOMEM;
>>> +
>>> +     epittm->base = of_iomap(np, 0);
>>> +     if (!epittm->base) {
>>> +             ret = -ENXIO;
>>> +             goto out_kfree;
>>> +     }
>>> +
>>> +     epittm->irq = irq_of_parse_and_map(np, 0);
>>> +     if (!epittm->irq) {
>>> +             ret = -EINVAL;
>>> +             goto out_iounmap;
>>> +     }
>>> +
>>> +     /* Get EPIT clock */
>>> +     epittm->clk = of_clk_get(np, 0);
>>> +     if (IS_ERR(epittm->clk)) {
>>> +             pr_err("i.MX EPIT: unable to get clk\n");
>>> +             ret = PTR_ERR(epittm->clk);
>>> +             goto out_iounmap;
>>> +     }
>>> +
>>> +     ret = clk_prepare_enable(epittm->clk);
>>> +     if (ret) {
>>> +             pr_err("i.MX EPIT: unable to prepare+enable clk\n");
>>> +             goto out_iounmap;
>>> +     }
>>
>> Please replace all the above with the timer-of API as:
> Ok I will,
> 
> Thanks
> Clement
> 
>>
>> https://patchwork.kernel.org/patch/10510443/
>>
>>
>>> +     /* Initialise to a known state (all timers off, and timing reset) */
>>> +     writel_relaxed(0x0, epittm->base + EPITCR);
>>> +     writel_relaxed(0xffffffff, epittm->base + EPITLR);
>>> +     writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
>>> +                    epittm->base + EPITCR);
>>> +
>>> +     ret = epit_clocksource_init(epittm);
>>> +     if (ret) {
>>> +             pr_err("i.MX EPIT: failed to init clocksource\n");
>>> +             goto out_clk_disable;
>>> +     }
>>> +
>>> +     ret = epit_clockevent_init(epittm);
>>> +     if (ret) {
>>> +             pr_err("i.MX EPIT: failed to init clockevent\n");
>>> +             goto out_clk_disable;
>>> +     }
>>> +
>>> +     return 0;
>>> +
>>> +out_clk_disable:
>>> +     clk_disable_unprepare(epittm->clk);
>>> +out_iounmap:
>>> +     iounmap(epittm->base);
>>> +out_kfree:
>>> +     kfree(epittm);
>>> +
>>> +     return ret;
>>> +}
>>> +TIMER_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit_timer_init);
>>>
>>
>>
>> --
>>  <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
>>


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


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

* Re: [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer
  2018-11-05 11:48       ` Daniel Lezcano
@ 2018-11-08 13:25         ` Clément Péron
  0 siblings, 0 replies; 17+ messages in thread
From: Clément Péron @ 2018-11-08 13:25 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Colin Didier, linux-arm-kernel, devicetree, linux-kernel,
	Stefan Agner, Thomas Gleixner, Fabio Estevam, Vladimir Zapolskiy,
	Sascha Hauer, Rob Herring, NXP Linux Team,
	Pengutronix Kernel Team

Hi Daniel,

On Mon, 5 Nov 2018 at 12:48, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
>
>
> Hi Clément,
>
> On 04/11/2018 17:07, Clément Péron wrote:
> > Hi Daniel,
> >
> > Thanks for the review and sorry for the delay.
>
> no problem.
>
> > On Tue, 10 Jul 2018 at 18:20, Daniel Lezcano <daniel.lezcano@linaro.org> wrote:
> >>
> >> On 11/06/2018 17:50, Clément Péron wrote:
> >>> From: Colin Didier <colin.didier@devialet.com>
> >>>
> >>> Add driver for NXP's EPIT timer used in i.MX SoC.
> >>
> >> Give a description on how works this timer.
> > Ok,
> >
> >>
> >>
> >>> Signed-off-by: Colin Didier <colin.didier@devialet.com>
> >>> Signed-off-by: Clément Peron <clement.peron@devialet.com>
> >>> Reviewed-by: Vladimir Zapolskiy <vz@mleia.com>
> >>> Tested-by: Vladimir Zapolskiy <vz@mleia.com>
> >>> ---
> >>>  drivers/clocksource/Kconfig          |  11 ++
> >>>  drivers/clocksource/Makefile         |   1 +
> >>>  drivers/clocksource/timer-imx-epit.c | 265 +++++++++++++++++++++++++++
> >>>  3 files changed, 277 insertions(+)
> >>>  create mode 100644 drivers/clocksource/timer-imx-epit.c
> >>>
> >>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> >>> index 8e8a09755d10..790478afd02c 100644
> >>> --- a/drivers/clocksource/Kconfig
> >>> +++ b/drivers/clocksource/Kconfig
> >>> @@ -576,6 +576,17 @@ config H8300_TPU
> >>>         This enables the clocksource for the H8300 platform with the
> >>>         H8S2678 cpu.
> >>>
> >>> +config CLKSRC_IMX_EPIT
> >>> +     bool "Clocksource using i.MX EPIT"
> >>> +     depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
> >>> +     select CLKSRC_MMIO
> >>> +     help
> >>> +       This enables EPIT support available on some i.MX platforms.
> >>> +       Normally you don't have a reason to do so as the EPIT has
> >>> +       the same features and uses the same clocks as the GPT.
> >>> +       Anyway, on some systems the GPT may be in use for other
> >>> +       purposes.
> >>> +
> >>>  config CLKSRC_IMX_GPT
> >>>       bool "Clocksource using i.MX GPT" if COMPILE_TEST
> >>>       depends on ARM && CLKDEV_LOOKUP
> >>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> >>> index 00caf37e52f9..d9426f69ec69 100644
> >>> --- a/drivers/clocksource/Makefile
> >>> +++ b/drivers/clocksource/Makefile
> >>> @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER)   += timer-integrator-ap.o
> >>>  obj-$(CONFIG_CLKSRC_VERSATILE)               += versatile.o
> >>>  obj-$(CONFIG_CLKSRC_MIPS_GIC)                += mips-gic-timer.o
> >>>  obj-$(CONFIG_CLKSRC_TANGO_XTAL)              += tango_xtal.o
> >>> +obj-$(CONFIG_CLKSRC_IMX_EPIT)                += timer-imx-epit.o
> >>>  obj-$(CONFIG_CLKSRC_IMX_GPT)         += timer-imx-gpt.o
> >>>  obj-$(CONFIG_CLKSRC_IMX_TPM)         += timer-imx-tpm.o
> >>>  obj-$(CONFIG_ASM9260_TIMER)          += asm9260_timer.o
> >>> diff --git a/drivers/clocksource/timer-imx-epit.c b/drivers/clocksource/timer-imx-epit.c
> >>> new file mode 100644
> >>> index 000000000000..7f1c8e2e00aa
> >>> --- /dev/null
> >>> +++ b/drivers/clocksource/timer-imx-epit.c
> >>> @@ -0,0 +1,265 @@
> >>> +// SPDX-License-Identifier: GPL-2.0
> >>> +/*
> >>> + * i.MX EPIT Timer
> >>> + *
> >>> + * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
> >>> + * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
> >>> + * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
> >>> + */
> >>> +
> >>> +#include <linux/clk.h>
> >>> +#include <linux/clockchips.h>
> >>> +#include <linux/interrupt.h>
> >>> +#include <linux/of_address.h>
> >>> +#include <linux/of_irq.h>
> >>> +#include <linux/sched_clock.h>
> >>> +#include <linux/slab.h>
> >>> +
> >>> +#define EPITCR                               0x00
> >>> +#define EPITSR                               0x04
> >>> +#define EPITLR                               0x08
> >>> +#define EPITCMPR                     0x0c
> >>> +#define EPITCNR                              0x10
> >>> +
> >>> +#define EPITCR_EN                    BIT(0)
> >>> +#define EPITCR_ENMOD                 BIT(1)
> >>> +#define EPITCR_OCIEN                 BIT(2)
> >>> +#define EPITCR_RLD                   BIT(3)
> >>> +#define EPITCR_PRESC(x)                      (((x) & 0xfff) << 4)
> >>> +#define EPITCR_SWR                   BIT(16)
> >>> +#define EPITCR_IOVW                  BIT(17)
> >>> +#define EPITCR_DBGEN                 BIT(18)
> >>> +#define EPITCR_WAITEN                        BIT(19)
> >>> +#define EPITCR_RES                   BIT(20)
> >>> +#define EPITCR_STOPEN                        BIT(21)
> >>> +#define EPITCR_OM_DISCON             (0 << 22)
> >>> +#define EPITCR_OM_TOGGLE             (1 << 22)
> >>> +#define EPITCR_OM_CLEAR                      (2 << 22)
> >>> +#define EPITCR_OM_SET                        (3 << 22)
> >>> +#define EPITCR_CLKSRC_OFF            (0 << 24)
> >>> +#define EPITCR_CLKSRC_PERIPHERAL     (1 << 24)
> >>> +#define EPITCR_CLKSRC_REF_HIGH               (2 << 24)
> >>> +#define EPITCR_CLKSRC_REF_LOW                (3 << 24)
> >>> +
> >>> +#define EPITSR_OCIF                  BIT(0)
> >>> +
> >>> +struct epit_timer {
> >>> +     void __iomem *base;
> >>> +     int irq;
> >>> +     struct clk *clk;
> >>> +     struct clock_event_device ced;
> >>> +     struct irqaction act;
> >>> +};
> >>> +
> >>> +static void __iomem *sched_clock_reg;
> >>> +
> >>> +static inline struct epit_timer *to_epit_timer(struct clock_event_device *ced)
> >>> +{
> >>> +     return container_of(ced, struct epit_timer, ced);
> >>> +}
> >>> +
> >>> +static inline void epit_irq_disable(struct epit_timer *epittm)
> >>> +{
> >>> +     u32 val;
> >>> +
> >>> +     val = readl_relaxed(epittm->base + EPITCR);
> >>> +     writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
> >>> +}
> >>> +
> >>> +static inline void epit_irq_enable(struct epit_timer *epittm)
> >>> +{
> >>> +     u32 val;
> >>> +
> >>> +     val = readl_relaxed(epittm->base + EPITCR);
> >>> +     writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
> >>> +}
> >>> +
> >>> +static void epit_irq_acknowledge(struct epit_timer *epittm)
> >>> +{
> >>> +     writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
> >>> +}
> >>> +
> >>> +static u64 notrace epit_read_sched_clock(void)
> >>> +{
> >>> +     return ~readl_relaxed(sched_clock_reg);
> >>> +}
> >>> +
> >>> +static int epit_set_next_event(unsigned long cycles,
> >>> +                            struct clock_event_device *ced)
> >>> +{
> >>> +     struct epit_timer *epittm = to_epit_timer(ced);
> >>> +     unsigned long tcmp;
> >>> +
> >>> +     tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
> >>> +     writel_relaxed(tcmp, epittm->base + EPITCMPR);
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/* Left event sources disabled, no more interrupts appear */
> >>> +static int epit_shutdown(struct clock_event_device *ced)
> >>> +{
> >>> +     struct epit_timer *epittm = to_epit_timer(ced);
> >>> +     unsigned long flags;
> >>> +
> >>> +     /*
> >>> +      * The timer interrupt generation is disabled at least
> >>> +      * for enough time to call epit_set_next_event()
> >>> +      */
> >>> +     local_irq_save(flags);
> >>
> >> This is not necessary. This function is called with interrupt disabled.
> >
> > I took this from the i.MX GPT Timer :
> > https://elixir.bootlin.com/linux/latest/source/drivers/clocksource/timer-imx-gpt.c#L208
> >
> > Do you think i should also fix on the imx gpt timer ?
>
> Yes, the pointed code is 10 years old, so if you are willing to do the
> changes in a separate patchset, that would be nice.
>
> >>> +     /* Disable interrupt in EPIT module */
> >>> +     epit_irq_disable(epittm);
> >>> +
> >>> +     /* Clear pending interrupt */
> >>> +     epit_irq_acknowledge(epittm);
> >>
> >> No irq ack is needed here. Neither disabling the interrupt.
> > Is it done by the framework ?
> >
> > I took also this from the IMX GPT driver
>
> If we reach this point of code with a pending timer interrupt, that
> means it should be processed after the clockevent shutdown path is
> finished. Otherwise it is like we cancel the timer on the back of the
> system.

Thanks for pointing out that. This is actually the first timer driver
that I touch.
I found all this a bit crappy and I have lazily copy/paste from imx-gpt driver.
for me it should more propre to have something like the
"timer-npcm7xx.c" driver.
I'm looking to understand a bit more the framework before cleaning
this. Could you point me any documentation about the framework,
Specially what should set_state_**,  and tick_resume should do. I'm
septic about this "ced->tick_resume = epit_shutdown;"

Also do you have some test that i could run to confirm the driver works fine ?

Thanks,
Clement

>
> >> Why not just stop the counter ?
> > I will check the datasheet.
> >>> +     local_irq_restore(flags);
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +static int epit_set_oneshot(struct clock_event_device *ced)
> >>> +{
> >>> +     struct epit_timer *epittm = to_epit_timer(ced);
> >>> +     unsigned long flags;
> >>> +
> >>> +     /*
> >>> +      * The timer interrupt generation is disabled at least
> >>> +      * for enough time to call epit_set_next_event()
> >>> +      */
> >>> +     local_irq_save(flags);
> >>
> >> This is not necessary. This function is called with interrupt disabled.
> >>
> >>> +     /* Disable interrupt in EPIT module */
> >>> +     epit_irq_disable(epittm);
> >>> +
> >>> +     /* Clear pending interrupt, only while switching mode */
> >>> +     if (!clockevent_state_oneshot(ced))
> >>> +             epit_irq_acknowledge(epittm);
> >>
> >> Why do you need to ack the interrupt here ?
> >>
> >>> +     /*
> >>> +      * Do not put overhead of interrupt enable/disable into
> >>> +      * epit_set_next_event(), the core has about 4 minutes
> >>> +      * to call epit_set_next_event() or shutdown clock after
> >>> +      * mode switching
> >>> +      */
> >>> +     epit_irq_enable(epittm);
> >>> +     local_irq_restore(flags);
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
> >>> +{
> >>> +     struct clock_event_device *ced = dev_id;
> >>> +     struct epit_timer *epittm = to_epit_timer(ced);
> >>> +
> >>> +     epit_irq_acknowledge(epittm);
> >>> +
> >>> +     ced->event_handler(ced);
> >>> +
> >>> +     return IRQ_HANDLED;
> >>> +}
> >>> +
> >>> +static int __init epit_clocksource_init(struct epit_timer *epittm)
> >>> +{
> >>> +     unsigned int c = clk_get_rate(epittm->clk);
> >>> +
> >>> +     sched_clock_reg = epittm->base + EPITCNR;
> >>> +     sched_clock_register(epit_read_sched_clock, 32, c);
> >>> +
> >>> +     return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c, 200, 32,
> >>> +                                  clocksource_mmio_readl_down);
> >>> +}
> >>> +
> >>> +static int __init epit_clockevent_init(struct epit_timer *epittm)
> >>> +{
> >>> +     struct clock_event_device *ced = &epittm->ced;
> >>> +     struct irqaction *act = &epittm->act;
> >>> +
> >>> +     ced->name = "epit";
> >>> +     ced->features = CLOCK_set_state_shutdownEVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
> >>> +     ced->set_state_shutdown = epit_shutdown;
> >>> +     ced->tick_resume = epit_shutdown;
> >>> +     ced->set_state_oneshot = epit_set_oneshot;
> >>> +     ced->set_next_event = epit_set_next_event;
> >>> +     ced->rating = 200;
> >>> +     ced->cpumask = cpumask_of(0);
> >>> +     ced->irq = epittm->irq;
> >>> +     clockevents_config_and_register(ced, clk_get_rate(epittm->clk),
> >>> +                                     0xff, 0xfffffffe);
> >>> +
> >>> +     act->name = "i.MX EPIT Timer Tick",
> >>> +     act->flags = IRQF_TIMER | IRQF_IRQPOLL;
> >>> +     act->handler = epit_timer_interrupt;
> >>> +     act->dev_id = ced;
> >>> +
> >>> +     /* Make irqs happen */
> >>> +     return setup_irq(epittm->irq, act);
> >>> +}
> >>> +
> >>> +static int __init epit_timer_init(struct device_node *np)
> >>> +{
> >>> +     struct epit_timer *epittm;
> >>> +     int ret;
> >>> +
> >>> +     epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
> >>> +     if (!epittm)
> >>> +             return -ENOMEM;
> >>> +
> >>> +     epittm->base = of_iomap(np, 0);
> >>> +     if (!epittm->base) {
> >>> +             ret = -ENXIO;
> >>> +             goto out_kfree;
> >>> +     }
> >>> +
> >>> +     epittm->irq = irq_of_parse_and_map(np, 0);
> >>> +     if (!epittm->irq) {
> >>> +             ret = -EINVAL;
> >>> +             goto out_iounmap;
> >>> +     }
> >>> +
> >>> +     /* Get EPIT clock */
> >>> +     epittm->clk = of_clk_get(np, 0);
> >>> +     if (IS_ERR(epittm->clk)) {
> >>> +             pr_err("i.MX EPIT: unable to get clk\n");
> >>> +             ret = PTR_ERR(epittm->clk);
> >>> +             goto out_iounmap;
> >>> +     }
> >>> +
> >>> +     ret = clk_prepare_enable(epittm->clk);
> >>> +     if (ret) {
> >>> +             pr_err("i.MX EPIT: unable to prepare+enable clk\n");
> >>> +             goto out_iounmap;
> >>> +     }
> >>
> >> Please replace all the above with the timer-of API as:
> > Ok I will,
> >
> > Thanks
> > Clement
> >
> >>
> >> https://patchwork.kernel.org/patch/10510443/
> >>
> >>
> >>> +     /* Initialise to a known state (all timers off, and timing reset) */
> >>> +     writel_relaxed(0x0, epittm->base + EPITCR);
> >>> +     writel_relaxed(0xffffffff, epittm->base + EPITLR);
> >>> +     writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
> >>> +                    epittm->base + EPITCR);
> >>> +
> >>> +     ret = epit_clocksource_init(epittm);
> >>> +     if (ret) {
> >>> +             pr_err("i.MX EPIT: failed to init clocksource\n");
> >>> +             goto out_clk_disable;
> >>> +     }
> >>> +
> >>> +     ret = epit_clockevent_init(epittm);
> >>> +     if (ret) {
> >>> +             pr_err("i.MX EPIT: failed to init clockevent\n");
> >>> +             goto out_clk_disable;
> >>> +     }
> >>> +
> >>> +     return 0;
> >>> +
> >>> +out_clk_disable:
> >>> +     clk_disable_unprepare(epittm->clk);
> >>> +out_iounmap:
> >>> +     iounmap(epittm->base);
> >>> +out_kfree:
> >>> +     kfree(epittm);
> >>> +
> >>> +     return ret;
> >>> +}
> >>> +TIMER_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit_timer_init);
> >>>
> >>
> >>
> >> --
> >>  <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
> >>
>
>
> --
>  <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
>

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

end of thread, other threads:[~2018-11-08 13:25 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-11 15:49 [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
2018-06-11 15:49 ` [PATCH v7 1/5] clk: imx6: add EPIT clock support Clément Péron
2018-06-11 15:49 ` [PATCH v7 2/5] ARM: imx: remove inexistant EPIT timer init Clément Péron
2018-06-11 15:49 ` [PATCH v7 3/5] dt-bindings: timer: add i.MX EPIT timer binding Clément Péron
2018-06-12 18:27   ` Rob Herring
2018-06-11 15:50 ` [PATCH v7 4/5] clocksource: add driver for i.MX EPIT timer Clément Péron
2018-07-10 16:20   ` Daniel Lezcano
2018-11-04 16:07     ` Clément Péron
2018-11-05 11:48       ` Daniel Lezcano
2018-11-08 13:25         ` Clément Péron
2018-06-11 15:50 ` [PATCH v7 5/5] ARM: dts: imx: add missing compatible and clock properties for EPIT Clément Péron
2018-07-10 14:55 ` [PATCH v7 0/5] Reintroduce i.MX EPIT Timer Clément Péron
2018-07-10 14:58   ` Daniel Lezcano
2018-07-10 15:12   ` Daniel Lezcano
2018-07-10 15:22     ` Clément Péron
2018-07-10 15:37       ` Daniel Lezcano
2018-07-10 16:05         ` Clément Péron

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).