162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Faraday Technology FTTMR010 timer driver 462306a36Sopenharmony_ci * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Based on a rewrite of arch/arm/mach-gemini/timer.c: 762306a36Sopenharmony_ci * Copyright (C) 2001-2006 Storlink, Corp. 862306a36Sopenharmony_ci * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci#include <linux/of_irq.h> 1562306a36Sopenharmony_ci#include <linux/clockchips.h> 1662306a36Sopenharmony_ci#include <linux/clocksource.h> 1762306a36Sopenharmony_ci#include <linux/sched_clock.h> 1862306a36Sopenharmony_ci#include <linux/clk.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/bitops.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * Register definitions common for all the timer variants. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#define TIMER1_COUNT (0x00) 2762306a36Sopenharmony_ci#define TIMER1_LOAD (0x04) 2862306a36Sopenharmony_ci#define TIMER1_MATCH1 (0x08) 2962306a36Sopenharmony_ci#define TIMER1_MATCH2 (0x0c) 3062306a36Sopenharmony_ci#define TIMER2_COUNT (0x10) 3162306a36Sopenharmony_ci#define TIMER2_LOAD (0x14) 3262306a36Sopenharmony_ci#define TIMER2_MATCH1 (0x18) 3362306a36Sopenharmony_ci#define TIMER2_MATCH2 (0x1c) 3462306a36Sopenharmony_ci#define TIMER3_COUNT (0x20) 3562306a36Sopenharmony_ci#define TIMER3_LOAD (0x24) 3662306a36Sopenharmony_ci#define TIMER3_MATCH1 (0x28) 3762306a36Sopenharmony_ci#define TIMER3_MATCH2 (0x2c) 3862306a36Sopenharmony_ci#define TIMER_CR (0x30) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Control register set to clear for ast2600 only. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci#define AST2600_TIMER_CR_CLR (0x3c) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Control register (TMC30) bit fields for fttmr010/gemini/moxart timers. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define TIMER_1_CR_ENABLE BIT(0) 4962306a36Sopenharmony_ci#define TIMER_1_CR_CLOCK BIT(1) 5062306a36Sopenharmony_ci#define TIMER_1_CR_INT BIT(2) 5162306a36Sopenharmony_ci#define TIMER_2_CR_ENABLE BIT(3) 5262306a36Sopenharmony_ci#define TIMER_2_CR_CLOCK BIT(4) 5362306a36Sopenharmony_ci#define TIMER_2_CR_INT BIT(5) 5462306a36Sopenharmony_ci#define TIMER_3_CR_ENABLE BIT(6) 5562306a36Sopenharmony_ci#define TIMER_3_CR_CLOCK BIT(7) 5662306a36Sopenharmony_ci#define TIMER_3_CR_INT BIT(8) 5762306a36Sopenharmony_ci#define TIMER_1_CR_UPDOWN BIT(9) 5862306a36Sopenharmony_ci#define TIMER_2_CR_UPDOWN BIT(10) 5962306a36Sopenharmony_ci#define TIMER_3_CR_UPDOWN BIT(11) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Control register (TMC30) bit fields for aspeed ast2400/ast2500 timers. 6362306a36Sopenharmony_ci * The aspeed timers move bits around in the control register and lacks 6462306a36Sopenharmony_ci * bits for setting the timer to count upwards. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define TIMER_1_CR_ASPEED_ENABLE BIT(0) 6762306a36Sopenharmony_ci#define TIMER_1_CR_ASPEED_CLOCK BIT(1) 6862306a36Sopenharmony_ci#define TIMER_1_CR_ASPEED_INT BIT(2) 6962306a36Sopenharmony_ci#define TIMER_2_CR_ASPEED_ENABLE BIT(4) 7062306a36Sopenharmony_ci#define TIMER_2_CR_ASPEED_CLOCK BIT(5) 7162306a36Sopenharmony_ci#define TIMER_2_CR_ASPEED_INT BIT(6) 7262306a36Sopenharmony_ci#define TIMER_3_CR_ASPEED_ENABLE BIT(8) 7362306a36Sopenharmony_ci#define TIMER_3_CR_ASPEED_CLOCK BIT(9) 7462306a36Sopenharmony_ci#define TIMER_3_CR_ASPEED_INT BIT(10) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Interrupt status/mask register definitions for fttmr010/gemini/moxart 7862306a36Sopenharmony_ci * timers. 7962306a36Sopenharmony_ci * The registers don't exist and they are not needed on aspeed timers 8062306a36Sopenharmony_ci * because: 8162306a36Sopenharmony_ci * - aspeed timer overflow interrupt is controlled by bits in Control 8262306a36Sopenharmony_ci * Register (TMC30). 8362306a36Sopenharmony_ci * - aspeed timers always generate interrupt when either one of the 8462306a36Sopenharmony_ci * Match registers equals to Status register. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci#define TIMER_INTR_STATE (0x34) 8762306a36Sopenharmony_ci#define TIMER_INTR_MASK (0x38) 8862306a36Sopenharmony_ci#define TIMER_1_INT_MATCH1 BIT(0) 8962306a36Sopenharmony_ci#define TIMER_1_INT_MATCH2 BIT(1) 9062306a36Sopenharmony_ci#define TIMER_1_INT_OVERFLOW BIT(2) 9162306a36Sopenharmony_ci#define TIMER_2_INT_MATCH1 BIT(3) 9262306a36Sopenharmony_ci#define TIMER_2_INT_MATCH2 BIT(4) 9362306a36Sopenharmony_ci#define TIMER_2_INT_OVERFLOW BIT(5) 9462306a36Sopenharmony_ci#define TIMER_3_INT_MATCH1 BIT(6) 9562306a36Sopenharmony_ci#define TIMER_3_INT_MATCH2 BIT(7) 9662306a36Sopenharmony_ci#define TIMER_3_INT_OVERFLOW BIT(8) 9762306a36Sopenharmony_ci#define TIMER_INT_ALL_MASK 0x1ff 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct fttmr010 { 10062306a36Sopenharmony_ci void __iomem *base; 10162306a36Sopenharmony_ci unsigned int tick_rate; 10262306a36Sopenharmony_ci bool is_aspeed; 10362306a36Sopenharmony_ci u32 t1_enable_val; 10462306a36Sopenharmony_ci struct clock_event_device clkevt; 10562306a36Sopenharmony_ci int (*timer_shutdown)(struct clock_event_device *evt); 10662306a36Sopenharmony_ci#ifdef CONFIG_ARM 10762306a36Sopenharmony_ci struct delay_timer delay_timer; 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * A local singleton used by sched_clock and delay timer reads, which are 11362306a36Sopenharmony_ci * fast and stateless 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic struct fttmr010 *local_fttmr; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return container_of(evt, struct fttmr010, clkevt); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic unsigned long fttmr010_read_current_timer_up(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return readl(local_fttmr->base + TIMER2_COUNT); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic unsigned long fttmr010_read_current_timer_down(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return ~readl(local_fttmr->base + TIMER2_COUNT); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic u64 notrace fttmr010_read_sched_clock_up(void) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return fttmr010_read_current_timer_up(); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic u64 notrace fttmr010_read_sched_clock_down(void) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return fttmr010_read_current_timer_down(); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int fttmr010_timer_set_next_event(unsigned long cycles, 14362306a36Sopenharmony_ci struct clock_event_device *evt) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 14662306a36Sopenharmony_ci u32 cr; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Stop */ 14962306a36Sopenharmony_ci fttmr010->timer_shutdown(evt); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (fttmr010->is_aspeed) { 15262306a36Sopenharmony_ci /* 15362306a36Sopenharmony_ci * ASPEED Timer Controller will load TIMER1_LOAD register 15462306a36Sopenharmony_ci * into TIMER1_COUNT register when the timer is re-enabled. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci writel(cycles, fttmr010->base + TIMER1_LOAD); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci /* Setup the match register forward in time */ 15962306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER1_COUNT); 16062306a36Sopenharmony_ci writel(cr + cycles, fttmr010->base + TIMER1_MATCH1); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Start */ 16462306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 16562306a36Sopenharmony_ci cr |= fttmr010->t1_enable_val; 16662306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int ast2600_timer_shutdown(struct clock_event_device *evt) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Stop */ 17662306a36Sopenharmony_ci writel(fttmr010->t1_enable_val, fttmr010->base + AST2600_TIMER_CR_CLR); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int fttmr010_timer_shutdown(struct clock_event_device *evt) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 18462306a36Sopenharmony_ci u32 cr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Stop */ 18762306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 18862306a36Sopenharmony_ci cr &= ~fttmr010->t1_enable_val; 18962306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int fttmr010_timer_set_oneshot(struct clock_event_device *evt) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 19762306a36Sopenharmony_ci u32 cr; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Stop */ 20062306a36Sopenharmony_ci fttmr010->timer_shutdown(evt); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Setup counter start from 0 or ~0 */ 20362306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_COUNT); 20462306a36Sopenharmony_ci if (fttmr010->is_aspeed) { 20562306a36Sopenharmony_ci writel(~0, fttmr010->base + TIMER1_LOAD); 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_LOAD); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Enable interrupt */ 21062306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER_INTR_MASK); 21162306a36Sopenharmony_ci cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 21262306a36Sopenharmony_ci cr |= TIMER_1_INT_MATCH1; 21362306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER_INTR_MASK); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int fttmr010_timer_set_periodic(struct clock_event_device *evt) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 22262306a36Sopenharmony_ci u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); 22362306a36Sopenharmony_ci u32 cr; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Stop */ 22662306a36Sopenharmony_ci fttmr010->timer_shutdown(evt); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Setup timer to fire at 1/HZ intervals. */ 22962306a36Sopenharmony_ci if (fttmr010->is_aspeed) { 23062306a36Sopenharmony_ci writel(period, fttmr010->base + TIMER1_LOAD); 23162306a36Sopenharmony_ci } else { 23262306a36Sopenharmony_ci cr = 0xffffffff - (period - 1); 23362306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER1_COUNT); 23462306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER1_LOAD); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Enable interrupt on overflow */ 23762306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER_INTR_MASK); 23862306a36Sopenharmony_ci cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 23962306a36Sopenharmony_ci cr |= TIMER_1_INT_OVERFLOW; 24062306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER_INTR_MASK); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Start the timer */ 24462306a36Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 24562306a36Sopenharmony_ci cr |= fttmr010->t1_enable_val; 24662306a36Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * IRQ handler for the timer 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci evt->event_handler(evt); 25962306a36Sopenharmony_ci return IRQ_HANDLED; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic irqreturn_t ast2600_timer_interrupt(int irq, void *dev_id) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct clock_event_device *evt = dev_id; 26562306a36Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci writel(0x1, fttmr010->base + TIMER_INTR_STATE); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci evt->event_handler(evt); 27062306a36Sopenharmony_ci return IRQ_HANDLED; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int __init fttmr010_common_init(struct device_node *np, 27462306a36Sopenharmony_ci bool is_aspeed, bool is_ast2600) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct fttmr010 *fttmr010; 27762306a36Sopenharmony_ci int irq; 27862306a36Sopenharmony_ci struct clk *clk; 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci u32 val; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * These implementations require a clock reference. 28462306a36Sopenharmony_ci * FIXME: we currently only support clocking using PCLK 28562306a36Sopenharmony_ci * and using EXTCLK is not supported in the driver. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci clk = of_clk_get_by_name(np, "PCLK"); 28862306a36Sopenharmony_ci if (IS_ERR(clk)) { 28962306a36Sopenharmony_ci pr_err("could not get PCLK\n"); 29062306a36Sopenharmony_ci return PTR_ERR(clk); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 29362306a36Sopenharmony_ci if (ret) { 29462306a36Sopenharmony_ci pr_err("failed to enable PCLK\n"); 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); 29962306a36Sopenharmony_ci if (!fttmr010) { 30062306a36Sopenharmony_ci ret = -ENOMEM; 30162306a36Sopenharmony_ci goto out_disable_clock; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci fttmr010->tick_rate = clk_get_rate(clk); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci fttmr010->base = of_iomap(np, 0); 30662306a36Sopenharmony_ci if (!fttmr010->base) { 30762306a36Sopenharmony_ci pr_err("Can't remap registers\n"); 30862306a36Sopenharmony_ci ret = -ENXIO; 30962306a36Sopenharmony_ci goto out_free; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci /* IRQ for timer 1 */ 31262306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 31362306a36Sopenharmony_ci if (irq <= 0) { 31462306a36Sopenharmony_ci pr_err("Can't parse IRQ\n"); 31562306a36Sopenharmony_ci ret = -EINVAL; 31662306a36Sopenharmony_ci goto out_unmap; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * The Aspeed timers move bits around in the control register. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci if (is_aspeed) { 32362306a36Sopenharmony_ci fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | 32462306a36Sopenharmony_ci TIMER_1_CR_ASPEED_INT; 32562306a36Sopenharmony_ci fttmr010->is_aspeed = true; 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* 33062306a36Sopenharmony_ci * Reset the interrupt mask and status 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 33362306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER_INTR_STATE); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Enable timer 1 count up, timer 2 count up, except on Aspeed, 33862306a36Sopenharmony_ci * where everything just counts down. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (is_aspeed) 34162306a36Sopenharmony_ci val = TIMER_2_CR_ASPEED_ENABLE; 34262306a36Sopenharmony_ci else { 34362306a36Sopenharmony_ci val = TIMER_2_CR_ENABLE | TIMER_1_CR_UPDOWN | 34462306a36Sopenharmony_ci TIMER_2_CR_UPDOWN; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci writel(val, fttmr010->base + TIMER_CR); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * Setup free-running clocksource timer (interrupts 35062306a36Sopenharmony_ci * disabled.) 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci local_fttmr = fttmr010; 35362306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER2_COUNT); 35462306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER2_MATCH1); 35562306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER2_MATCH2); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (fttmr010->is_aspeed) { 35862306a36Sopenharmony_ci writel(~0, fttmr010->base + TIMER2_LOAD); 35962306a36Sopenharmony_ci clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 36062306a36Sopenharmony_ci "FTTMR010-TIMER2", 36162306a36Sopenharmony_ci fttmr010->tick_rate, 36262306a36Sopenharmony_ci 300, 32, clocksource_mmio_readl_down); 36362306a36Sopenharmony_ci sched_clock_register(fttmr010_read_sched_clock_down, 32, 36462306a36Sopenharmony_ci fttmr010->tick_rate); 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER2_LOAD); 36762306a36Sopenharmony_ci clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 36862306a36Sopenharmony_ci "FTTMR010-TIMER2", 36962306a36Sopenharmony_ci fttmr010->tick_rate, 37062306a36Sopenharmony_ci 300, 32, clocksource_mmio_readl_up); 37162306a36Sopenharmony_ci sched_clock_register(fttmr010_read_sched_clock_up, 32, 37262306a36Sopenharmony_ci fttmr010->tick_rate); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Setup clockevent timer (interrupt-driven) on timer 1. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_COUNT); 37962306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_LOAD); 38062306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_MATCH1); 38162306a36Sopenharmony_ci writel(0, fttmr010->base + TIMER1_MATCH2); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (is_ast2600) { 38462306a36Sopenharmony_ci fttmr010->timer_shutdown = ast2600_timer_shutdown; 38562306a36Sopenharmony_ci ret = request_irq(irq, ast2600_timer_interrupt, 38662306a36Sopenharmony_ci IRQF_TIMER, "FTTMR010-TIMER1", 38762306a36Sopenharmony_ci &fttmr010->clkevt); 38862306a36Sopenharmony_ci } else { 38962306a36Sopenharmony_ci fttmr010->timer_shutdown = fttmr010_timer_shutdown; 39062306a36Sopenharmony_ci ret = request_irq(irq, fttmr010_timer_interrupt, 39162306a36Sopenharmony_ci IRQF_TIMER, "FTTMR010-TIMER1", 39262306a36Sopenharmony_ci &fttmr010->clkevt); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci if (ret) { 39562306a36Sopenharmony_ci pr_err("FTTMR010-TIMER1 no IRQ\n"); 39662306a36Sopenharmony_ci goto out_unmap; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci fttmr010->clkevt.name = "FTTMR010-TIMER1"; 40062306a36Sopenharmony_ci /* Reasonably fast and accurate clock event */ 40162306a36Sopenharmony_ci fttmr010->clkevt.rating = 300; 40262306a36Sopenharmony_ci fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | 40362306a36Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT; 40462306a36Sopenharmony_ci fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; 40562306a36Sopenharmony_ci fttmr010->clkevt.set_state_shutdown = fttmr010->timer_shutdown; 40662306a36Sopenharmony_ci fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; 40762306a36Sopenharmony_ci fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; 40862306a36Sopenharmony_ci fttmr010->clkevt.tick_resume = fttmr010->timer_shutdown; 40962306a36Sopenharmony_ci fttmr010->clkevt.cpumask = cpumask_of(0); 41062306a36Sopenharmony_ci fttmr010->clkevt.irq = irq; 41162306a36Sopenharmony_ci clockevents_config_and_register(&fttmr010->clkevt, 41262306a36Sopenharmony_ci fttmr010->tick_rate, 41362306a36Sopenharmony_ci 1, 0xffffffff); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci#ifdef CONFIG_ARM 41662306a36Sopenharmony_ci /* Also use this timer for delays */ 41762306a36Sopenharmony_ci if (fttmr010->is_aspeed) 41862306a36Sopenharmony_ci fttmr010->delay_timer.read_current_timer = 41962306a36Sopenharmony_ci fttmr010_read_current_timer_down; 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci fttmr010->delay_timer.read_current_timer = 42262306a36Sopenharmony_ci fttmr010_read_current_timer_up; 42362306a36Sopenharmony_ci fttmr010->delay_timer.freq = fttmr010->tick_rate; 42462306a36Sopenharmony_ci register_current_timer_delay(&fttmr010->delay_timer); 42562306a36Sopenharmony_ci#endif 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciout_unmap: 43062306a36Sopenharmony_ci iounmap(fttmr010->base); 43162306a36Sopenharmony_ciout_free: 43262306a36Sopenharmony_ci kfree(fttmr010); 43362306a36Sopenharmony_ciout_disable_clock: 43462306a36Sopenharmony_ci clk_disable_unprepare(clk); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic __init int ast2600_timer_init(struct device_node *np) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci return fttmr010_common_init(np, true, true); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic __init int aspeed_timer_init(struct device_node *np) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci return fttmr010_common_init(np, true, false); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic __init int fttmr010_timer_init(struct device_node *np) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci return fttmr010_common_init(np, false, false); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ciTIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 45562306a36Sopenharmony_ciTIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 45662306a36Sopenharmony_ciTIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init); 45762306a36Sopenharmony_ciTIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init); 45862306a36Sopenharmony_ciTIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init); 45962306a36Sopenharmony_ciTIMER_OF_DECLARE(ast2600, "aspeed,ast2600-timer", ast2600_timer_init); 460