brintos

brintos / linux-shallow public Read only

0
0
Text · 13.4 KiB · 2a90c92 Raw
512 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/init.h>3#include <linux/clocksource.h>4#include <linux/clockchips.h>5#include <linux/interrupt.h>6#include <linux/irq.h>7 8#include <linux/clk.h>9#include <linux/delay.h>10#include <linux/err.h>11#include <linux/ioport.h>12#include <linux/io.h>13#include <linux/of_address.h>14#include <linux/of_irq.h>15#include <linux/sched_clock.h>16#include <linux/syscore_ops.h>17#include <soc/at91/atmel_tcb.h>18 19 20/*21 * We're configured to use a specific TC block, one that's not hooked22 * up to external hardware, to provide a time solution:23 *24 *   - Two channels combine to create a free-running 32 bit counter25 *     with a base rate of 5+ MHz, packaged as a clocksource (with26 *     resolution better than 200 nsec).27 *   - Some chips support 32 bit counter. A single channel is used for28 *     this 32 bit free-running counter. the second channel is not used.29 *30 *   - The third channel may be used to provide a clockevent source, used in31 *   either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ,32 *   and can handle delays of up to two seconds. For 32-bit counters, it runs at33 *   the same rate as the clocksource34 *35 * REVISIT behavior during system suspend states... we should disable36 * all clocks and save the power.  Easily done for clockevent devices,37 * but clocksources won't necessarily get the needed notifications.38 * For deeper system sleep states, this will be mandatory...39 */40 41static void __iomem *tcaddr;42static struct43{44	u32 cmr;45	u32 imr;46	u32 rc;47	bool clken;48} tcb_cache[3];49static u32 bmr_cache;50 51static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 };52 53static u64 tc_get_cycles(struct clocksource *cs)54{55	unsigned long	flags;56	u32		lower, upper;57 58	raw_local_irq_save(flags);59	do {60		upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV));61		lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));62	} while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)));63 64	raw_local_irq_restore(flags);65	return (upper << 16) | lower;66}67 68static u64 tc_get_cycles32(struct clocksource *cs)69{70	return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));71}72 73static void tc_clksrc_suspend(struct clocksource *cs)74{75	int i;76 77	for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {78		tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR));79		tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR));80		tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC));81		tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) &82					ATMEL_TC_CLKSTA);83	}84 85	bmr_cache = readl(tcaddr + ATMEL_TC_BMR);86}87 88static void tc_clksrc_resume(struct clocksource *cs)89{90	int i;91 92	for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {93		/* Restore registers for the channel, RA and RB are not used  */94		writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR));95		writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC));96		writel(0, tcaddr + ATMEL_TC_REG(i, RA));97		writel(0, tcaddr + ATMEL_TC_REG(i, RB));98		/* Disable all the interrupts */99		writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR));100		/* Reenable interrupts that were enabled before suspending */101		writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER));102		/* Start the clock if it was used */103		if (tcb_cache[i].clken)104			writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(i, CCR));105	}106 107	/* Dual channel, chain channels */108	writel(bmr_cache, tcaddr + ATMEL_TC_BMR);109	/* Finally, trigger all the channels*/110	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);111}112 113static struct clocksource clksrc = {114	.rating         = 200,115	.read           = tc_get_cycles,116	.mask           = CLOCKSOURCE_MASK(32),117	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,118	.suspend	= tc_clksrc_suspend,119	.resume		= tc_clksrc_resume,120};121 122static u64 notrace tc_sched_clock_read(void)123{124	return tc_get_cycles(&clksrc);125}126 127static u64 notrace tc_sched_clock_read32(void)128{129	return tc_get_cycles32(&clksrc);130}131 132static struct delay_timer tc_delay_timer;133 134static unsigned long tc_delay_timer_read(void)135{136	return tc_get_cycles(&clksrc);137}138 139static unsigned long notrace tc_delay_timer_read32(void)140{141	return tc_get_cycles32(&clksrc);142}143 144#ifdef CONFIG_GENERIC_CLOCKEVENTS145 146struct tc_clkevt_device {147	struct clock_event_device	clkevt;148	struct clk			*clk;149	u32				rate;150	void __iomem			*regs;151};152 153static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)154{155	return container_of(clkevt, struct tc_clkevt_device, clkevt);156}157 158static u32 timer_clock;159 160static int tc_shutdown(struct clock_event_device *d)161{162	struct tc_clkevt_device *tcd = to_tc_clkevt(d);163	void __iomem		*regs = tcd->regs;164 165	writel(0xff, regs + ATMEL_TC_REG(2, IDR));166	writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));167	if (!clockevent_state_detached(d))168		clk_disable(tcd->clk);169 170	return 0;171}172 173static int tc_set_oneshot(struct clock_event_device *d)174{175	struct tc_clkevt_device *tcd = to_tc_clkevt(d);176	void __iomem		*regs = tcd->regs;177 178	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))179		tc_shutdown(d);180 181	clk_enable(tcd->clk);182 183	/* count up to RC, then irq and stop */184	writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |185		     ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));186	writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));187 188	/* set_next_event() configures and starts the timer */189	return 0;190}191 192static int tc_set_periodic(struct clock_event_device *d)193{194	struct tc_clkevt_device *tcd = to_tc_clkevt(d);195	void __iomem		*regs = tcd->regs;196 197	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))198		tc_shutdown(d);199 200	/* By not making the gentime core emulate periodic mode on top201	 * of oneshot, we get lower overhead and improved accuracy.202	 */203	clk_enable(tcd->clk);204 205	/* count up to RC, then irq and restart */206	writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,207		     regs + ATMEL_TC_REG(2, CMR));208	writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));209 210	/* Enable clock and interrupts on RC compare */211	writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));212 213	/* go go gadget! */214	writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs +215		     ATMEL_TC_REG(2, CCR));216	return 0;217}218 219static int tc_next_event(unsigned long delta, struct clock_event_device *d)220{221	writel_relaxed(delta, tcaddr + ATMEL_TC_REG(2, RC));222 223	/* go go gadget! */224	writel_relaxed(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,225			tcaddr + ATMEL_TC_REG(2, CCR));226	return 0;227}228 229static struct tc_clkevt_device clkevt = {230	.clkevt	= {231		.features		= CLOCK_EVT_FEAT_PERIODIC |232					  CLOCK_EVT_FEAT_ONESHOT,233		/* Should be lower than at91rm9200's system timer */234		.rating			= 125,235		.set_next_event		= tc_next_event,236		.set_state_shutdown	= tc_shutdown,237		.set_state_periodic	= tc_set_periodic,238		.set_state_oneshot	= tc_set_oneshot,239	},240};241 242static irqreturn_t ch2_irq(int irq, void *handle)243{244	struct tc_clkevt_device	*dev = handle;245	unsigned int		sr;246 247	sr = readl_relaxed(dev->regs + ATMEL_TC_REG(2, SR));248	if (sr & ATMEL_TC_CPCS) {249		dev->clkevt.event_handler(&dev->clkevt);250		return IRQ_HANDLED;251	}252 253	return IRQ_NONE;254}255 256static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)257{258	int ret;259	struct clk *t2_clk = tc->clk[2];260	int irq = tc->irq[2];261	int bits = tc->tcb_config->counter_width;262 263	/* try to enable t2 clk to avoid future errors in mode change */264	ret = clk_prepare_enable(t2_clk);265	if (ret)266		return ret;267 268	clkevt.regs = tc->regs;269	clkevt.clk = t2_clk;270 271	if (bits == 32) {272		timer_clock = divisor_idx;273		clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx];274	} else {275		ret = clk_prepare_enable(tc->slow_clk);276		if (ret) {277			clk_disable_unprepare(t2_clk);278			return ret;279		}280 281		clkevt.rate = clk_get_rate(tc->slow_clk);282		timer_clock = ATMEL_TC_TIMER_CLOCK5;283	}284 285	clk_disable(t2_clk);286 287	clkevt.clkevt.cpumask = cpumask_of(0);288 289	ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);290	if (ret) {291		clk_unprepare(t2_clk);292		if (bits != 32)293			clk_disable_unprepare(tc->slow_clk);294		return ret;295	}296 297	clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1);298 299	return ret;300}301 302#else /* !CONFIG_GENERIC_CLOCKEVENTS */303 304static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)305{306	/* NOTHING */307	return 0;308}309 310#endif311 312static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)313{314	/* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */315	writel(mck_divisor_idx			/* likely divide-by-8 */316			| ATMEL_TC_WAVE317			| ATMEL_TC_WAVESEL_UP		/* free-run */318			| ATMEL_TC_ASWTRG_SET		/* TIOA0 rises at software trigger */319			| ATMEL_TC_ACPA_SET		/* TIOA0 rises at 0 */320			| ATMEL_TC_ACPC_CLEAR,		/* (duty cycle 50%) */321			tcaddr + ATMEL_TC_REG(0, CMR));322	writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));323	writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));324	writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */325	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));326 327	/* channel 1:  waveform mode, input TIOA0 */328	writel(ATMEL_TC_XC1			/* input: TIOA0 */329			| ATMEL_TC_WAVE330			| ATMEL_TC_WAVESEL_UP,		/* free-run */331			tcaddr + ATMEL_TC_REG(1, CMR));332	writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));	/* no irqs */333	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));334 335	/* chain channel 0 to channel 1*/336	writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);337	/* then reset all the timers */338	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);339}340 341static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)342{343	/* channel 0:  waveform mode, input mclk/8 */344	writel(mck_divisor_idx			/* likely divide-by-8 */345			| ATMEL_TC_WAVE346			| ATMEL_TC_WAVESEL_UP,		/* free-run */347			tcaddr + ATMEL_TC_REG(0, CMR));348	writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));	/* no irqs */349	writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));350 351	/* then reset all the timers */352	writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);353}354 355static struct atmel_tcb_config tcb_rm9200_config = {356	.counter_width = 16,357};358 359static struct atmel_tcb_config tcb_sam9x5_config = {360	.counter_width = 32,361};362 363static struct atmel_tcb_config tcb_sama5d2_config = {364	.counter_width = 32,365	.has_gclk = 1,366};367 368static const struct of_device_id atmel_tcb_of_match[] = {369	{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },370	{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },371	{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },372	{ /* sentinel */ }373};374 375static int __init tcb_clksrc_init(struct device_node *node)376{377	struct atmel_tc tc;378	struct clk *t0_clk;379	const struct of_device_id *match;380	u64 (*tc_sched_clock)(void);381	u32 rate, divided_rate = 0;382	int best_divisor_idx = -1;383	int bits;384	int i;385	int ret;386 387	/* Protect against multiple calls */388	if (tcaddr)389		return 0;390 391	tc.regs = of_iomap(node->parent, 0);392	if (!tc.regs)393		return -ENXIO;394 395	t0_clk = of_clk_get_by_name(node->parent, "t0_clk");396	if (IS_ERR(t0_clk))397		return PTR_ERR(t0_clk);398 399	tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");400	if (IS_ERR(tc.slow_clk))401		return PTR_ERR(tc.slow_clk);402 403	tc.clk[0] = t0_clk;404	tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");405	if (IS_ERR(tc.clk[1]))406		tc.clk[1] = t0_clk;407	tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");408	if (IS_ERR(tc.clk[2]))409		tc.clk[2] = t0_clk;410 411	tc.irq[2] = of_irq_get(node->parent, 2);412	if (tc.irq[2] <= 0) {413		tc.irq[2] = of_irq_get(node->parent, 0);414		if (tc.irq[2] <= 0)415			return -EINVAL;416	}417 418	match = of_match_node(atmel_tcb_of_match, node->parent);419	if (!match)420		return -ENODEV;421 422	tc.tcb_config = match->data;423	bits = tc.tcb_config->counter_width;424 425	for (i = 0; i < ARRAY_SIZE(tc.irq); i++)426		writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));427 428	ret = clk_prepare_enable(t0_clk);429	if (ret) {430		pr_debug("can't enable T0 clk\n");431		return ret;432	}433 434	/* How fast will we be counting?  Pick something over 5 MHz.  */435	rate = (u32) clk_get_rate(t0_clk);436	i = 0;437	if (tc.tcb_config->has_gclk)438		i = 1;439	for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {440		unsigned divisor = atmel_tcb_divisors[i];441		unsigned tmp;442 443		tmp = rate / divisor;444		pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);445		if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000))446			break;447		divided_rate = tmp;448		best_divisor_idx = i;449	}450 451	clksrc.name = kbasename(node->parent->full_name);452	clkevt.clkevt.name = kbasename(node->parent->full_name);453	pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,454			((divided_rate % 1000000) + 500) / 1000);455 456	tcaddr = tc.regs;457 458	if (bits == 32) {459		/* use appropriate function to read 32 bit counter */460		clksrc.read = tc_get_cycles32;461		/* setup only channel 0 */462		tcb_setup_single_chan(&tc, best_divisor_idx);463		tc_sched_clock = tc_sched_clock_read32;464		tc_delay_timer.read_current_timer = tc_delay_timer_read32;465	} else {466		/* we have three clocks no matter what the467		 * underlying platform supports.468		 */469		ret = clk_prepare_enable(tc.clk[1]);470		if (ret) {471			pr_debug("can't enable T1 clk\n");472			goto err_disable_t0;473		}474		/* setup both channel 0 & 1 */475		tcb_setup_dual_chan(&tc, best_divisor_idx);476		tc_sched_clock = tc_sched_clock_read;477		tc_delay_timer.read_current_timer = tc_delay_timer_read;478	}479 480	/* and away we go! */481	ret = clocksource_register_hz(&clksrc, divided_rate);482	if (ret)483		goto err_disable_t1;484 485	/* channel 2:  periodic and oneshot timer support */486	ret = setup_clkevents(&tc, best_divisor_idx);487	if (ret)488		goto err_unregister_clksrc;489 490	sched_clock_register(tc_sched_clock, 32, divided_rate);491 492	tc_delay_timer.freq = divided_rate;493	register_current_timer_delay(&tc_delay_timer);494 495	return 0;496 497err_unregister_clksrc:498	clocksource_unregister(&clksrc);499 500err_disable_t1:501	if (bits != 32)502		clk_disable_unprepare(tc.clk[1]);503 504err_disable_t0:505	clk_disable_unprepare(t0_clk);506 507	tcaddr = NULL;508 509	return ret;510}511TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);512