From: u.kleine-koenig@pengutronix.de (Uwe Kleine-König)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 04/11] ARM: imx: Add timer support for i.MX28
Date: Mon, 15 Nov 2010 17:40:08 +0100 [thread overview]
Message-ID: <20101115164008.GL8942@pengutronix.de> (raw)
In-Reply-To: <1289831795-4373-5-git-send-email-shawn.guo@freescale.com>
On Mon, Nov 15, 2010 at 10:36:28PM +0800, Shawn Guo wrote:
> SoC i.MX28 implements the timer in block TIMROT. It adds the
> support in the same file with GPT, and uses timer_is_timrot()
> to distinguish the IP block.
>
> Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
> ---
> arch/arm/plat-mxc/time.c | 120 ++++++++++++++++++++++++++++++++++++++--------
> 1 files changed, 100 insertions(+), 20 deletions(-)
>
> diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
> index f9a1b05..3e1f09d 100644
> --- a/arch/arm/plat-mxc/time.c
> +++ b/arch/arm/plat-mxc/time.c
> @@ -5,6 +5,7 @@
> * Copyright (C) 2002 Shane Nay (shane at minirl.com)
> * Copyright (C) 2006-2007 Pavel Pisa (ppisa at pikron.com)
> * Copyright (C) 2008 Juergen Beisert (kernel at pengutronix.de)
> + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> @@ -63,8 +64,22 @@
> #define V2_TCN 0x24
> #define V2_TCMP 0x10
>
> -#define timer_is_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
> -#define timer_is_v2() (!timer_is_v1())
> +/* TIMROT */
> +#define HW_TIMROT_ROTCTRL 0x00
> +#define HW_TIMROT_TIMCTRL0 0x20
> +#define HW_TIMROT_TIMCTRL0_SET 0x24
> +#define HW_TIMROT_TIMCTRL0_CLR 0x28
> +#define HW_TIMROT_RUNNING_COUNT0 0x30
> +#define HW_TIMROT_MATCH_COUNT0 0x50
> +#define BM_TIMROT_TIMCTRL0_IRQ_EN 0x00004000
> +#define BM_TIMROT_TIMCTRL0_IRQ 0x00008000
> +#define BM_TIMROT_TIMCTRL0_MATCH_MODE 0x00000800
> +#define BP_TIMROT_TIMCTRL0_SELECT 0
> +#define BV_TIMROT_TIMCTRLn_SELECT__32KHZ_XTAL 0xb
> +
> +#define timer_is_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
> +#define timer_is_v2() (!timer_is_v1())
> +#define timer_is_timrot() (cpu_is_mx28())
Did you notice that timer_is_v2() evaluates to true on mx28?
> static struct clock_event_device clockevent_mxc;
> static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
> @@ -105,6 +120,24 @@ static void gpt_irq_acknowledge(void)
> __raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
> }
>
> +static inline void timrot_irq_disable(void)
> +{
> + __raw_writel(BM_TIMROT_TIMCTRL0_IRQ_EN,
> + timer_base + HW_TIMROT_TIMCTRL0_CLR);
> +}
> +
> +static inline void timrot_irq_enable(void)
> +{
> + __raw_writel(BM_TIMROT_TIMCTRL0_IRQ_EN,
> + timer_base + HW_TIMROT_TIMCTRL0_SET);
> +}
> +
> +static void timrot_irq_acknowledge(void)
> +{
> + __raw_writel(BM_TIMROT_TIMCTRL0_IRQ,
> + timer_base + HW_TIMROT_TIMCTRL0_CLR);
> +}
> +
> static cycle_t mx1_2_get_cycles(struct clocksource *cs)
> {
> return __raw_readl(timer_base + MX1_2_TCN);
> @@ -115,6 +148,11 @@ static cycle_t v2_get_cycles(struct clocksource *cs)
> return __raw_readl(timer_base + V2_TCN);
> }
>
> +static cycle_t timrot_get_cycles(struct clocksource *cs)
> +{
> + return ~__raw_readl(timer_base + HW_TIMROT_RUNNING_COUNT0);
> +}
> +
> static struct clocksource clocksource_mxc = {
> .name = "mxc_timer1",
> .rating = 200,
> @@ -128,8 +166,12 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
> {
> unsigned int c = clk_get_rate(timer_clk);
>
> - if (timer_is_v2())
> + if (timer_is_timrot()) {
> + clocksource_mxc.read = timrot_get_cycles;
> + clocksource_mxc.shift = 10;
> + } else if (timer_is_v2()) {
> clocksource_mxc.read = v2_get_cycles;
> + }
>
> clocksource_mxc.mult = clocksource_hz2mult(c,
> clocksource_mxc.shift);
> @@ -166,6 +208,18 @@ static int v2_set_next_event(unsigned long evt,
> -ETIME : 0;
> }
>
> +static int timrot_set_next_event(unsigned long evt,
> + struct clock_event_device *dev)
> +{
> + unsigned long match;
> +
> + match = __raw_readl(timer_base + HW_TIMROT_MATCH_COUNT0) - evt;
> + __raw_writel(match, timer_base + HW_TIMROT_MATCH_COUNT0);
> +
> + return (int)(match - __raw_readl(timer_base +
> + HW_TIMROT_RUNNING_COUNT0)) > 0 ? -ETIME : 0;
> +}
> +
> #ifdef DEBUG
> static const char *clock_event_mode_label[] = {
> [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
> @@ -186,12 +240,19 @@ static void mxc_set_mode(enum clock_event_mode mode,
> */
> local_irq_save(flags);
>
> - /* Disable interrupt in GPT module */
> - gpt_irq_disable();
> + /* Disable interrupt in timer module */
> + if (timer_is_timrot())
> + timrot_irq_disable();
> + else
> + gpt_irq_disable();
can we have timrot_set_mode() please. Having several cpu_is_... in hot
paths isn't nice.
> if (mode != clockevent_mode) {
> /* Set event time into far-far future */
> - if (timer_is_v2())
> + if (timer_is_timrot())
> + __raw_writel(__raw_readl(timer_base +
> + HW_TIMROT_RUNNING_COUNT0) + 3,
> + timer_base + HW_TIMROT_MATCH_COUNT0);
> + else if (timer_is_v2())
> __raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
> timer_base + V2_TCMP);
> else
> @@ -199,7 +260,10 @@ static void mxc_set_mode(enum clock_event_mode mode,
> timer_base + MX1_2_TCMP);
>
> /* Clear pending interrupt */
> - gpt_irq_acknowledge();
> + if (timer_is_timrot())
> + timrot_irq_acknowledge();
> + else
> + gpt_irq_acknowledge();
> }
>
> #ifdef DEBUG
> @@ -225,7 +289,10 @@ static void mxc_set_mode(enum clock_event_mode mode,
> * mode switching
> */
> local_irq_save(flags);
> - gpt_irq_enable();
> + if (timer_is_timrot())
> + timrot_irq_enable();
> + else
> + gpt_irq_enable();
> local_irq_restore(flags);
> break;
> case CLOCK_EVT_MODE_SHUTDOWN:
> @@ -249,7 +316,10 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
> else
> tstat = __raw_readl(timer_base + MX1_2_TSTAT);
>
> - gpt_irq_acknowledge();
> + if (timer_is_timrot())
> + timrot_irq_acknowledge();
> + else
> + gpt_irq_acknowledge();
>
> evt->event_handler(evt);
>
> @@ -275,7 +345,9 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
> {
> unsigned int c = clk_get_rate(timer_clk);
>
> - if (timer_is_v2())
> + if (timer_is_timrot())
> + clockevent_mxc.set_next_event = timrot_set_next_event;
> + else if (timer_is_v2())
> clockevent_mxc.set_next_event = v2_set_next_event;
>
> clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
> @@ -303,16 +375,24 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
> /*
> * Initialise to a known state (all timers off, and timing reset)
> */
> -
> - __raw_writel(0, timer_base + MXC_TCTL);
> - __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
> -
> - if (timer_is_v2())
> - tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
> - else
> - tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
> -
> - __raw_writel(tctl_val, timer_base + MXC_TCTL);
> + if (timer_is_timrot()) {
> + mxc_reset_block(base + HW_TIMROT_ROTCTRL);
> + __raw_writel(
> + BV_TIMROT_TIMCTRLn_SELECT__32KHZ_XTAL |
> + BM_TIMROT_TIMCTRL0_IRQ_EN |
> + BM_TIMROT_TIMCTRL0_MATCH_MODE,
> + timer_base + HW_TIMROT_TIMCTRL0); /* timer0*/
> + } else {
> + __raw_writel(0, timer_base + MXC_TCTL);
> + __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
> + if (timer_is_v2())
> + tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR |
> + V2_TCTL_WAITEN | MXC_TCTL_TEN;
> + else
> + tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 |
> + MXC_TCTL_TEN;
> + __raw_writel(tctl_val, timer_base + MXC_TCTL);
> + }
>
> /* init and register the timer to the framework */
> mxc_clocksource_init(timer_clk);
> --
> 1.7.1
>
>
>
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
next prev parent reply other threads:[~2010-11-15 16:40 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-15 14:36 [RFC][PATCH 00/11] ARM: imx: Add initial i.MX28 support Shawn Guo
2010-11-15 14:36 ` [PATCH 01/11] ARM: imx: Add basic definitions for i.MX28 Shawn Guo
2010-11-15 16:25 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 02/11] ARM: imx: Add support of interrupt controller ICOLL Shawn Guo
2010-11-15 16:33 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 03/11] ARM: imx: Add reset routine for i.MX28 Shawn Guo
2010-11-15 16:36 ` Uwe Kleine-König
2010-11-17 11:17 ` Shawn Guo
2010-11-17 13:44 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 04/11] ARM: imx: Add timer support " Shawn Guo
2010-11-15 16:40 ` Uwe Kleine-König [this message]
2010-11-15 14:36 ` [PATCH 05/11] ARM: imx: Add GPIO " Shawn Guo
2010-11-15 16:43 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 06/11] ARM: imx: Add IOMUX " Shawn Guo
2010-11-15 16:46 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 07/11] ARM: imx: Add support of uncompress print " Shawn Guo
2010-11-15 16:47 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 08/11] ARM: imx: Add clock support " Shawn Guo
2010-11-15 14:36 ` [PATCH 09/11] ARM: imx: Add memory map " Shawn Guo
2010-11-15 14:36 ` [PATCH 10/11] ARM: imx: Add initial support of machine mx28evk Shawn Guo
2010-11-15 16:54 ` Uwe Kleine-König
2010-11-15 14:36 ` [PATCH 11/11] ARM: imx: Add i.MX28 support into Kconfig and Makefile Shawn Guo
2010-11-15 17:01 ` Uwe Kleine-König
2010-11-16 10:15 ` [RFC][PATCH 00/11] ARM: imx: Add initial i.MX28 support Sascha Hauer
2010-11-16 12:42 ` Shawn Guo
2010-11-16 17:24 ` Uwe Kleine-König
2010-11-17 1:28 ` Shawn Guo
2010-11-17 6:06 ` Uwe Kleine-König
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=20101115164008.GL8942@pengutronix.de \
--to=u.kleine-koenig@pengutronix.de \
--cc=linux-arm-kernel@lists.infradead.org \
/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: link
Be 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.