From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kuo-Jung Su Date: Wed, 26 Mar 2014 14:03:15 +0800 Subject: [U-Boot] [PATCH v11 2/6] arm: faraday: add FTTMR010 timer support In-Reply-To: <1395813799-3672-1-git-send-email-dantesu@gmail.com> References: <1395813799-3672-1-git-send-email-dantesu@gmail.com> Message-ID: <1395813799-3672-3-git-send-email-dantesu@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Kuo-Jung Su Faraday FTTMR010 is a simple APB device which supports generic timer functions. Signed-off-by: Kuo-Jung Su CC: Albert Aribaud --- Changes for v11: - Directly specify the timer object in 'arch/arm/cpu/faraday//Makefile' instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile' Changes for v8, v9, v10: - Nothing updates Changes for v7: - Update license to use SPDX identifiers. Changes for v6: - Nothing updates Changes for v5: - Drop IRQ dependant implementation - Use gd->arch.timer_rate_hz for timer clock source - Use gd->arch.tbl for timestamp Changes for v4: - Coding Style cleanup. - Break up from [arm: add Faraday A36x SoC platform support] Changes for v3: - Coding Style cleanup. - Drop macros for wirtel()/readl(), call them directly. - Always insert a blank line between declarations and code. - Add '__iomem' to all the declaration of HW register pointers. Changes for v2: - Coding Style cleanup. - Use readl(), writel(), clrsetbits_le32() to replace REG() macros. - Use structure based hardware registers to replace the macro constants. - Replace BIT() with BIT_MASK(). arch/arm/cpu/faraday/fttmr010.c | 123 +++++++++++++++++++++++++++++++++++++++ include/faraday/fttmr010.h | 17 ++++++ 2 files changed, 140 insertions(+) create mode 100644 arch/arm/cpu/faraday/fttmr010.c diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c new file mode 100644 index 0000000..28b0086 --- /dev/null +++ b/arch/arm/cpu/faraday/fttmr010.c @@ -0,0 +1,123 @@ +/* + * (C) Copyright 2013 + * Faraday Technology Corporation. + * Kuo-Jung Su + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE; + +void udelay_masked(unsigned long usec) +{ + ulong freq = gd->arch.timer_rate_hz; + + /* Disable Timer2 */ + clrbits_le32(®s->cr, FTTMR010_TM2_CRMASK); + /* Disable Timer2 interrupts */ + writel(FTTMR010_TM2_ISRMASK, ®s->interrupt_mask); + /* Clear Timer2 interrupts */ + writel(FTTMR010_TM2_ISRMASK, ®s->interrupt_state); + + /* Configure Timer2 */ + writel((freq / 1000000) * usec, ®s->timer2_counter); + writel(0, ®s->timer2_load); + writel(0, ®s->timer2_match1); + writel(0, ®s->timer2_match2); + + /* Enable Timer2 */ + setbits_le32(®s->cr, + FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE); + + /* Wait until timeout */ + while (!(readl(®s->interrupt_state) & FTTMR010_TM2_ISRMASK)) + ; +} + +void reset_timer_masked(void) +{ + ulong freq = gd->arch.timer_rate_hz; + + /* Disable Timer1 */ + clrbits_le32(®s->cr, FTTMR010_TM1_CRMASK); + + /* Disable & Clear Timer1 interrupts */ + writel(FTTMR010_TM1_ISRMASK, ®s->interrupt_mask); + writel(FTTMR010_TM1_ISRMASK, ®s->interrupt_state); + + /* Setup a longest periodic timer */ + writel((0xffffffff / freq) * freq, ®s->timer1_counter); + writel((0xffffffff / freq) * freq, ®s->timer1_load); + + writel(0, ®s->timer1_match1); + writel(0, ®s->timer1_match2); + + /* Disable match interrupts */ + writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2, + ®s->interrupt_mask); + + /* Enable Timer1 with overflow interrupt */ + setbits_le32(®s->cr, + FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE); +} + +ulong get_timer_masked(void) +{ + ulong freq = gd->arch.timer_rate_hz; + ulong secs = 0xffffffff / freq; + ulong ms = freq / CONFIG_SYS_HZ; + + if (readl(®s->interrupt_state) & FTTMR010_TM1_ISRMASK) { + writel(FTTMR010_TM1_ISRMASK, ®s->interrupt_state); + gd->arch.tbl += secs * CONFIG_SYS_HZ; + } + + return gd->arch.tbl + + ((secs * freq) - readl(®s->timer1_counter)) / ms; +} + +int timer_init(void) +{ + gd->arch.tbl = 0; + reset_timer_masked(); + return 0; +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void __udelay(unsigned long usec) +{ + udelay_masked(usec); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h index 2ab68d1..21ab113 100644 --- a/include/faraday/fttmr010.h +++ b/include/faraday/fttmr010.h @@ -45,6 +45,16 @@ struct fttmr010 { #define FTTMR010_TM1_CLOCK (1 << 1) #define FTTMR010_TM1_ENABLE (1 << 0) +#define FTTMR010_TM1_CRMASK \ + (FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \ + | FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE) +#define FTTMR010_TM2_CRMASK \ + (FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \ + | FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE) +#define FTTMR010_TM3_CRMASK \ + (FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \ + | FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE) + /* * Timer Interrupt State & Mask Registers */ @@ -58,4 +68,11 @@ struct fttmr010 { #define FTTMR010_TM1_MATCH2 (1 << 1) #define FTTMR010_TM1_MATCH1 (1 << 0) +#define FTTMR010_TM1_ISRMASK \ + (FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1) +#define FTTMR010_TM2_ISRMASK \ + (FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1) +#define FTTMR010_TM3_ISRMASK \ + (FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1) + #endif /* __FTTMR010_H */ -- 1.7.9.5