162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/mach-pxa/time.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * PXA clocksource, clockevents, and OST interrupt handlers. 662306a36Sopenharmony_ci * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 962306a36Sopenharmony_ci * by MontaVista Software, Inc. (Nico, your code rocks!) 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/clk.h> 1662306a36Sopenharmony_ci#include <linux/clockchips.h> 1762306a36Sopenharmony_ci#include <linux/of_address.h> 1862306a36Sopenharmony_ci#include <linux/of_irq.h> 1962306a36Sopenharmony_ci#include <linux/sched/clock.h> 2062306a36Sopenharmony_ci#include <linux/sched_clock.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <clocksource/pxa.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm/div64.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define OSMR0 0x00 /* OS Timer 0 Match Register */ 2762306a36Sopenharmony_ci#define OSMR1 0x04 /* OS Timer 1 Match Register */ 2862306a36Sopenharmony_ci#define OSMR2 0x08 /* OS Timer 2 Match Register */ 2962306a36Sopenharmony_ci#define OSMR3 0x0C /* OS Timer 3 Match Register */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define OSCR 0x10 /* OS Timer Counter Register */ 3262306a36Sopenharmony_ci#define OSSR 0x14 /* OS Timer Status Register */ 3362306a36Sopenharmony_ci#define OWER 0x18 /* OS Timer Watchdog Enable Register */ 3462306a36Sopenharmony_ci#define OIER 0x1C /* OS Timer Interrupt Enable Register */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define OSSR_M3 (1 << 3) /* Match status channel 3 */ 3762306a36Sopenharmony_ci#define OSSR_M2 (1 << 2) /* Match status channel 2 */ 3862306a36Sopenharmony_ci#define OSSR_M1 (1 << 1) /* Match status channel 1 */ 3962306a36Sopenharmony_ci#define OSSR_M0 (1 << 0) /* Match status channel 0 */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * This is PXA's sched_clock implementation. This has a resolution 4562306a36Sopenharmony_ci * of at least 308 ns and a maximum value of 208 days. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * The return value is guaranteed to be monotonic in that range as 4862306a36Sopenharmony_ci * long as there is always less than 582 seconds between successive 4962306a36Sopenharmony_ci * calls to sched_clock() which should always be the case in practice. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define timer_readl(reg) readl_relaxed(timer_base + (reg)) 5362306a36Sopenharmony_ci#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg)) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void __iomem *timer_base; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic u64 notrace pxa_read_sched_clock(void) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci return timer_readl(OSCR); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define MIN_OSCR_DELTA 16 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic irqreturn_t 6662306a36Sopenharmony_cipxa_ost0_interrupt(int irq, void *dev_id) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct clock_event_device *c = dev_id; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Disarm the compare/match, signal the event. */ 7162306a36Sopenharmony_ci timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); 7262306a36Sopenharmony_ci timer_writel(OSSR_M0, OSSR); 7362306a36Sopenharmony_ci c->event_handler(c); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return IRQ_HANDLED; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int 7962306a36Sopenharmony_cipxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci unsigned long next, oscr; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci timer_writel(timer_readl(OIER) | OIER_E0, OIER); 8462306a36Sopenharmony_ci next = timer_readl(OSCR) + delta; 8562306a36Sopenharmony_ci timer_writel(next, OSMR0); 8662306a36Sopenharmony_ci oscr = timer_readl(OSCR); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int pxa_osmr0_shutdown(struct clock_event_device *evt) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci /* initializing, released, or preparing for suspend */ 9462306a36Sopenharmony_ci timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); 9562306a36Sopenharmony_ci timer_writel(OSSR_M0, OSSR); 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#ifdef CONFIG_PM 10062306a36Sopenharmony_cistatic unsigned long osmr[4], oier, oscr; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void pxa_timer_suspend(struct clock_event_device *cedev) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci osmr[0] = timer_readl(OSMR0); 10562306a36Sopenharmony_ci osmr[1] = timer_readl(OSMR1); 10662306a36Sopenharmony_ci osmr[2] = timer_readl(OSMR2); 10762306a36Sopenharmony_ci osmr[3] = timer_readl(OSMR3); 10862306a36Sopenharmony_ci oier = timer_readl(OIER); 10962306a36Sopenharmony_ci oscr = timer_readl(OSCR); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void pxa_timer_resume(struct clock_event_device *cedev) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci /* 11562306a36Sopenharmony_ci * Ensure that we have at least MIN_OSCR_DELTA between match 11662306a36Sopenharmony_ci * register 0 and the OSCR, to guarantee that we will receive 11762306a36Sopenharmony_ci * the one-shot timer interrupt. We adjust OSMR0 in preference 11862306a36Sopenharmony_ci * to OSCR to guarantee that OSCR is monotonically incrementing. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci if (osmr[0] - oscr < MIN_OSCR_DELTA) 12162306a36Sopenharmony_ci osmr[0] += MIN_OSCR_DELTA; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci timer_writel(osmr[0], OSMR0); 12462306a36Sopenharmony_ci timer_writel(osmr[1], OSMR1); 12562306a36Sopenharmony_ci timer_writel(osmr[2], OSMR2); 12662306a36Sopenharmony_ci timer_writel(osmr[3], OSMR3); 12762306a36Sopenharmony_ci timer_writel(oier, OIER); 12862306a36Sopenharmony_ci timer_writel(oscr, OSCR); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci#else 13162306a36Sopenharmony_ci#define pxa_timer_suspend NULL 13262306a36Sopenharmony_ci#define pxa_timer_resume NULL 13362306a36Sopenharmony_ci#endif 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct clock_event_device ckevt_pxa_osmr0 = { 13662306a36Sopenharmony_ci .name = "osmr0", 13762306a36Sopenharmony_ci .features = CLOCK_EVT_FEAT_ONESHOT, 13862306a36Sopenharmony_ci .rating = 200, 13962306a36Sopenharmony_ci .set_next_event = pxa_osmr0_set_next_event, 14062306a36Sopenharmony_ci .set_state_shutdown = pxa_osmr0_shutdown, 14162306a36Sopenharmony_ci .set_state_oneshot = pxa_osmr0_shutdown, 14262306a36Sopenharmony_ci .suspend = pxa_timer_suspend, 14362306a36Sopenharmony_ci .resume = pxa_timer_resume, 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci timer_writel(0, OIER); 15162306a36Sopenharmony_ci timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci ckevt_pxa_osmr0.cpumask = cpumask_of(0); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 15862306a36Sopenharmony_ci "ost0", &ckevt_pxa_osmr0); 15962306a36Sopenharmony_ci if (ret) { 16062306a36Sopenharmony_ci pr_err("Failed to setup irq\n"); 16162306a36Sopenharmony_ci return ret; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200, 16562306a36Sopenharmony_ci 32, clocksource_mmio_readl_up); 16662306a36Sopenharmony_ci if (ret) { 16762306a36Sopenharmony_ci pr_err("Failed to init clocksource\n"); 16862306a36Sopenharmony_ci return ret; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, 17262306a36Sopenharmony_ci MIN_OSCR_DELTA * 2, 0x7fffffff); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int __init pxa_timer_dt_init(struct device_node *np) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct clk *clk; 18062306a36Sopenharmony_ci int irq, ret; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* timer registers are shared with watchdog timer */ 18362306a36Sopenharmony_ci timer_base = of_iomap(np, 0); 18462306a36Sopenharmony_ci if (!timer_base) { 18562306a36Sopenharmony_ci pr_err("%pOFn: unable to map resource\n", np); 18662306a36Sopenharmony_ci return -ENXIO; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci clk = of_clk_get(np, 0); 19062306a36Sopenharmony_ci if (IS_ERR(clk)) { 19162306a36Sopenharmony_ci pr_crit("%pOFn: unable to get clk\n", np); 19262306a36Sopenharmony_ci return PTR_ERR(clk); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 19662306a36Sopenharmony_ci if (ret) { 19762306a36Sopenharmony_ci pr_crit("Failed to prepare clock\n"); 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* we are only interested in OS-timer0 irq */ 20262306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 20362306a36Sopenharmony_ci if (irq <= 0) { 20462306a36Sopenharmony_ci pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np); 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return pxa_timer_common_init(irq, clk_get_rate(clk)); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ciTIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * Legacy timer init for non device-tree boards. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_civoid __init pxa_timer_nodt_init(int irq, void __iomem *base) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct clk *clk; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci timer_base = base; 22062306a36Sopenharmony_ci clk = clk_get(NULL, "OSTIMER0"); 22162306a36Sopenharmony_ci if (clk && !IS_ERR(clk)) { 22262306a36Sopenharmony_ci clk_prepare_enable(clk); 22362306a36Sopenharmony_ci pxa_timer_common_init(irq, clk_get_rate(clk)); 22462306a36Sopenharmony_ci } else { 22562306a36Sopenharmony_ci pr_crit("%s: unable to get clk\n", __func__); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci} 228