From: Carlo Caione <carlo@caione.org> To: linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-serial@vger.kernel.org, linux@arm.linux.org.uk, robh+dt@kernel.org, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk, daniel.lezcano@linaro.org, tglx@linutronix.de, gregkh@linuxfoundation.org, jslaby@suse.cz, grant.likely@linaro.org, b.galvani@gmail.com, maxime.ripard@free-electrons.com, afaerber@suse.de, matthias.bgg@gmail.com Cc: Carlo Caione <carlo@caione.org> Subject: [PATCH v2 5/9] ARM: meson6: clocksource: add Meson6 timer support Date: Thu, 11 Sep 2014 22:11:36 +0200 [thread overview] Message-ID: <1410466300-19168-6-git-send-email-carlo@caione.org> (raw) In-Reply-To: <1410466300-19168-1-git-send-email-carlo@caione.org> Meson6 SoCs are equipped with 5 32-bit timers, called TIMER_A, TIMER_B, TIMER_C, TIMER_D and TIMER_E. The driver is providing clocksource support for the 32-bit counter using TIMER_E. Clockevents are also supported using TIMER_A. Signed-off-by: Carlo Caione <carlo@caione.org> --- drivers/clocksource/Kconfig | 3 + drivers/clocksource/Makefile | 1 + drivers/clocksource/meson6_timer.c | 167 +++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/clocksource/meson6_timer.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 065131c..1c80d7e 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -28,6 +28,9 @@ config ARMADA_370_XP_TIMER bool select CLKSRC_OF +config MESON6_TIMER + bool + config ORION_TIMER select CLKSRC_OF select CLKSRC_MMIO diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 800b130..5a4fc59 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o +obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c new file mode 100644 index 0000000..5c15cba --- /dev/null +++ b/drivers/clocksource/meson6_timer.c @@ -0,0 +1,167 @@ +/* + * Amlogic Meson6 SoCs timer handling. + * + * Copyright (C) 2014 Carlo Caione <carlo@caione.org> + * + * Based on code from Amlogic, Inc + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqreturn.h> +#include <linux/sched_clock.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#define CED_ID 0 +#define CSD_ID 4 + +#define TIMER_ISA_MUX 0 +#define TIMER_ISA_VAL(t) (((t) + 1) << 2) + +#define TIMER_INPUT_BIT(t) (2 * (t)) +#define TIMER_ENABLE_BIT(t) (16 + (t)) +#define TIMER_PERIODIC_BIT(t) (12 + (t)) + +#define TIMER_CED_INPUT_MASK (3UL << TIMER_INPUT_BIT(CED_ID)) +#define TIMER_CSD_INPUT_MASK (7UL << TIMER_INPUT_BIT(CSD_ID)) + +#define TIMER_CED_UNIT_1US 0 +#define TIMER_CSD_UNIT_1US 1 + +static void __iomem *timer_base; + +static u64 notrace meson6_timer_sched_read(void) +{ + return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID)); +} + +static void meson6_clkevt_time_stop(unsigned char timer) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay) +{ + writel(delay, timer_base + TIMER_ISA_VAL(timer)); +} + +static void meson6_clkevt_time_start(unsigned char timer, bool periodic) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + if (periodic) + val |= TIMER_PERIODIC_BIT(timer); + else + val &= ~TIMER_PERIODIC_BIT(timer); + + writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1); + meson6_clkevt_time_start(CED_ID, true); + break; + case CLOCK_EVT_MODE_ONESHOT: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_start(CED_ID, false); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + meson6_clkevt_time_stop(CED_ID); + break; + } +} + +static int meson6_clkevt_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, evt); + meson6_clkevt_time_start(CED_ID, false); + + return 0; +} + +static struct clock_event_device meson6_clockevent = { + .name = "meson6_tick", + .rating = 400, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = meson6_clkevt_mode, + .set_next_event = meson6_clkevt_next_event, +}; + +static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = (struct clock_event_device *)dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction meson6_timer_irq = { + .name = "meson6_timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = meson6_timer_interrupt, + .dev_id = &meson6_clockevent, +}; + +static void __init meson6_timer_init(struct device_node *node) +{ + u32 val; + int ret, irq; + + timer_base = of_io_request_and_map(node, 0, "meson6-timer"); + if (IS_ERR(timer_base)) + panic("Can't map registers"); + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + /* Set 1us for timer E */ + val = readl(timer_base + TIMER_ISA_MUX); + val &= ~TIMER_CSD_INPUT_MASK; + val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC); + clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name, + 1000 * 1000, 300, 32, clocksource_mmio_readl_up); + + /* Timer A base 1us */ + val &= ~TIMER_CED_INPUT_MASK; + val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + /* Stop the timer A */ + meson6_clkevt_time_stop(CED_ID); + + ret = setup_irq(irq, &meson6_timer_irq); + if (ret) + pr_warn("failed to setup irq %d\n", irq); + + meson6_clockevent.cpumask = cpu_possible_mask; + meson6_clockevent.irq = irq; + + clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC, + 1, 0xfffe); +} +CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", + meson6_timer_init); -- 1.9.1
WARNING: multiple messages have this Message-ID (diff)
From: carlo@caione.org (Carlo Caione) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH v2 5/9] ARM: meson6: clocksource: add Meson6 timer support Date: Thu, 11 Sep 2014 22:11:36 +0200 [thread overview] Message-ID: <1410466300-19168-6-git-send-email-carlo@caione.org> (raw) In-Reply-To: <1410466300-19168-1-git-send-email-carlo@caione.org> Meson6 SoCs are equipped with 5 32-bit timers, called TIMER_A, TIMER_B, TIMER_C, TIMER_D and TIMER_E. The driver is providing clocksource support for the 32-bit counter using TIMER_E. Clockevents are also supported using TIMER_A. Signed-off-by: Carlo Caione <carlo@caione.org> --- drivers/clocksource/Kconfig | 3 + drivers/clocksource/Makefile | 1 + drivers/clocksource/meson6_timer.c | 167 +++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/clocksource/meson6_timer.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 065131c..1c80d7e 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -28,6 +28,9 @@ config ARMADA_370_XP_TIMER bool select CLKSRC_OF +config MESON6_TIMER + bool + config ORION_TIMER select CLKSRC_OF select CLKSRC_MMIO diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 800b130..5a4fc59 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o +obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c new file mode 100644 index 0000000..5c15cba --- /dev/null +++ b/drivers/clocksource/meson6_timer.c @@ -0,0 +1,167 @@ +/* + * Amlogic Meson6 SoCs timer handling. + * + * Copyright (C) 2014 Carlo Caione <carlo@caione.org> + * + * Based on code from Amlogic, Inc + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqreturn.h> +#include <linux/sched_clock.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#define CED_ID 0 +#define CSD_ID 4 + +#define TIMER_ISA_MUX 0 +#define TIMER_ISA_VAL(t) (((t) + 1) << 2) + +#define TIMER_INPUT_BIT(t) (2 * (t)) +#define TIMER_ENABLE_BIT(t) (16 + (t)) +#define TIMER_PERIODIC_BIT(t) (12 + (t)) + +#define TIMER_CED_INPUT_MASK (3UL << TIMER_INPUT_BIT(CED_ID)) +#define TIMER_CSD_INPUT_MASK (7UL << TIMER_INPUT_BIT(CSD_ID)) + +#define TIMER_CED_UNIT_1US 0 +#define TIMER_CSD_UNIT_1US 1 + +static void __iomem *timer_base; + +static u64 notrace meson6_timer_sched_read(void) +{ + return (u64)readl(timer_base + TIMER_ISA_VAL(CSD_ID)); +} + +static void meson6_clkevt_time_stop(unsigned char timer) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + writel(val & ~TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_time_setup(unsigned char timer, unsigned long delay) +{ + writel(delay, timer_base + TIMER_ISA_VAL(timer)); +} + +static void meson6_clkevt_time_start(unsigned char timer, bool periodic) +{ + u32 val = readl(timer_base + TIMER_ISA_MUX); + + if (periodic) + val |= TIMER_PERIODIC_BIT(timer); + else + val &= ~TIMER_PERIODIC_BIT(timer); + + writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); +} + +static void meson6_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1); + meson6_clkevt_time_start(CED_ID, true); + break; + case CLOCK_EVT_MODE_ONESHOT: + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_start(CED_ID, false); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + meson6_clkevt_time_stop(CED_ID); + break; + } +} + +static int meson6_clkevt_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, evt); + meson6_clkevt_time_start(CED_ID, false); + + return 0; +} + +static struct clock_event_device meson6_clockevent = { + .name = "meson6_tick", + .rating = 400, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = meson6_clkevt_mode, + .set_next_event = meson6_clkevt_next_event, +}; + +static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = (struct clock_event_device *)dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static struct irqaction meson6_timer_irq = { + .name = "meson6_timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = meson6_timer_interrupt, + .dev_id = &meson6_clockevent, +}; + +static void __init meson6_timer_init(struct device_node *node) +{ + u32 val; + int ret, irq; + + timer_base = of_io_request_and_map(node, 0, "meson6-timer"); + if (IS_ERR(timer_base)) + panic("Can't map registers"); + + irq = irq_of_parse_and_map(node, 0); + if (irq <= 0) + panic("Can't parse IRQ"); + + /* Set 1us for timer E */ + val = readl(timer_base + TIMER_ISA_MUX); + val &= ~TIMER_CSD_INPUT_MASK; + val |= TIMER_CSD_UNIT_1US << TIMER_INPUT_BIT(CSD_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + sched_clock_register(meson6_timer_sched_read, 32, USEC_PER_SEC); + clocksource_mmio_init(timer_base + TIMER_ISA_VAL(CSD_ID), node->name, + 1000 * 1000, 300, 32, clocksource_mmio_readl_up); + + /* Timer A base 1us */ + val &= ~TIMER_CED_INPUT_MASK; + val |= TIMER_CED_UNIT_1US << TIMER_INPUT_BIT(CED_ID); + writel(val, timer_base + TIMER_ISA_MUX); + + /* Stop the timer A */ + meson6_clkevt_time_stop(CED_ID); + + ret = setup_irq(irq, &meson6_timer_irq); + if (ret) + pr_warn("failed to setup irq %d\n", irq); + + meson6_clockevent.cpumask = cpu_possible_mask; + meson6_clockevent.irq = irq; + + clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC, + 1, 0xfffe); +} +CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", + meson6_timer_init); -- 1.9.1
next prev parent reply other threads:[~2014-09-11 20:11 UTC|newest] Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-09-11 20:11 [PATCH v2 0/9] ARM: meson: add preliminary support for MesonX/Meson6 SoCs Carlo Caione 2014-09-11 20:11 ` Carlo Caione [not found] ` <1410466300-19168-1-git-send-email-carlo-KA+7E9HrN00dnm+yROfE0A@public.gmane.org> 2014-09-11 20:11 ` [PATCH v2 1/9] ARM: meson: debug: add debug UART for earlyprintk support Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 20:11 ` [PATCH v2 2/9] ARM: meson: documentation: add UART documentation Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 20:11 ` [PATCH v2 3/9] ARM: meson: serial: add MesonX SoC on-chip uart driver Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 21:25 ` Greg KH 2014-09-11 21:25 ` Greg KH 2014-09-12 6:59 ` Carlo Caione 2014-09-12 6:59 ` Carlo Caione 2014-09-11 20:11 ` [PATCH v2 7/9] ARM: meson: add basic support for MesonX SoCs Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 20:11 ` [PATCH v2 4/9] ARM: meson: documentation: add timer documentation Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 20:59 ` Arnd Bergmann 2014-09-11 20:59 ` Arnd Bergmann 2014-09-11 20:11 ` Carlo Caione [this message] 2014-09-11 20:11 ` [PATCH v2 5/9] ARM: meson6: clocksource: add Meson6 timer support Carlo Caione 2014-09-11 20:57 ` Arnd Bergmann 2014-09-11 20:57 ` Arnd Bergmann 2014-09-16 9:06 ` Matthias Brugger 2014-09-16 9:06 ` Matthias Brugger 2014-09-11 20:11 ` [PATCH v2 6/9] ARM: meson: documentation: add bindings documentation Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 20:11 ` [PATCH v2 8/9] ARM: meson: dts: add basic Meson/Meson6/Meson6-atv1200 DTSI/DTS Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 21:03 ` Arnd Bergmann 2014-09-11 21:03 ` Arnd Bergmann 2014-09-11 20:11 ` [PATCH v2 9/9] ARM: meson: update multi_v7_defconfig Carlo Caione 2014-09-11 20:11 ` Carlo Caione 2014-09-11 21:01 ` [PATCH v2 0/9] ARM: meson: add preliminary support for MesonX/Meson6 SoCs Arnd Bergmann 2014-09-11 21:01 ` Arnd Bergmann
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1410466300-19168-6-git-send-email-carlo@caione.org \ --to=carlo@caione.org \ --cc=afaerber@suse.de \ --cc=b.galvani@gmail.com \ --cc=daniel.lezcano@linaro.org \ --cc=devicetree@vger.kernel.org \ --cc=grant.likely@linaro.org \ --cc=gregkh@linuxfoundation.org \ --cc=ijc+devicetree@hellion.org.uk \ --cc=jslaby@suse.cz \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-serial@vger.kernel.org \ --cc=linux@arm.linux.org.uk \ --cc=mark.rutland@arm.com \ --cc=matthias.bgg@gmail.com \ --cc=maxime.ripard@free-electrons.com \ --cc=robh+dt@kernel.org \ --cc=tglx@linutronix.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.