Path: blob/master/drivers/clocksource/timer-atmel-tcb.c
26278 views
// SPDX-License-Identifier: GPL-2.01#include <linux/init.h>2#include <linux/clocksource.h>3#include <linux/clockchips.h>4#include <linux/interrupt.h>5#include <linux/irq.h>67#include <linux/clk.h>8#include <linux/delay.h>9#include <linux/err.h>10#include <linux/ioport.h>11#include <linux/io.h>12#include <linux/of_address.h>13#include <linux/of_irq.h>14#include <linux/sched_clock.h>15#include <linux/syscore_ops.h>16#include <soc/at91/atmel_tcb.h>171819/*20* We're configured to use a specific TC block, one that's not hooked21* up to external hardware, to provide a time solution:22*23* - Two channels combine to create a free-running 32 bit counter24* with a base rate of 5+ MHz, packaged as a clocksource (with25* resolution better than 200 nsec).26* - Some chips support 32 bit counter. A single channel is used for27* this 32 bit free-running counter. the second channel is not used.28*29* - The third channel may be used to provide a clockevent source, used in30* either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ,31* and can handle delays of up to two seconds. For 32-bit counters, it runs at32* the same rate as the clocksource33*34* REVISIT behavior during system suspend states... we should disable35* all clocks and save the power. Easily done for clockevent devices,36* but clocksources won't necessarily get the needed notifications.37* For deeper system sleep states, this will be mandatory...38*/3940static void __iomem *tcaddr;41static struct42{43u32 cmr;44u32 imr;45u32 rc;46bool clken;47} tcb_cache[3];48static u32 bmr_cache;4950static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 };5152static u64 tc_get_cycles(struct clocksource *cs)53{54unsigned long flags;55u32 lower, upper;5657raw_local_irq_save(flags);58do {59upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV));60lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));61} while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)));6263raw_local_irq_restore(flags);64return (upper << 16) | lower;65}6667static u64 tc_get_cycles32(struct clocksource *cs)68{69return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV));70}7172static void tc_clksrc_suspend(struct clocksource *cs)73{74int i;7576for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {77tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR));78tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR));79tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC));80tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) &81ATMEL_TC_CLKSTA);82}8384bmr_cache = readl(tcaddr + ATMEL_TC_BMR);85}8687static void tc_clksrc_resume(struct clocksource *cs)88{89int i;9091for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) {92/* Restore registers for the channel, RA and RB are not used */93writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR));94writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC));95writel(0, tcaddr + ATMEL_TC_REG(i, RA));96writel(0, tcaddr + ATMEL_TC_REG(i, RB));97/* Disable all the interrupts */98writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR));99/* Reenable interrupts that were enabled before suspending */100writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER));101/* Start the clock if it was used */102if (tcb_cache[i].clken)103writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(i, CCR));104}105106/* Dual channel, chain channels */107writel(bmr_cache, tcaddr + ATMEL_TC_BMR);108/* Finally, trigger all the channels*/109writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);110}111112static struct clocksource clksrc = {113.rating = 200,114.read = tc_get_cycles,115.mask = CLOCKSOURCE_MASK(32),116.flags = CLOCK_SOURCE_IS_CONTINUOUS,117.suspend = tc_clksrc_suspend,118.resume = tc_clksrc_resume,119};120121static u64 notrace tc_sched_clock_read(void)122{123return tc_get_cycles(&clksrc);124}125126static u64 notrace tc_sched_clock_read32(void)127{128return tc_get_cycles32(&clksrc);129}130131static struct delay_timer tc_delay_timer;132133static unsigned long tc_delay_timer_read(void)134{135return tc_get_cycles(&clksrc);136}137138static unsigned long notrace tc_delay_timer_read32(void)139{140return tc_get_cycles32(&clksrc);141}142143#ifdef CONFIG_GENERIC_CLOCKEVENTS144145struct tc_clkevt_device {146struct clock_event_device clkevt;147struct clk *clk;148u32 rate;149void __iomem *regs;150};151152static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)153{154return container_of(clkevt, struct tc_clkevt_device, clkevt);155}156157static u32 timer_clock;158159static int tc_shutdown(struct clock_event_device *d)160{161struct tc_clkevt_device *tcd = to_tc_clkevt(d);162void __iomem *regs = tcd->regs;163164writel(0xff, regs + ATMEL_TC_REG(2, IDR));165writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));166if (!clockevent_state_detached(d))167clk_disable(tcd->clk);168169return 0;170}171172static int tc_set_oneshot(struct clock_event_device *d)173{174struct tc_clkevt_device *tcd = to_tc_clkevt(d);175void __iomem *regs = tcd->regs;176177if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))178tc_shutdown(d);179180clk_enable(tcd->clk);181182/* count up to RC, then irq and stop */183writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |184ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));185writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));186187/* set_next_event() configures and starts the timer */188return 0;189}190191static int tc_set_periodic(struct clock_event_device *d)192{193struct tc_clkevt_device *tcd = to_tc_clkevt(d);194void __iomem *regs = tcd->regs;195196if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))197tc_shutdown(d);198199/* By not making the gentime core emulate periodic mode on top200* of oneshot, we get lower overhead and improved accuracy.201*/202clk_enable(tcd->clk);203204/* count up to RC, then irq and restart */205writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,206regs + ATMEL_TC_REG(2, CMR));207writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));208209/* Enable clock and interrupts on RC compare */210writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));211212/* go go gadget! */213writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs +214ATMEL_TC_REG(2, CCR));215return 0;216}217218static int tc_next_event(unsigned long delta, struct clock_event_device *d)219{220writel_relaxed(delta, tcaddr + ATMEL_TC_REG(2, RC));221222/* go go gadget! */223writel_relaxed(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,224tcaddr + ATMEL_TC_REG(2, CCR));225return 0;226}227228static struct tc_clkevt_device clkevt = {229.clkevt = {230.features = CLOCK_EVT_FEAT_PERIODIC |231CLOCK_EVT_FEAT_ONESHOT,232/* Should be lower than at91rm9200's system timer */233.rating = 125,234.set_next_event = tc_next_event,235.set_state_shutdown = tc_shutdown,236.set_state_periodic = tc_set_periodic,237.set_state_oneshot = tc_set_oneshot,238},239};240241static irqreturn_t ch2_irq(int irq, void *handle)242{243struct tc_clkevt_device *dev = handle;244unsigned int sr;245246sr = readl_relaxed(dev->regs + ATMEL_TC_REG(2, SR));247if (sr & ATMEL_TC_CPCS) {248dev->clkevt.event_handler(&dev->clkevt);249return IRQ_HANDLED;250}251252return IRQ_NONE;253}254255static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)256{257int ret;258struct clk *t2_clk = tc->clk[2];259int irq = tc->irq[2];260int bits = tc->tcb_config->counter_width;261262/* try to enable t2 clk to avoid future errors in mode change */263ret = clk_prepare_enable(t2_clk);264if (ret)265return ret;266267clkevt.regs = tc->regs;268clkevt.clk = t2_clk;269270if (bits == 32) {271timer_clock = divisor_idx;272clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx];273} else {274ret = clk_prepare_enable(tc->slow_clk);275if (ret) {276clk_disable_unprepare(t2_clk);277return ret;278}279280clkevt.rate = clk_get_rate(tc->slow_clk);281timer_clock = ATMEL_TC_TIMER_CLOCK5;282}283284clk_disable(t2_clk);285286clkevt.clkevt.cpumask = cpumask_of(0);287288ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);289if (ret) {290clk_unprepare(t2_clk);291if (bits != 32)292clk_disable_unprepare(tc->slow_clk);293return ret;294}295296clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1);297298return ret;299}300301#else /* !CONFIG_GENERIC_CLOCKEVENTS */302303static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx)304{305/* NOTHING */306return 0;307}308309#endif310311static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)312{313/* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */314writel(mck_divisor_idx /* likely divide-by-8 */315| ATMEL_TC_WAVE316| ATMEL_TC_WAVESEL_UP /* free-run */317| ATMEL_TC_ASWTRG_SET /* TIOA0 rises at software trigger */318| ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */319| ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */320tcaddr + ATMEL_TC_REG(0, CMR));321writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));322writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));323writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */324writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));325326/* channel 1: waveform mode, input TIOA0 */327writel(ATMEL_TC_XC1 /* input: TIOA0 */328| ATMEL_TC_WAVE329| ATMEL_TC_WAVESEL_UP, /* free-run */330tcaddr + ATMEL_TC_REG(1, CMR));331writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */332writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));333334/* chain channel 0 to channel 1*/335writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);336/* then reset all the timers */337writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);338}339340static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)341{342/* channel 0: waveform mode, input mclk/8 */343writel(mck_divisor_idx /* likely divide-by-8 */344| ATMEL_TC_WAVE345| ATMEL_TC_WAVESEL_UP, /* free-run */346tcaddr + ATMEL_TC_REG(0, CMR));347writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */348writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));349350/* then reset all the timers */351writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);352}353354static struct atmel_tcb_config tcb_rm9200_config = {355.counter_width = 16,356};357358static struct atmel_tcb_config tcb_sam9x5_config = {359.counter_width = 32,360};361362static struct atmel_tcb_config tcb_sama5d2_config = {363.counter_width = 32,364.has_gclk = 1,365};366367static const struct of_device_id atmel_tcb_of_match[] = {368{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },369{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },370{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },371{ /* sentinel */ }372};373374static int __init tcb_clksrc_init(struct device_node *node)375{376struct atmel_tc tc;377struct clk *t0_clk;378const struct of_device_id *match;379u64 (*tc_sched_clock)(void);380u32 rate, divided_rate = 0;381int best_divisor_idx = -1;382int bits;383int i;384int ret;385386/* Protect against multiple calls */387if (tcaddr)388return 0;389390tc.regs = of_iomap(node->parent, 0);391if (!tc.regs)392return -ENXIO;393394t0_clk = of_clk_get_by_name(node->parent, "t0_clk");395if (IS_ERR(t0_clk))396return PTR_ERR(t0_clk);397398tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk");399if (IS_ERR(tc.slow_clk))400return PTR_ERR(tc.slow_clk);401402tc.clk[0] = t0_clk;403tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk");404if (IS_ERR(tc.clk[1]))405tc.clk[1] = t0_clk;406tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk");407if (IS_ERR(tc.clk[2]))408tc.clk[2] = t0_clk;409410tc.irq[2] = of_irq_get(node->parent, 2);411if (tc.irq[2] <= 0) {412tc.irq[2] = of_irq_get(node->parent, 0);413if (tc.irq[2] <= 0)414return -EINVAL;415}416417match = of_match_node(atmel_tcb_of_match, node->parent);418if (!match)419return -ENODEV;420421tc.tcb_config = match->data;422bits = tc.tcb_config->counter_width;423424for (i = 0; i < ARRAY_SIZE(tc.irq); i++)425writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR));426427ret = clk_prepare_enable(t0_clk);428if (ret) {429pr_debug("can't enable T0 clk\n");430return ret;431}432433/* How fast will we be counting? Pick something over 5 MHz. */434rate = (u32) clk_get_rate(t0_clk);435i = 0;436if (tc.tcb_config->has_gclk)437i = 1;438for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) {439unsigned divisor = atmel_tcb_divisors[i];440unsigned tmp;441442tmp = rate / divisor;443pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);444if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000))445break;446divided_rate = tmp;447best_divisor_idx = i;448}449450clksrc.name = kbasename(node->parent->full_name);451clkevt.clkevt.name = kbasename(node->parent->full_name);452pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000,453((divided_rate % 1000000) + 500) / 1000);454455tcaddr = tc.regs;456457if (bits == 32) {458/* use appropriate function to read 32 bit counter */459clksrc.read = tc_get_cycles32;460/* setup only channel 0 */461tcb_setup_single_chan(&tc, best_divisor_idx);462tc_sched_clock = tc_sched_clock_read32;463tc_delay_timer.read_current_timer = tc_delay_timer_read32;464} else {465/* we have three clocks no matter what the466* underlying platform supports.467*/468ret = clk_prepare_enable(tc.clk[1]);469if (ret) {470pr_debug("can't enable T1 clk\n");471goto err_disable_t0;472}473/* setup both channel 0 & 1 */474tcb_setup_dual_chan(&tc, best_divisor_idx);475tc_sched_clock = tc_sched_clock_read;476tc_delay_timer.read_current_timer = tc_delay_timer_read;477}478479/* and away we go! */480ret = clocksource_register_hz(&clksrc, divided_rate);481if (ret)482goto err_disable_t1;483484/* channel 2: periodic and oneshot timer support */485ret = setup_clkevents(&tc, best_divisor_idx);486if (ret)487goto err_unregister_clksrc;488489sched_clock_register(tc_sched_clock, 32, divided_rate);490491tc_delay_timer.freq = divided_rate;492register_current_timer_delay(&tc_delay_timer);493494return 0;495496err_unregister_clksrc:497clocksource_unregister(&clksrc);498499err_disable_t1:500if (bits != 32)501clk_disable_unprepare(tc.clk[1]);502503err_disable_t0:504clk_disable_unprepare(t0_clk);505506tcaddr = NULL;507508return ret;509}510TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init);511512513