2018-02-13 09:19:21

by Greentime Hu

[permalink] [raw]
Subject: [PATCH v7 0/3] clocksource/drivers/atcpit100: Add andestech atcpit100 timer

Hi, all:

ATCPIT100 is often used on the Andes architecture,
This timer provide 4 PIT channels. Each PIT channel is a
multi-function timer, can be configured as 32,16,8 bit timers
or PWM as well.

For system timer it will set channel 1 32-bit timer0 as clock
source and count downwards until underflow and restart again.

It also set channel 0 32-bit timer0 as clock event and count
downwards until condition match. It will generate an interrupt
for handling periodically.

Changes in v7:
- Fix atcpit100_clkevt_next_event(), before set reload register,
clock source timer shall disable. And re-enable it after the setting.
Without this modification, the test case 'clock_nanosleep02' of ltp_20170929
will fail.

Changes in v6:
- To select TIMER_OF in drivers/clocksource/Kconfig instead of arch/nds32/Kconfig
- Refine Kconfig
- Update license format to SPDX-License-Identifier


Rick Chen (3):
clocksource/drivers/atcpit100: Add andestech atcpit100 timer
clocksource/drivers/atcpit100: VDSO support
dt-bindings: timer: Add andestech atcpit100 timer binding doc

.../bindings/timer/andestech,atcpit100-timer.txt | 33 +++
drivers/clocksource/Kconfig | 9 +
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-atcpit100.c | 266 +++++++++++++++++++++
4 files changed, 309 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt
create mode 100644 drivers/clocksource/timer-atcpit100.c

--
2.16.1



2018-02-13 09:15:45

by Greentime Hu

[permalink] [raw]
Subject: [PATCH v7 3/3] dt-bindings: timer: Add andestech atcpit100 timer binding doc

From: Rick Chen <[email protected]>

Add a document to describe Andestech atcpit100 timer and
binding information.

Signed-off-by: Rick Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
Acked-by: Rob Herring <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
---
.../bindings/timer/andestech,atcpit100-timer.txt | 33 ++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt b/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt
new file mode 100644
index 000000000000..4c9ea5989e35
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt
@@ -0,0 +1,33 @@
+Andestech ATCPIT100 timer
+------------------------------------------------------------------
+ATCPIT100 is a generic IP block from Andes Technology, embedded in
+Andestech AE3XX platforms and other designs.
+
+This timer is a set of compact multi-function timers, which can be
+used as pulse width modulators (PWM) as well as simple timers.
+
+It supports up to 4 PIT channels. Each PIT channel is a
+multi-function timer and provide the following usage scenarios:
+One 32-bit timer
+Two 16-bit timers
+Four 8-bit timers
+One 16-bit PWM
+One 16-bit timer and one 8-bit PWM
+Two 8-bit timer and one 8-bit PWM
+
+Required properties:
+- compatible : Should be "andestech,atcpit100"
+- reg : Address and length of the register set
+- interrupts : Reference to the timer interrupt
+- clocks : a clock to provide the tick rate for "andestech,atcpit100"
+- clock-names : should be "PCLK" for the peripheral clock source.
+
+Examples:
+
+timer0: timer@f0400000 {
+ compatible = "andestech,atcpit100";
+ reg = <0xf0400000 0x1000>;
+ interrupts = <2>;
+ clocks = <&apb>;
+ clock-names = "PCLK";
+};
--
2.16.1


2018-02-13 09:16:14

by Greentime Hu

[permalink] [raw]
Subject: [PATCH v7 1/3] clocksource/drivers/atcpit100: Add andestech atcpit100 timer

From: Rick Chen <[email protected]>

ATCPIT100 is often used on the Andes architecture,
This timer provide 4 PIT channels. Each PIT channel is a
multi-function timer, can be configured as 32,16,8 bit timers
or PWM as well.

For system timer it will set channel 1 32-bit timer0 as clock
source and count downwards until underflow and restart again.

It also set channel 0 32-bit timer0 as clock event and count
downwards until condition match. It will generate an interrupt
for handling periodically.

Signed-off-by: Rick Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
Reviewed-by: Linus Walleij <[email protected]>

