18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/sizes.h> 98c2ecf20Sopenharmony_ci#include <asm/time.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <loongson1.h> 128c2ecf20Sopenharmony_ci#include <platform.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#ifdef CONFIG_CEVT_CSRC_LS1X 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#if defined(CONFIG_TIMER_USE_PWM1) 178c2ecf20Sopenharmony_ci#define LS1X_TIMER_BASE LS1X_PWM1_BASE 188c2ecf20Sopenharmony_ci#define LS1X_TIMER_IRQ LS1X_PWM1_IRQ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#elif defined(CONFIG_TIMER_USE_PWM2) 218c2ecf20Sopenharmony_ci#define LS1X_TIMER_BASE LS1X_PWM2_BASE 228c2ecf20Sopenharmony_ci#define LS1X_TIMER_IRQ LS1X_PWM2_IRQ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#elif defined(CONFIG_TIMER_USE_PWM3) 258c2ecf20Sopenharmony_ci#define LS1X_TIMER_BASE LS1X_PWM3_BASE 268c2ecf20Sopenharmony_ci#define LS1X_TIMER_IRQ LS1X_PWM3_IRQ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#else 298c2ecf20Sopenharmony_ci#define LS1X_TIMER_BASE LS1X_PWM0_BASE 308c2ecf20Sopenharmony_ci#define LS1X_TIMER_IRQ LS1X_PWM0_IRQ 318c2ecf20Sopenharmony_ci#endif 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciDEFINE_RAW_SPINLOCK(ls1x_timer_lock); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void __iomem *timer_reg_base; 368c2ecf20Sopenharmony_cistatic uint32_t ls1x_jiffies_per_tick; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline void ls1x_pwmtimer_set_period(uint32_t period) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci __raw_writel(period, timer_reg_base + PWM_HRC); 418c2ecf20Sopenharmony_ci __raw_writel(period, timer_reg_base + PWM_LRC); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline void ls1x_pwmtimer_restart(void) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci __raw_writel(0x0, timer_reg_base + PWM_CNT); 478c2ecf20Sopenharmony_ci __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid __init ls1x_pwmtimer_init(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci timer_reg_base = ioremap(LS1X_TIMER_BASE, SZ_16); 538c2ecf20Sopenharmony_ci if (!timer_reg_base) 548c2ecf20Sopenharmony_ci panic("Failed to remap timer registers"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); 598c2ecf20Sopenharmony_ci ls1x_pwmtimer_restart(); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic u64 ls1x_clocksource_read(struct clocksource *cs) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned long flags; 658c2ecf20Sopenharmony_ci int count; 668c2ecf20Sopenharmony_ci u32 jifs; 678c2ecf20Sopenharmony_ci static int old_count; 688c2ecf20Sopenharmony_ci static u32 old_jifs; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ls1x_timer_lock, flags); 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * Although our caller may have the read side of xtime_lock, 738c2ecf20Sopenharmony_ci * this is now a seqlock, and we are cheating in this routine 748c2ecf20Sopenharmony_ci * by having side effects on state that we cannot undo if 758c2ecf20Sopenharmony_ci * there is a collision on the seqlock and our caller has to 768c2ecf20Sopenharmony_ci * retry. (Namely, old_jifs and old_count.) So we must treat 778c2ecf20Sopenharmony_ci * jiffies as volatile despite the lock. We read jiffies 788c2ecf20Sopenharmony_ci * before latching the timer count to guarantee that although 798c2ecf20Sopenharmony_ci * the jiffies value might be older than the count (that is, 808c2ecf20Sopenharmony_ci * the counter may underflow between the last point where 818c2ecf20Sopenharmony_ci * jiffies was incremented and the point where we latch the 828c2ecf20Sopenharmony_ci * count), it cannot be newer. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci jifs = jiffies; 858c2ecf20Sopenharmony_ci /* read the count */ 868c2ecf20Sopenharmony_ci count = __raw_readl(timer_reg_base + PWM_CNT); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * It's possible for count to appear to go the wrong way for this 908c2ecf20Sopenharmony_ci * reason: 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * The timer counter underflows, but we haven't handled the resulting 938c2ecf20Sopenharmony_ci * interrupt and incremented jiffies yet. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Previous attempts to handle these cases intelligently were buggy, so 968c2ecf20Sopenharmony_ci * we just do the simple thing now. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (count < old_count && jifs == old_jifs) 998c2ecf20Sopenharmony_ci count = old_count; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci old_count = count; 1028c2ecf20Sopenharmony_ci old_jifs = jifs; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ls1x_timer_lock, flags); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return (u64) (jifs * ls1x_jiffies_per_tick) + count; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic struct clocksource ls1x_clocksource = { 1108c2ecf20Sopenharmony_ci .name = "ls1x-pwmtimer", 1118c2ecf20Sopenharmony_ci .read = ls1x_clocksource_read, 1128c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(24), 1138c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic irqreturn_t ls1x_clockevent_isr(int irq, void *devid) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct clock_event_device *cd = devid; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ls1x_pwmtimer_restart(); 1218c2ecf20Sopenharmony_ci cd->event_handler(cd); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci raw_spin_lock(&ls1x_timer_lock); 1298c2ecf20Sopenharmony_ci ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); 1308c2ecf20Sopenharmony_ci ls1x_pwmtimer_restart(); 1318c2ecf20Sopenharmony_ci __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); 1328c2ecf20Sopenharmony_ci raw_spin_unlock(&ls1x_timer_lock); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int ls1x_clockevent_tick_resume(struct clock_event_device *cd) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci raw_spin_lock(&ls1x_timer_lock); 1408c2ecf20Sopenharmony_ci __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); 1418c2ecf20Sopenharmony_ci raw_spin_unlock(&ls1x_timer_lock); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci raw_spin_lock(&ls1x_timer_lock); 1498c2ecf20Sopenharmony_ci __raw_writel(__raw_readl(timer_reg_base + PWM_CTRL) & ~CNT_EN, 1508c2ecf20Sopenharmony_ci timer_reg_base + PWM_CTRL); 1518c2ecf20Sopenharmony_ci raw_spin_unlock(&ls1x_timer_lock); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int ls1x_clockevent_set_next(unsigned long evt, 1578c2ecf20Sopenharmony_ci struct clock_event_device *cd) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci raw_spin_lock(&ls1x_timer_lock); 1608c2ecf20Sopenharmony_ci ls1x_pwmtimer_set_period(evt); 1618c2ecf20Sopenharmony_ci ls1x_pwmtimer_restart(); 1628c2ecf20Sopenharmony_ci raw_spin_unlock(&ls1x_timer_lock); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic struct clock_event_device ls1x_clockevent = { 1688c2ecf20Sopenharmony_ci .name = "ls1x-pwmtimer", 1698c2ecf20Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC, 1708c2ecf20Sopenharmony_ci .rating = 300, 1718c2ecf20Sopenharmony_ci .irq = LS1X_TIMER_IRQ, 1728c2ecf20Sopenharmony_ci .set_next_event = ls1x_clockevent_set_next, 1738c2ecf20Sopenharmony_ci .set_state_shutdown = ls1x_clockevent_set_state_shutdown, 1748c2ecf20Sopenharmony_ci .set_state_periodic = ls1x_clockevent_set_state_periodic, 1758c2ecf20Sopenharmony_ci .set_state_oneshot = ls1x_clockevent_set_state_shutdown, 1768c2ecf20Sopenharmony_ci .tick_resume = ls1x_clockevent_tick_resume, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void __init ls1x_time_init(void) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct clock_event_device *cd = &ls1x_clockevent; 1828c2ecf20Sopenharmony_ci int ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!mips_hpt_frequency) 1858c2ecf20Sopenharmony_ci panic("Invalid timer clock rate"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ls1x_pwmtimer_init(); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci clockevent_set_clock(cd, mips_hpt_frequency); 1908c2ecf20Sopenharmony_ci cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd); 1918c2ecf20Sopenharmony_ci cd->max_delta_ticks = 0xffffff; 1928c2ecf20Sopenharmony_ci cd->min_delta_ns = clockevent_delta2ns(0x000300, cd); 1938c2ecf20Sopenharmony_ci cd->min_delta_ticks = 0x000300; 1948c2ecf20Sopenharmony_ci cd->cpumask = cpumask_of(smp_processor_id()); 1958c2ecf20Sopenharmony_ci clockevents_register_device(cd); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ls1x_clocksource.rating = 200 + mips_hpt_frequency / 10000000; 1988c2ecf20Sopenharmony_ci ret = clocksource_register_hz(&ls1x_clocksource, mips_hpt_frequency); 1998c2ecf20Sopenharmony_ci if (ret) 2008c2ecf20Sopenharmony_ci panic(KERN_ERR "Failed to register clocksource: %d\n", ret); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (request_irq(LS1X_TIMER_IRQ, ls1x_clockevent_isr, 2038c2ecf20Sopenharmony_ci IRQF_PERCPU | IRQF_TIMER, "ls1x-pwmtimer", 2048c2ecf20Sopenharmony_ci &ls1x_clockevent)) 2058c2ecf20Sopenharmony_ci pr_err("Failed to register ls1x-pwmtimer interrupt\n"); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci#endif /* CONFIG_CEVT_CSRC_LS1X */ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_civoid __init plat_time_init(void) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct clk *clk = NULL; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* initialize LS1X clocks */ 2148c2ecf20Sopenharmony_ci ls1x_clk_init(); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#ifdef CONFIG_CEVT_CSRC_LS1X 2178c2ecf20Sopenharmony_ci /* setup LS1X PWM timer */ 2188c2ecf20Sopenharmony_ci clk = clk_get(NULL, "ls1x-pwmtimer"); 2198c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 2208c2ecf20Sopenharmony_ci panic("unable to get timer clock, err=%ld", PTR_ERR(clk)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mips_hpt_frequency = clk_get_rate(clk); 2238c2ecf20Sopenharmony_ci ls1x_time_init(); 2248c2ecf20Sopenharmony_ci#else 2258c2ecf20Sopenharmony_ci /* setup mips r4k timer */ 2268c2ecf20Sopenharmony_ci clk = clk_get(NULL, "cpu_clk"); 2278c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 2288c2ecf20Sopenharmony_ci panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci mips_hpt_frequency = clk_get_rate(clk) / 2; 2318c2ecf20Sopenharmony_ci#endif /* CONFIG_CEVT_CSRC_LS1X */ 2328c2ecf20Sopenharmony_ci} 233