brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 7ad0e5a Raw
228 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * arch/arm/mach-pxa/time.c4 *5 * PXA clocksource, clockevents, and OST interrupt handlers.6 * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.7 *8 * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 20019 * by MontaVista Software, Inc.  (Nico, your code rocks!)10 */11 12#include <linux/kernel.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/clk.h>16#include <linux/clockchips.h>17#include <linux/of_address.h>18#include <linux/of_irq.h>19#include <linux/sched/clock.h>20#include <linux/sched_clock.h>21 22#include <clocksource/pxa.h>23 24#include <asm/div64.h>25 26#define OSMR0		0x00	/* OS Timer 0 Match Register */27#define OSMR1		0x04	/* OS Timer 1 Match Register */28#define OSMR2		0x08	/* OS Timer 2 Match Register */29#define OSMR3		0x0C	/* OS Timer 3 Match Register */30 31#define OSCR		0x10	/* OS Timer Counter Register */32#define OSSR		0x14	/* OS Timer Status Register */33#define OWER		0x18	/* OS Timer Watchdog Enable Register */34#define OIER		0x1C	/* OS Timer Interrupt Enable Register */35 36#define OSSR_M3		(1 << 3)	/* Match status channel 3 */37#define OSSR_M2		(1 << 2)	/* Match status channel 2 */38#define OSSR_M1		(1 << 1)	/* Match status channel 1 */39#define OSSR_M0		(1 << 0)	/* Match status channel 0 */40 41#define OIER_E0		(1 << 0)	/* Interrupt enable channel 0 */42 43/*44 * This is PXA's sched_clock implementation. This has a resolution45 * of at least 308 ns and a maximum value of 208 days.46 *47 * The return value is guaranteed to be monotonic in that range as48 * long as there is always less than 582 seconds between successive49 * calls to sched_clock() which should always be the case in practice.50 */51 52#define timer_readl(reg) readl_relaxed(timer_base + (reg))53#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))54 55static void __iomem *timer_base;56 57static u64 notrace pxa_read_sched_clock(void)58{59	return timer_readl(OSCR);60}61 62 63#define MIN_OSCR_DELTA 1664 65static irqreturn_t66pxa_ost0_interrupt(int irq, void *dev_id)67{68	struct clock_event_device *c = dev_id;69 70	/* Disarm the compare/match, signal the event. */71	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);72	timer_writel(OSSR_M0, OSSR);73	c->event_handler(c);74 75	return IRQ_HANDLED;76}77 78static int79pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)80{81	unsigned long next, oscr;82 83	timer_writel(timer_readl(OIER) | OIER_E0, OIER);84	next = timer_readl(OSCR) + delta;85	timer_writel(next, OSMR0);86	oscr = timer_readl(OSCR);87 88	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;89}90 91static int pxa_osmr0_shutdown(struct clock_event_device *evt)92{93	/* initializing, released, or preparing for suspend */94	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);95	timer_writel(OSSR_M0, OSSR);96	return 0;97}98 99#ifdef CONFIG_PM100static unsigned long osmr[4], oier, oscr;101 102static void pxa_timer_suspend(struct clock_event_device *cedev)103{104	osmr[0] = timer_readl(OSMR0);105	osmr[1] = timer_readl(OSMR1);106	osmr[2] = timer_readl(OSMR2);107	osmr[3] = timer_readl(OSMR3);108	oier = timer_readl(OIER);109	oscr = timer_readl(OSCR);110}111 112static void pxa_timer_resume(struct clock_event_device *cedev)113{114	/*115	 * Ensure that we have at least MIN_OSCR_DELTA between match116	 * register 0 and the OSCR, to guarantee that we will receive117	 * the one-shot timer interrupt.  We adjust OSMR0 in preference118	 * to OSCR to guarantee that OSCR is monotonically incrementing.119	 */120	if (osmr[0] - oscr < MIN_OSCR_DELTA)121		osmr[0] += MIN_OSCR_DELTA;122 123	timer_writel(osmr[0], OSMR0);124	timer_writel(osmr[1], OSMR1);125	timer_writel(osmr[2], OSMR2);126	timer_writel(osmr[3], OSMR3);127	timer_writel(oier, OIER);128	timer_writel(oscr, OSCR);129}130#else131#define pxa_timer_suspend NULL132#define pxa_timer_resume NULL133#endif134 135static struct clock_event_device ckevt_pxa_osmr0 = {136	.name			= "osmr0",137	.features		= CLOCK_EVT_FEAT_ONESHOT,138	.rating			= 200,139	.set_next_event		= pxa_osmr0_set_next_event,140	.set_state_shutdown	= pxa_osmr0_shutdown,141	.set_state_oneshot	= pxa_osmr0_shutdown,142	.suspend		= pxa_timer_suspend,143	.resume			= pxa_timer_resume,144};145 146static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)147{148	int ret;149 150	timer_writel(0, OIER);151	timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);152 153	sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);154 155	ckevt_pxa_osmr0.cpumask = cpumask_of(0);156 157	ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL,158			  "ost0", &ckevt_pxa_osmr0);159	if (ret) {160		pr_err("Failed to setup irq\n");161		return ret;162	}163 164	ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,165				    32, clocksource_mmio_readl_up);166	if (ret) {167		pr_err("Failed to init clocksource\n");168		return ret;169	}170 171	clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,172					MIN_OSCR_DELTA * 2, 0x7fffffff);173 174	return 0;175}176 177static int __init pxa_timer_dt_init(struct device_node *np)178{179	struct clk *clk;180	int irq, ret;181 182	/* timer registers are shared with watchdog timer */183	timer_base = of_iomap(np, 0);184	if (!timer_base) {185		pr_err("%pOFn: unable to map resource\n", np);186		return -ENXIO;187	}188 189	clk = of_clk_get(np, 0);190	if (IS_ERR(clk)) {191		pr_crit("%pOFn: unable to get clk\n", np);192		return PTR_ERR(clk);193	}194 195	ret = clk_prepare_enable(clk);196	if (ret) {197		pr_crit("Failed to prepare clock\n");198		return ret;199	}200 201	/* we are only interested in OS-timer0 irq */202	irq = irq_of_parse_and_map(np, 0);203	if (irq <= 0) {204		pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np);205		return -EINVAL;206	}207 208	return pxa_timer_common_init(irq, clk_get_rate(clk));209}210TIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);211 212/*213 * Legacy timer init for non device-tree boards.214 */215void __init pxa_timer_nodt_init(int irq, void __iomem *base)216{217	struct clk *clk;218 219	timer_base = base;220	clk = clk_get(NULL, "OSTIMER0");221	if (clk && !IS_ERR(clk)) {222		clk_prepare_enable(clk);223		pxa_timer_common_init(irq, clk_get_rate(clk));224	} else {225		pr_crit("%s: unable to get clk\n", __func__);226	}227}228