Add andestech atcpit100 timer
---
drivers/clocksource/Kconfig | 9 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-atcpit100.c | 248 ++++++++++++++++++++++++++++++++++
3 files changed, 258 insertions(+)
create mode 100644 drivers/clocksource/timer-atcpit100.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b3b4ed9b6874..19d65fe0627e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -591,4 +591,13 @@ config CLKSRC_ST_LPC
Enable this option to use the Low Power controller timer
as clocksource.

+config ATCPIT100_TIMER
+ bool "ATCPIT100 timer driver"
+ depends on NDS32 || COMPILE_TEST
+ depends on HAS_IOMEM
+ select TIMER_OF
+ default NDS32
+ help
+ This option enables support for the Andestech ATCPIT100 timers.
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index d6dec4489d66..a79523b22e52 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -76,3 +76,4 @@ obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
+obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
diff --git a/drivers/clocksource/timer-atcpit100.c b/drivers/clocksource/timer-atcpit100.c
new file mode 100644
index 000000000000..2190096cffa3
--- /dev/null
+++ b/drivers/clocksource/timer-atcpit100.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2005-2017 Andes Technology Corporation
+/*
+ * Andestech ATCPIT100 Timer Device Driver Implementation
+ * Rick Chen, Andes Technology Corporation <[email protected]>
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/sched.h>
+#include <linux/sched_clock.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include "timer-of.h"
+
+/*
+ * Definition of register offsets
+ */
+
+/* ID and Revision Register */
+#define ID_REV 0x0
+
+/* Configuration Register */
+#define CFG 0x10
+
+/* Interrupt Enable Register */
+#define INT_EN 0x14
+#define CH_INT_EN(c, i) ((1<<i)<<(4*c))
+#define CH0INT0EN 0x01
+
+/* Interrupt Status Register */
+#define INT_STA 0x18
+#define CH0INT0 0x01
+
+/* Channel Enable Register */
+#define CH_EN 0x1C
+#define CH0TMR0EN 0x1
+#define CH1TMR0EN 0x10
+
+/* Channel 0 , 1 Control Register */
+#define CH0_CTL (0x20)
+#define CH1_CTL (0x20 + 0x10)
+
+/* Channel clock source , bit 3 , 0:External clock , 1:APB clock */
+#define APB_CLK BIT(3)
+
+/* Channel mode , bit 0~2 */
+#define TMR_32 0x1
+#define TMR_16 0x2
+#define TMR_8 0x3
+
+/* Channel 0 , 1 Reload Register */
+#define CH0_REL (0x24)
+#define CH1_REL (0x24 + 0x10)
+
+/* Channel 0 , 1 Counter Register */
+#define CH0_CNT (0x28)
+#define CH1_CNT (0x28 + 0x10)
+
+#define TIMER_SYNC_TICKS 3
+
+static void atcpit100_ch1_tmr0_en(void __iomem *base)
+{
+ writel(~0, base + CH1_REL);
+ writel(APB_CLK|TMR_32, base + CH1_CTL);
+}
+
+static void atcpit100_ch0_tmr0_en(void __iomem *base)
+{
+ writel(APB_CLK|TMR_32, base + CH0_CTL);
+}
+
+static void atcpit100_clkevt_time_setup(void __iomem *base, unsigned long delay)
+{
+ writel(delay, base + CH0_CNT);
+ writel(delay, base + CH0_REL);
+}
+
+static void atcpit100_timer_clear_interrupt(void __iomem *base)
+{
+ u32 val;
+
+ val = readl(base + INT_STA);
+ writel(val | CH0INT0, base + INT_STA);
+}
+
+static void atcpit100_clocksource_start(void __iomem *base)
+{
+ u32 val;
+
+ val = readl(base + CH_EN);
+ writel(val | CH1TMR0EN, base + CH_EN);
+}
+
+static void atcpit100_clkevt_time_start(void __iomem *base)
+{
+ u32 val;
+
+ val = readl(base + CH_EN);
+ writel(val | CH0TMR0EN, base + CH_EN);
+}
+
+static void atcpit100_clkevt_time_stop(void __iomem *base)
+{
+ u32 val;
+
+ atcpit100_timer_clear_interrupt(base);
+ val = readl(base + CH_EN);
+ writel(val & ~CH0TMR0EN, base + CH_EN);
+}
+
+static int atcpit100_clkevt_next_event(unsigned long evt,
+ struct clock_event_device *clkevt)
+{
+ u32 val;
+ struct timer_of *to = to_timer_of(clkevt);
+
+ val = readl(timer_of_base(to) + CH_EN);
+ writel(val & ~CH0TMR0EN, timer_of_base(to) + CH_EN);
+ writel(evt, timer_of_base(to) + CH0_REL);
+ writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN);
+
+ return 0;
+}
+
+static int atcpit100_clkevt_set_periodic(struct clock_event_device *evt)
+{
+ struct timer_of *to = to_timer_of(evt);
+
+ atcpit100_clkevt_time_setup(timer_of_base(to), timer_of_period(to));
+ atcpit100_clkevt_time_start(timer_of_base(to));
+
+ return 0;
+}
+static int atcpit100_clkevt_shutdown(struct clock_event_device *evt)
+{
+ struct timer_of *to = to_timer_of(evt);
+
+ atcpit100_clkevt_time_stop(timer_of_base(to));
+
+ return 0;
+}
+static int atcpit100_clkevt_set_oneshot(struct clock_event_device *evt)
+{
+ struct timer_of *to = to_timer_of(evt);
+ u32 val;
+
+ writel(~0x0, timer_of_base(to) + CH0_REL);
+ val = readl(timer_of_base(to) + CH_EN);
+ writel(val | CH0TMR0EN, timer_of_base(to) + CH_EN);
+
+ return 0;
+}
+
+static irqreturn_t atcpit100_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = (struct clock_event_device *)dev_id;
+ struct timer_of *to = to_timer_of(evt);
+
+ atcpit100_timer_clear_interrupt(timer_of_base(to));
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct timer_of to = {
+ .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
+
+ .clkevt = {
+ .name = "atcpit100_tick",
+ .rating = 300,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_shutdown = atcpit100_clkevt_shutdown,
+ .set_state_periodic = atcpit100_clkevt_set_periodic,
+ .set_state_oneshot = atcpit100_clkevt_set_oneshot,
+ .tick_resume = atcpit100_clkevt_shutdown,
+ .set_next_event = atcpit100_clkevt_next_event,
+ .cpumask = cpu_all_mask,
+ },
+
+ .of_irq = {
+ .handler = atcpit100_timer_interrupt,
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ },
+
+ /*
+ * FIXME: we currently only support clocking using PCLK
+ * and using EXTCLK is not supported in the driver.
+ */
+ .of_clk = {
+ .name = "PCLK",
+ }
+};
+
+static u64 notrace atcpit100_timer_sched_read(void)
+{
+ return ~readl(timer_of_base(&to) + CH1_CNT);
+}
+
+static int __init atcpit100_timer_init(struct device_node *node)
+{
+ int ret;
+ u32 val;
+ void __iomem *base;
+
+ ret = timer_of_init(node, &to);
+ if (ret)
+ return ret;
+
+ base = timer_of_base(&to);
+
+ sched_clock_register(atcpit100_timer_sched_read, 32,
+ timer_of_rate(&to));
+
+ ret = clocksource_mmio_init(base + CH1_CNT,
+ node->name, timer_of_rate(&to), 300, 32,
+ clocksource_mmio_readl_down);
+
+ if (ret) {
+ pr_err("Failed to register clocksource\n");
+ return ret;
+ }
+
+ /* clear channel 0 timer0 interrupt */
+ atcpit100_timer_clear_interrupt(base);
+
+ clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
+ TIMER_SYNC_TICKS, 0xffffffff);
+ atcpit100_ch0_tmr0_en(base);
+ atcpit100_ch1_tmr0_en(base);
+ atcpit100_clocksource_start(base);
+ atcpit100_clkevt_time_start(base);
+
+ /* Enable channel 0 timer0 interrupt */
+ val = readl(base + INT_EN);
+ writel(val | CH0INT0EN, base + INT_EN);
+
+ return ret;
+}
+
+TIMER_OF_DECLARE(atcpit100, "andestech,atcpit100", atcpit100_timer_init);
--
2.16.1


