18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/clocksource/timer-sp.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999 - 2003 ARM Limited 68c2ecf20Sopenharmony_ci * Copyright (C) 2000 Deep Blue Solutions Ltd 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 108c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/irq.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci#include <linux/of_clk.h> 188c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 198c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "timer-sp.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Hisilicon 64-bit timer(a variant of ARM SP804) */ 248c2ecf20Sopenharmony_ci#define HISI_TIMER_1_BASE 0x00 258c2ecf20Sopenharmony_ci#define HISI_TIMER_2_BASE 0x40 268c2ecf20Sopenharmony_ci#define HISI_TIMER_LOAD 0x00 278c2ecf20Sopenharmony_ci#define HISI_TIMER_LOAD_H 0x04 288c2ecf20Sopenharmony_ci#define HISI_TIMER_VALUE 0x08 298c2ecf20Sopenharmony_ci#define HISI_TIMER_VALUE_H 0x0c 308c2ecf20Sopenharmony_ci#define HISI_TIMER_CTRL 0x10 318c2ecf20Sopenharmony_ci#define HISI_TIMER_INTCLR 0x14 328c2ecf20Sopenharmony_ci#define HISI_TIMER_RIS 0x18 338c2ecf20Sopenharmony_ci#define HISI_TIMER_MIS 0x1c 348c2ecf20Sopenharmony_ci#define HISI_TIMER_BGLOAD 0x20 358c2ecf20Sopenharmony_ci#define HISI_TIMER_BGLOAD_H 0x24 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct sp804_timer __initdata arm_sp804_timer = { 398c2ecf20Sopenharmony_ci .load = TIMER_LOAD, 408c2ecf20Sopenharmony_ci .value = TIMER_VALUE, 418c2ecf20Sopenharmony_ci .ctrl = TIMER_CTRL, 428c2ecf20Sopenharmony_ci .intclr = TIMER_INTCLR, 438c2ecf20Sopenharmony_ci .timer_base = {TIMER_1_BASE, TIMER_2_BASE}, 448c2ecf20Sopenharmony_ci .width = 32, 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct sp804_timer __initdata hisi_sp804_timer = { 488c2ecf20Sopenharmony_ci .load = HISI_TIMER_LOAD, 498c2ecf20Sopenharmony_ci .load_h = HISI_TIMER_LOAD_H, 508c2ecf20Sopenharmony_ci .value = HISI_TIMER_VALUE, 518c2ecf20Sopenharmony_ci .value_h = HISI_TIMER_VALUE_H, 528c2ecf20Sopenharmony_ci .ctrl = HISI_TIMER_CTRL, 538c2ecf20Sopenharmony_ci .intclr = HISI_TIMER_INTCLR, 548c2ecf20Sopenharmony_ci .timer_base = {HISI_TIMER_1_BASE, HISI_TIMER_2_BASE}, 558c2ecf20Sopenharmony_ci .width = 64, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct sp804_clkevt sp804_clkevt[NR_TIMERS]; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic long __init sp804_get_clock_rate(struct clk *clk, const char *name) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci long rate; 638c2ecf20Sopenharmony_ci int err; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!clk) 668c2ecf20Sopenharmony_ci clk = clk_get_sys("sp804", name); 678c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 688c2ecf20Sopenharmony_ci pr_err("sp804: %s clock not found: %ld\n", name, PTR_ERR(clk)); 698c2ecf20Sopenharmony_ci return PTR_ERR(clk); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci err = clk_prepare(clk); 738c2ecf20Sopenharmony_ci if (err) { 748c2ecf20Sopenharmony_ci pr_err("sp804: clock failed to prepare: %d\n", err); 758c2ecf20Sopenharmony_ci clk_put(clk); 768c2ecf20Sopenharmony_ci return err; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci err = clk_enable(clk); 808c2ecf20Sopenharmony_ci if (err) { 818c2ecf20Sopenharmony_ci pr_err("sp804: clock failed to enable: %d\n", err); 828c2ecf20Sopenharmony_ci clk_unprepare(clk); 838c2ecf20Sopenharmony_ci clk_put(clk); 848c2ecf20Sopenharmony_ci return err; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci rate = clk_get_rate(clk); 888c2ecf20Sopenharmony_ci if (rate < 0) { 898c2ecf20Sopenharmony_ci pr_err("sp804: clock failed to get rate: %ld\n", rate); 908c2ecf20Sopenharmony_ci clk_disable(clk); 918c2ecf20Sopenharmony_ci clk_unprepare(clk); 928c2ecf20Sopenharmony_ci clk_put(clk); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return rate; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic struct sp804_clkevt * __init sp804_clkevt_get(void __iomem *base) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int i; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci for (i = 0; i < NR_TIMERS; i++) { 1038c2ecf20Sopenharmony_ci if (sp804_clkevt[i].base == base) 1048c2ecf20Sopenharmony_ci return &sp804_clkevt[i]; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* It's impossible to reach here */ 1088c2ecf20Sopenharmony_ci WARN_ON(1); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return NULL; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct sp804_clkevt *sched_clkevt; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic u64 notrace sp804_read(void) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return ~readl_relaxed(sched_clkevt->value); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciint __init sp804_clocksource_and_sched_clock_init(void __iomem *base, 1218c2ecf20Sopenharmony_ci const char *name, 1228c2ecf20Sopenharmony_ci struct clk *clk, 1238c2ecf20Sopenharmony_ci int use_sched_clock) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci long rate; 1268c2ecf20Sopenharmony_ci struct sp804_clkevt *clkevt; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci rate = sp804_get_clock_rate(clk, name); 1298c2ecf20Sopenharmony_ci if (rate < 0) 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci clkevt = sp804_clkevt_get(base); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci writel(0, clkevt->ctrl); 1358c2ecf20Sopenharmony_ci writel(0xffffffff, clkevt->load); 1368c2ecf20Sopenharmony_ci writel(0xffffffff, clkevt->value); 1378c2ecf20Sopenharmony_ci if (clkevt->width == 64) { 1388c2ecf20Sopenharmony_ci writel(0xffffffff, clkevt->load_h); 1398c2ecf20Sopenharmony_ci writel(0xffffffff, clkevt->value_h); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, 1428c2ecf20Sopenharmony_ci clkevt->ctrl); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci clocksource_mmio_init(clkevt->value, name, 1458c2ecf20Sopenharmony_ci rate, 200, 32, clocksource_mmio_readl_down); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (use_sched_clock) { 1488c2ecf20Sopenharmony_ci sched_clkevt = clkevt; 1498c2ecf20Sopenharmony_ci sched_clock_register(sp804_read, 32, rate); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct sp804_clkevt *common_clkevt; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* 1598c2ecf20Sopenharmony_ci * IRQ handler for the timer 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistatic irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct clock_event_device *evt = dev_id; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* clear the interrupt */ 1668c2ecf20Sopenharmony_ci writel(1, common_clkevt->intclr); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci evt->event_handler(evt); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic inline void timer_shutdown(struct clock_event_device *evt) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci writel(0, common_clkevt->ctrl); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int sp804_shutdown(struct clock_event_device *evt) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci timer_shutdown(evt); 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int sp804_set_periodic(struct clock_event_device *evt) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | 1878c2ecf20Sopenharmony_ci TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci timer_shutdown(evt); 1908c2ecf20Sopenharmony_ci writel(common_clkevt->reload, common_clkevt->load); 1918c2ecf20Sopenharmony_ci writel(ctrl, common_clkevt->ctrl); 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int sp804_set_next_event(unsigned long next, 1968c2ecf20Sopenharmony_ci struct clock_event_device *evt) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | 1998c2ecf20Sopenharmony_ci TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci writel(next, common_clkevt->load); 2028c2ecf20Sopenharmony_ci writel(ctrl, common_clkevt->ctrl); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic struct clock_event_device sp804_clockevent = { 2088c2ecf20Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | 2098c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT | 2108c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_DYNIRQ, 2118c2ecf20Sopenharmony_ci .set_state_shutdown = sp804_shutdown, 2128c2ecf20Sopenharmony_ci .set_state_periodic = sp804_set_periodic, 2138c2ecf20Sopenharmony_ci .set_state_oneshot = sp804_shutdown, 2148c2ecf20Sopenharmony_ci .tick_resume = sp804_shutdown, 2158c2ecf20Sopenharmony_ci .set_next_event = sp804_set_next_event, 2168c2ecf20Sopenharmony_ci .rating = 300, 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint __init sp804_clockevents_init(void __iomem *base, unsigned int irq, 2208c2ecf20Sopenharmony_ci struct clk *clk, const char *name) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct clock_event_device *evt = &sp804_clockevent; 2238c2ecf20Sopenharmony_ci long rate; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci rate = sp804_get_clock_rate(clk, name); 2268c2ecf20Sopenharmony_ci if (rate < 0) 2278c2ecf20Sopenharmony_ci return -EINVAL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci common_clkevt = sp804_clkevt_get(base); 2308c2ecf20Sopenharmony_ci common_clkevt->reload = DIV_ROUND_CLOSEST(rate, HZ); 2318c2ecf20Sopenharmony_ci evt->name = name; 2328c2ecf20Sopenharmony_ci evt->irq = irq; 2338c2ecf20Sopenharmony_ci evt->cpumask = cpu_possible_mask; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci writel(0, common_clkevt->ctrl); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 2388c2ecf20Sopenharmony_ci "timer", &sp804_clockevent)) 2398c2ecf20Sopenharmony_ci pr_err("%s: request_irq() failed\n", "timer"); 2408c2ecf20Sopenharmony_ci clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void __init sp804_clkevt_init(struct sp804_timer *timer, void __iomem *base) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (i = 0; i < NR_TIMERS; i++) { 2508c2ecf20Sopenharmony_ci void __iomem *timer_base; 2518c2ecf20Sopenharmony_ci struct sp804_clkevt *clkevt; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci timer_base = base + timer->timer_base[i]; 2548c2ecf20Sopenharmony_ci clkevt = &sp804_clkevt[i]; 2558c2ecf20Sopenharmony_ci clkevt->base = timer_base; 2568c2ecf20Sopenharmony_ci clkevt->load = timer_base + timer->load; 2578c2ecf20Sopenharmony_ci clkevt->load_h = timer_base + timer->load_h; 2588c2ecf20Sopenharmony_ci clkevt->value = timer_base + timer->value; 2598c2ecf20Sopenharmony_ci clkevt->value_h = timer_base + timer->value_h; 2608c2ecf20Sopenharmony_ci clkevt->ctrl = timer_base + timer->ctrl; 2618c2ecf20Sopenharmony_ci clkevt->intclr = timer_base + timer->intclr; 2628c2ecf20Sopenharmony_ci clkevt->width = timer->width; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int __init sp804_of_init(struct device_node *np, struct sp804_timer *timer) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci static bool initialized = false; 2698c2ecf20Sopenharmony_ci void __iomem *base; 2708c2ecf20Sopenharmony_ci void __iomem *timer1_base; 2718c2ecf20Sopenharmony_ci void __iomem *timer2_base; 2728c2ecf20Sopenharmony_ci int irq, ret = -EINVAL; 2738c2ecf20Sopenharmony_ci u32 irq_num = 0; 2748c2ecf20Sopenharmony_ci struct clk *clk1, *clk2; 2758c2ecf20Sopenharmony_ci const char *name = of_get_property(np, "compatible", NULL); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (initialized) { 2788c2ecf20Sopenharmony_ci pr_debug("%pOF: skipping further SP804 timer device\n", np); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci base = of_iomap(np, 0); 2838c2ecf20Sopenharmony_ci if (!base) 2848c2ecf20Sopenharmony_ci return -ENXIO; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci timer1_base = base + timer->timer_base[0]; 2878c2ecf20Sopenharmony_ci timer2_base = base + timer->timer_base[1]; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Ensure timers are disabled */ 2908c2ecf20Sopenharmony_ci writel(0, timer1_base + timer->ctrl); 2918c2ecf20Sopenharmony_ci writel(0, timer2_base + timer->ctrl); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci clk1 = of_clk_get(np, 0); 2948c2ecf20Sopenharmony_ci if (IS_ERR(clk1)) 2958c2ecf20Sopenharmony_ci clk1 = NULL; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Get the 2nd clock if the timer has 3 timer clocks */ 2988c2ecf20Sopenharmony_ci if (of_clk_get_parent_count(np) == 3) { 2998c2ecf20Sopenharmony_ci clk2 = of_clk_get(np, 1); 3008c2ecf20Sopenharmony_ci if (IS_ERR(clk2)) { 3018c2ecf20Sopenharmony_ci pr_err("sp804: %pOFn clock not found: %d\n", np, 3028c2ecf20Sopenharmony_ci (int)PTR_ERR(clk2)); 3038c2ecf20Sopenharmony_ci clk2 = NULL; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } else 3068c2ecf20Sopenharmony_ci clk2 = clk1; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 3098c2ecf20Sopenharmony_ci if (irq <= 0) 3108c2ecf20Sopenharmony_ci goto err; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci sp804_clkevt_init(timer, base); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); 3158c2ecf20Sopenharmony_ci if (irq_num == 2) { 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ret = sp804_clockevents_init(timer2_base, irq, clk2, name); 3188c2ecf20Sopenharmony_ci if (ret) 3198c2ecf20Sopenharmony_ci goto err; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(timer1_base, 3228c2ecf20Sopenharmony_ci name, clk1, 1); 3238c2ecf20Sopenharmony_ci if (ret) 3248c2ecf20Sopenharmony_ci goto err; 3258c2ecf20Sopenharmony_ci } else { 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ret = sp804_clockevents_init(timer1_base, irq, clk1, name); 3288c2ecf20Sopenharmony_ci if (ret) 3298c2ecf20Sopenharmony_ci goto err; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(timer2_base, 3328c2ecf20Sopenharmony_ci name, clk2, 1); 3338c2ecf20Sopenharmony_ci if (ret) 3348c2ecf20Sopenharmony_ci goto err; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci initialized = true; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_cierr: 3408c2ecf20Sopenharmony_ci iounmap(base); 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int __init arm_sp804_of_init(struct device_node *np) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci return sp804_of_init(np, &arm_sp804_timer); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(sp804, "arm,sp804", arm_sp804_of_init); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int __init hisi_sp804_of_init(struct device_node *np) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci return sp804_of_init(np, &hisi_sp804_timer); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(hisi_sp804, "hisilicon,sp804", hisi_sp804_of_init); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int __init integrator_cp_of_init(struct device_node *np) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci static int init_count = 0; 3598c2ecf20Sopenharmony_ci void __iomem *base; 3608c2ecf20Sopenharmony_ci int irq, ret = -EINVAL; 3618c2ecf20Sopenharmony_ci const char *name = of_get_property(np, "compatible", NULL); 3628c2ecf20Sopenharmony_ci struct clk *clk; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci base = of_iomap(np, 0); 3658c2ecf20Sopenharmony_ci if (!base) { 3668c2ecf20Sopenharmony_ci pr_err("Failed to iomap\n"); 3678c2ecf20Sopenharmony_ci return -ENXIO; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci clk = of_clk_get(np, 0); 3718c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 3728c2ecf20Sopenharmony_ci pr_err("Failed to get clock\n"); 3738c2ecf20Sopenharmony_ci return PTR_ERR(clk); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* Ensure timer is disabled */ 3778c2ecf20Sopenharmony_ci writel(0, base + arm_sp804_timer.ctrl); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (init_count == 2 || !of_device_is_available(np)) 3808c2ecf20Sopenharmony_ci goto err; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci sp804_clkevt_init(&arm_sp804_timer, base); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!init_count) { 3858c2ecf20Sopenharmony_ci ret = sp804_clocksource_and_sched_clock_init(base, 3868c2ecf20Sopenharmony_ci name, clk, 0); 3878c2ecf20Sopenharmony_ci if (ret) 3888c2ecf20Sopenharmony_ci goto err; 3898c2ecf20Sopenharmony_ci } else { 3908c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 3918c2ecf20Sopenharmony_ci if (irq <= 0) 3928c2ecf20Sopenharmony_ci goto err; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci ret = sp804_clockevents_init(base, irq, clk, name); 3958c2ecf20Sopenharmony_ci if (ret) 3968c2ecf20Sopenharmony_ci goto err; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci init_count++; 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_cierr: 4028c2ecf20Sopenharmony_ci iounmap(base); 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); 406