18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Faraday Technology FTTMR010 timer driver 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on a rewrite of arch/arm/mach-gemini/timer.c: 78c2ecf20Sopenharmony_ci * Copyright (C) 2001-2006 Storlink, Corp. 88c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 158c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 168c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 178c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 188c2ecf20Sopenharmony_ci#include <linux/clk.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/bitops.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * Register definitions common for all the timer variants. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci#define TIMER1_COUNT (0x00) 278c2ecf20Sopenharmony_ci#define TIMER1_LOAD (0x04) 288c2ecf20Sopenharmony_ci#define TIMER1_MATCH1 (0x08) 298c2ecf20Sopenharmony_ci#define TIMER1_MATCH2 (0x0c) 308c2ecf20Sopenharmony_ci#define TIMER2_COUNT (0x10) 318c2ecf20Sopenharmony_ci#define TIMER2_LOAD (0x14) 328c2ecf20Sopenharmony_ci#define TIMER2_MATCH1 (0x18) 338c2ecf20Sopenharmony_ci#define TIMER2_MATCH2 (0x1c) 348c2ecf20Sopenharmony_ci#define TIMER3_COUNT (0x20) 358c2ecf20Sopenharmony_ci#define TIMER3_LOAD (0x24) 368c2ecf20Sopenharmony_ci#define TIMER3_MATCH1 (0x28) 378c2ecf20Sopenharmony_ci#define TIMER3_MATCH2 (0x2c) 388c2ecf20Sopenharmony_ci#define TIMER_CR (0x30) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * Control register set to clear for ast2600 only. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci#define AST2600_TIMER_CR_CLR (0x3c) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Control register (TMC30) bit fields for fttmr010/gemini/moxart timers. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci#define TIMER_1_CR_ENABLE BIT(0) 498c2ecf20Sopenharmony_ci#define TIMER_1_CR_CLOCK BIT(1) 508c2ecf20Sopenharmony_ci#define TIMER_1_CR_INT BIT(2) 518c2ecf20Sopenharmony_ci#define TIMER_2_CR_ENABLE BIT(3) 528c2ecf20Sopenharmony_ci#define TIMER_2_CR_CLOCK BIT(4) 538c2ecf20Sopenharmony_ci#define TIMER_2_CR_INT BIT(5) 548c2ecf20Sopenharmony_ci#define TIMER_3_CR_ENABLE BIT(6) 558c2ecf20Sopenharmony_ci#define TIMER_3_CR_CLOCK BIT(7) 568c2ecf20Sopenharmony_ci#define TIMER_3_CR_INT BIT(8) 578c2ecf20Sopenharmony_ci#define TIMER_1_CR_UPDOWN BIT(9) 588c2ecf20Sopenharmony_ci#define TIMER_2_CR_UPDOWN BIT(10) 598c2ecf20Sopenharmony_ci#define TIMER_3_CR_UPDOWN BIT(11) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Control register (TMC30) bit fields for aspeed ast2400/ast2500 timers. 638c2ecf20Sopenharmony_ci * The aspeed timers move bits around in the control register and lacks 648c2ecf20Sopenharmony_ci * bits for setting the timer to count upwards. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci#define TIMER_1_CR_ASPEED_ENABLE BIT(0) 678c2ecf20Sopenharmony_ci#define TIMER_1_CR_ASPEED_CLOCK BIT(1) 688c2ecf20Sopenharmony_ci#define TIMER_1_CR_ASPEED_INT BIT(2) 698c2ecf20Sopenharmony_ci#define TIMER_2_CR_ASPEED_ENABLE BIT(4) 708c2ecf20Sopenharmony_ci#define TIMER_2_CR_ASPEED_CLOCK BIT(5) 718c2ecf20Sopenharmony_ci#define TIMER_2_CR_ASPEED_INT BIT(6) 728c2ecf20Sopenharmony_ci#define TIMER_3_CR_ASPEED_ENABLE BIT(8) 738c2ecf20Sopenharmony_ci#define TIMER_3_CR_ASPEED_CLOCK BIT(9) 748c2ecf20Sopenharmony_ci#define TIMER_3_CR_ASPEED_INT BIT(10) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * Interrupt status/mask register definitions for fttmr010/gemini/moxart 788c2ecf20Sopenharmony_ci * timers. 798c2ecf20Sopenharmony_ci * The registers don't exist and they are not needed on aspeed timers 808c2ecf20Sopenharmony_ci * because: 818c2ecf20Sopenharmony_ci * - aspeed timer overflow interrupt is controlled by bits in Control 828c2ecf20Sopenharmony_ci * Register (TMC30). 838c2ecf20Sopenharmony_ci * - aspeed timers always generate interrupt when either one of the 848c2ecf20Sopenharmony_ci * Match registers equals to Status register. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define TIMER_INTR_STATE (0x34) 878c2ecf20Sopenharmony_ci#define TIMER_INTR_MASK (0x38) 888c2ecf20Sopenharmony_ci#define TIMER_1_INT_MATCH1 BIT(0) 898c2ecf20Sopenharmony_ci#define TIMER_1_INT_MATCH2 BIT(1) 908c2ecf20Sopenharmony_ci#define TIMER_1_INT_OVERFLOW BIT(2) 918c2ecf20Sopenharmony_ci#define TIMER_2_INT_MATCH1 BIT(3) 928c2ecf20Sopenharmony_ci#define TIMER_2_INT_MATCH2 BIT(4) 938c2ecf20Sopenharmony_ci#define TIMER_2_INT_OVERFLOW BIT(5) 948c2ecf20Sopenharmony_ci#define TIMER_3_INT_MATCH1 BIT(6) 958c2ecf20Sopenharmony_ci#define TIMER_3_INT_MATCH2 BIT(7) 968c2ecf20Sopenharmony_ci#define TIMER_3_INT_OVERFLOW BIT(8) 978c2ecf20Sopenharmony_ci#define TIMER_INT_ALL_MASK 0x1ff 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistruct fttmr010 { 1008c2ecf20Sopenharmony_ci void __iomem *base; 1018c2ecf20Sopenharmony_ci unsigned int tick_rate; 1028c2ecf20Sopenharmony_ci bool is_aspeed; 1038c2ecf20Sopenharmony_ci u32 t1_enable_val; 1048c2ecf20Sopenharmony_ci struct clock_event_device clkevt; 1058c2ecf20Sopenharmony_ci int (*timer_shutdown)(struct clock_event_device *evt); 1068c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM 1078c2ecf20Sopenharmony_ci struct delay_timer delay_timer; 1088c2ecf20Sopenharmony_ci#endif 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * A local singleton used by sched_clock and delay timer reads, which are 1138c2ecf20Sopenharmony_ci * fast and stateless 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistatic struct fttmr010 *local_fttmr; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline struct fttmr010 *to_fttmr010(struct clock_event_device *evt) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return container_of(evt, struct fttmr010, clkevt); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic unsigned long fttmr010_read_current_timer_up(void) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci return readl(local_fttmr->base + TIMER2_COUNT); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic unsigned long fttmr010_read_current_timer_down(void) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return ~readl(local_fttmr->base + TIMER2_COUNT); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic u64 notrace fttmr010_read_sched_clock_up(void) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return fttmr010_read_current_timer_up(); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic u64 notrace fttmr010_read_sched_clock_down(void) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci return fttmr010_read_current_timer_down(); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int fttmr010_timer_set_next_event(unsigned long cycles, 1438c2ecf20Sopenharmony_ci struct clock_event_device *evt) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 1468c2ecf20Sopenharmony_ci u32 cr; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Stop */ 1498c2ecf20Sopenharmony_ci fttmr010->timer_shutdown(evt); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (fttmr010->is_aspeed) { 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * ASPEED Timer Controller will load TIMER1_LOAD register 1548c2ecf20Sopenharmony_ci * into TIMER1_COUNT register when the timer is re-enabled. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci writel(cycles, fttmr010->base + TIMER1_LOAD); 1578c2ecf20Sopenharmony_ci } else { 1588c2ecf20Sopenharmony_ci /* Setup the match register forward in time */ 1598c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER1_COUNT); 1608c2ecf20Sopenharmony_ci writel(cr + cycles, fttmr010->base + TIMER1_MATCH1); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Start */ 1648c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 1658c2ecf20Sopenharmony_ci cr |= fttmr010->t1_enable_val; 1668c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int ast2600_timer_shutdown(struct clock_event_device *evt) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Stop */ 1768c2ecf20Sopenharmony_ci writel(fttmr010->t1_enable_val, fttmr010->base + AST2600_TIMER_CR_CLR); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int fttmr010_timer_shutdown(struct clock_event_device *evt) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 1848c2ecf20Sopenharmony_ci u32 cr; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Stop */ 1878c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 1888c2ecf20Sopenharmony_ci cr &= ~fttmr010->t1_enable_val; 1898c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int fttmr010_timer_set_oneshot(struct clock_event_device *evt) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 1978c2ecf20Sopenharmony_ci u32 cr; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Stop */ 2008c2ecf20Sopenharmony_ci fttmr010->timer_shutdown(evt); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Setup counter start from 0 or ~0 */ 2038c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_COUNT); 2048c2ecf20Sopenharmony_ci if (fttmr010->is_aspeed) { 2058c2ecf20Sopenharmony_ci writel(~0, fttmr010->base + TIMER1_LOAD); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_LOAD); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Enable interrupt */ 2108c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER_INTR_MASK); 2118c2ecf20Sopenharmony_ci cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); 2128c2ecf20Sopenharmony_ci cr |= TIMER_1_INT_MATCH1; 2138c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER_INTR_MASK); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int fttmr010_timer_set_periodic(struct clock_event_device *evt) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 2228c2ecf20Sopenharmony_ci u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); 2238c2ecf20Sopenharmony_ci u32 cr; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Stop */ 2268c2ecf20Sopenharmony_ci fttmr010->timer_shutdown(evt); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Setup timer to fire at 1/HZ intervals. */ 2298c2ecf20Sopenharmony_ci if (fttmr010->is_aspeed) { 2308c2ecf20Sopenharmony_ci writel(period, fttmr010->base + TIMER1_LOAD); 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci cr = 0xffffffff - (period - 1); 2338c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER1_COUNT); 2348c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER1_LOAD); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Enable interrupt on overflow */ 2378c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER_INTR_MASK); 2388c2ecf20Sopenharmony_ci cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); 2398c2ecf20Sopenharmony_ci cr |= TIMER_1_INT_OVERFLOW; 2408c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER_INTR_MASK); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Start the timer */ 2448c2ecf20Sopenharmony_ci cr = readl(fttmr010->base + TIMER_CR); 2458c2ecf20Sopenharmony_ci cr |= fttmr010->t1_enable_val; 2468c2ecf20Sopenharmony_ci writel(cr, fttmr010->base + TIMER_CR); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* 2528c2ecf20Sopenharmony_ci * IRQ handler for the timer 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct clock_event_device *evt = dev_id; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci evt->event_handler(evt); 2598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic irqreturn_t ast2600_timer_interrupt(int irq, void *dev_id) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct clock_event_device *evt = dev_id; 2658c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010 = to_fttmr010(evt); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci writel(0x1, fttmr010->base + TIMER_INTR_STATE); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci evt->event_handler(evt); 2708c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int __init fttmr010_common_init(struct device_node *np, 2748c2ecf20Sopenharmony_ci bool is_aspeed, 2758c2ecf20Sopenharmony_ci int (*timer_shutdown)(struct clock_event_device *), 2768c2ecf20Sopenharmony_ci irq_handler_t irq_handler) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct fttmr010 *fttmr010; 2798c2ecf20Sopenharmony_ci int irq; 2808c2ecf20Sopenharmony_ci struct clk *clk; 2818c2ecf20Sopenharmony_ci int ret; 2828c2ecf20Sopenharmony_ci u32 val; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * These implementations require a clock reference. 2868c2ecf20Sopenharmony_ci * FIXME: we currently only support clocking using PCLK 2878c2ecf20Sopenharmony_ci * and using EXTCLK is not supported in the driver. 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci clk = of_clk_get_by_name(np, "PCLK"); 2908c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 2918c2ecf20Sopenharmony_ci pr_err("could not get PCLK\n"); 2928c2ecf20Sopenharmony_ci return PTR_ERR(clk); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 2958c2ecf20Sopenharmony_ci if (ret) { 2968c2ecf20Sopenharmony_ci pr_err("failed to enable PCLK\n"); 2978c2ecf20Sopenharmony_ci return ret; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci fttmr010 = kzalloc(sizeof(*fttmr010), GFP_KERNEL); 3018c2ecf20Sopenharmony_ci if (!fttmr010) { 3028c2ecf20Sopenharmony_ci ret = -ENOMEM; 3038c2ecf20Sopenharmony_ci goto out_disable_clock; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci fttmr010->tick_rate = clk_get_rate(clk); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci fttmr010->base = of_iomap(np, 0); 3088c2ecf20Sopenharmony_ci if (!fttmr010->base) { 3098c2ecf20Sopenharmony_ci pr_err("Can't remap registers\n"); 3108c2ecf20Sopenharmony_ci ret = -ENXIO; 3118c2ecf20Sopenharmony_ci goto out_free; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci /* IRQ for timer 1 */ 3148c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 3158c2ecf20Sopenharmony_ci if (irq <= 0) { 3168c2ecf20Sopenharmony_ci pr_err("Can't parse IRQ\n"); 3178c2ecf20Sopenharmony_ci ret = -EINVAL; 3188c2ecf20Sopenharmony_ci goto out_unmap; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* 3228c2ecf20Sopenharmony_ci * The Aspeed timers move bits around in the control register. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci if (is_aspeed) { 3258c2ecf20Sopenharmony_ci fttmr010->t1_enable_val = TIMER_1_CR_ASPEED_ENABLE | 3268c2ecf20Sopenharmony_ci TIMER_1_CR_ASPEED_INT; 3278c2ecf20Sopenharmony_ci fttmr010->is_aspeed = true; 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci fttmr010->t1_enable_val = TIMER_1_CR_ENABLE | TIMER_1_CR_INT; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * Reset the interrupt mask and status 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci writel(TIMER_INT_ALL_MASK, fttmr010->base + TIMER_INTR_MASK); 3358c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER_INTR_STATE); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * Enable timer 1 count up, timer 2 count up, except on Aspeed, 3408c2ecf20Sopenharmony_ci * where everything just counts down. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (is_aspeed) 3438c2ecf20Sopenharmony_ci val = TIMER_2_CR_ASPEED_ENABLE; 3448c2ecf20Sopenharmony_ci else { 3458c2ecf20Sopenharmony_ci val = TIMER_2_CR_ENABLE | TIMER_1_CR_UPDOWN | 3468c2ecf20Sopenharmony_ci TIMER_2_CR_UPDOWN; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci writel(val, fttmr010->base + TIMER_CR); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* 3518c2ecf20Sopenharmony_ci * Setup free-running clocksource timer (interrupts 3528c2ecf20Sopenharmony_ci * disabled.) 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci local_fttmr = fttmr010; 3558c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER2_COUNT); 3568c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER2_MATCH1); 3578c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER2_MATCH2); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (fttmr010->is_aspeed) { 3608c2ecf20Sopenharmony_ci writel(~0, fttmr010->base + TIMER2_LOAD); 3618c2ecf20Sopenharmony_ci clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 3628c2ecf20Sopenharmony_ci "FTTMR010-TIMER2", 3638c2ecf20Sopenharmony_ci fttmr010->tick_rate, 3648c2ecf20Sopenharmony_ci 300, 32, clocksource_mmio_readl_down); 3658c2ecf20Sopenharmony_ci sched_clock_register(fttmr010_read_sched_clock_down, 32, 3668c2ecf20Sopenharmony_ci fttmr010->tick_rate); 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER2_LOAD); 3698c2ecf20Sopenharmony_ci clocksource_mmio_init(fttmr010->base + TIMER2_COUNT, 3708c2ecf20Sopenharmony_ci "FTTMR010-TIMER2", 3718c2ecf20Sopenharmony_ci fttmr010->tick_rate, 3728c2ecf20Sopenharmony_ci 300, 32, clocksource_mmio_readl_up); 3738c2ecf20Sopenharmony_ci sched_clock_register(fttmr010_read_sched_clock_up, 32, 3748c2ecf20Sopenharmony_ci fttmr010->tick_rate); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci fttmr010->timer_shutdown = timer_shutdown; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * Setup clockevent timer (interrupt-driven) on timer 1. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_COUNT); 3838c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_LOAD); 3848c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_MATCH1); 3858c2ecf20Sopenharmony_ci writel(0, fttmr010->base + TIMER1_MATCH2); 3868c2ecf20Sopenharmony_ci ret = request_irq(irq, irq_handler, IRQF_TIMER, 3878c2ecf20Sopenharmony_ci "FTTMR010-TIMER1", &fttmr010->clkevt); 3888c2ecf20Sopenharmony_ci if (ret) { 3898c2ecf20Sopenharmony_ci pr_err("FTTMR010-TIMER1 no IRQ\n"); 3908c2ecf20Sopenharmony_ci goto out_unmap; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci fttmr010->clkevt.name = "FTTMR010-TIMER1"; 3948c2ecf20Sopenharmony_ci /* Reasonably fast and accurate clock event */ 3958c2ecf20Sopenharmony_ci fttmr010->clkevt.rating = 300; 3968c2ecf20Sopenharmony_ci fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | 3978c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT; 3988c2ecf20Sopenharmony_ci fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event; 3998c2ecf20Sopenharmony_ci fttmr010->clkevt.set_state_shutdown = fttmr010->timer_shutdown; 4008c2ecf20Sopenharmony_ci fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic; 4018c2ecf20Sopenharmony_ci fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot; 4028c2ecf20Sopenharmony_ci fttmr010->clkevt.tick_resume = fttmr010->timer_shutdown; 4038c2ecf20Sopenharmony_ci fttmr010->clkevt.cpumask = cpumask_of(0); 4048c2ecf20Sopenharmony_ci fttmr010->clkevt.irq = irq; 4058c2ecf20Sopenharmony_ci clockevents_config_and_register(&fttmr010->clkevt, 4068c2ecf20Sopenharmony_ci fttmr010->tick_rate, 4078c2ecf20Sopenharmony_ci 1, 0xffffffff); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM 4108c2ecf20Sopenharmony_ci /* Also use this timer for delays */ 4118c2ecf20Sopenharmony_ci if (fttmr010->is_aspeed) 4128c2ecf20Sopenharmony_ci fttmr010->delay_timer.read_current_timer = 4138c2ecf20Sopenharmony_ci fttmr010_read_current_timer_down; 4148c2ecf20Sopenharmony_ci else 4158c2ecf20Sopenharmony_ci fttmr010->delay_timer.read_current_timer = 4168c2ecf20Sopenharmony_ci fttmr010_read_current_timer_up; 4178c2ecf20Sopenharmony_ci fttmr010->delay_timer.freq = fttmr010->tick_rate; 4188c2ecf20Sopenharmony_ci register_current_timer_delay(&fttmr010->delay_timer); 4198c2ecf20Sopenharmony_ci#endif 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciout_unmap: 4248c2ecf20Sopenharmony_ci iounmap(fttmr010->base); 4258c2ecf20Sopenharmony_ciout_free: 4268c2ecf20Sopenharmony_ci kfree(fttmr010); 4278c2ecf20Sopenharmony_ciout_disable_clock: 4288c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic __init int ast2600_timer_init(struct device_node *np) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci return fttmr010_common_init(np, true, 4368c2ecf20Sopenharmony_ci ast2600_timer_shutdown, 4378c2ecf20Sopenharmony_ci ast2600_timer_interrupt); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic __init int aspeed_timer_init(struct device_node *np) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci return fttmr010_common_init(np, true, 4438c2ecf20Sopenharmony_ci fttmr010_timer_shutdown, 4448c2ecf20Sopenharmony_ci fttmr010_timer_interrupt); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic __init int fttmr010_timer_init(struct device_node *np) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci return fttmr010_common_init(np, false, 4508c2ecf20Sopenharmony_ci fttmr010_timer_shutdown, 4518c2ecf20Sopenharmony_ci fttmr010_timer_interrupt); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init); 4558c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init); 4568c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init); 4578c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init); 4588c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init); 4598c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(ast2600, "aspeed,ast2600-timer", ast2600_timer_init); 460