2018-02-13 09:19:31

by Greentime Hu

[permalink] [raw]
Subject: [PATCH v7 2/3] clocksource/drivers/atcpit100: VDSO support

From: Rick Chen <[email protected]>

VDSO needs real-time cycle count to ensure the time accuracy.
Unlike others, nds32 architecture does not define clock source,
hence VDSO needs atcpit100 offering real-time cycle count
to derive the correct time.

Signed-off-by: Vincent Chen <[email protected]>
Signed-off-by: Rick Chen <[email protected]>
Signed-off-by: Greentime Hu <[email protected]>
---
drivers/clocksource/timer-atcpit100.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/drivers/clocksource/timer-atcpit100.c b/drivers/clocksource/timer-atcpit100.c
index 2190096cffa3..5e23d7b4a722 100644
--- a/drivers/clocksource/timer-atcpit100.c
+++ b/drivers/clocksource/timer-atcpit100.c
@@ -18,6 +18,9 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include "timer-of.h"
+#ifdef CONFIG_NDS32
+#include <asm/vdso_timer_info.h>
+#endif

/*
* Definition of register offsets
@@ -204,6 +207,17 @@ static u64 notrace atcpit100_timer_sched_read(void)
return ~readl(timer_of_base(&to) + CH1_CNT);
}

+#ifdef CONFIG_NDS32
+static void fill_vdso_need_info(struct device_node *node)
+{
+ struct resource timer_res;
+ of_address_to_resource(node, 0, &timer_res);
+ timer_info.mapping_base = (unsigned long)timer_res.start;
+ timer_info.cycle_count_down = true;
+ timer_info.cycle_count_reg_offset = CH1_CNT;
+}
+#endif
+
static int __init atcpit100_timer_init(struct device_node *node)
{
int ret;
@@ -242,6 +256,10 @@ static int __init atcpit100_timer_init(struct device_node *node)
val = readl(base + INT_EN);
writel(val | CH0INT0EN, base + INT_EN);

+#ifdef CONFIG_NDS32
+ fill_vdso_need_info(node);
+#endif
+
return ret;
}

--
2.16.1


2018-02-21 07:40:37

by Greentime Hu

[permalink] [raw]
Subject: Re: [PATCH v7 0/3] clocksource/drivers/atcpit100: Add andestech atcpit100 timer

2018-02-13 17:13 GMT+08:00 Greentime Hu <[email protected]>:
> Hi, all:
>
> ATCPIT100 is often used on the Andes architecture,
> This timer provide 4 PIT channels. Each PIT channel is a
> multi-function timer, can be configured as 32,16,8 bit timers
> or PWM as well.
>
> For system timer it will set channel 1 32-bit timer0 as clock
> source and count downwards until underflow and restart again.
>
> It also set channel 0 32-bit timer0 as clock event and count
> downwards until condition match. It will generate an interrupt
> for handling periodically.
>
> Changes in v7:
> - Fix atcpit100_clkevt_next_event(), before set reload register,
> clock source timer shall disable. And re-enable it after the setting.
> Without this modification, the test case 'clock_nanosleep02' of ltp_20170929
> will fail.
>
> Changes in v6:
> - To select TIMER_OF in drivers/clocksource/Kconfig instead of arch/nds32/Kconfig
> - Refine Kconfig
> - Update license format to SPDX-License-Identifier
>
>
> Rick Chen (3):
> clocksource/drivers/atcpit100: Add andestech atcpit100 timer
> clocksource/drivers/atcpit100: VDSO support
> dt-bindings: timer: Add andestech atcpit100 timer binding doc
>
> .../bindings/timer/andestech,atcpit100-timer.txt | 33 +++
> drivers/clocksource/Kconfig | 9 +
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/timer-atcpit100.c | 266 +++++++++++++++++++++
> 4 files changed, 309 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/timer/andestech,atcpit100-timer.txt
> create mode 100644 drivers/clocksource/timer-atcpit100.c
>
Hi, Daniel:

Please merge this driver for 4.17 to go along with the nds32
architeture support.
Thank you.