162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file contains driver for the Cadence Triple Timer Counter Rev 06 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011-2013 Xilinx 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * based on arch/mips/kernel/time.c timer driver 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/clockchips.h> 1362306a36Sopenharmony_ci#include <linux/clocksource.h> 1462306a36Sopenharmony_ci#include <linux/of_address.h> 1562306a36Sopenharmony_ci#include <linux/of_irq.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/sched_clock.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/of_platform.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * This driver configures the 2 16/32-bit count-up timers as follows: 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * T1: Timer 1, clocksource for generic timekeeping 2662306a36Sopenharmony_ci * T2: Timer 2, clockevent source for hrtimers 2762306a36Sopenharmony_ci * T3: Timer 3, <unused> 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * The input frequency to the timer module for emulation is 2.5MHz which is 3062306a36Sopenharmony_ci * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32, 3162306a36Sopenharmony_ci * the timers are clocked at 78.125KHz (12.8 us resolution). 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci * The input frequency to the timer module in silicon is configurable and 3462306a36Sopenharmony_ci * obtained from device tree. The pre-scaler of 32 is used. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Timer Register Offset Definitions of Timer 1, Increment base address by 4 3962306a36Sopenharmony_ci * and use same offsets for Timer 2 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci#define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ 4262306a36Sopenharmony_ci#define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ 4362306a36Sopenharmony_ci#define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ 4462306a36Sopenharmony_ci#define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ 4562306a36Sopenharmony_ci#define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ 4662306a36Sopenharmony_ci#define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define TTC_CNT_CNTRL_DISABLE_MASK 0x1 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define TTC_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */ 5162306a36Sopenharmony_ci#define TTC_CLK_CNTRL_PSV_MASK 0x1e 5262306a36Sopenharmony_ci#define TTC_CLK_CNTRL_PSV_SHIFT 1 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Setup the timers to use pre-scaling, using a fixed value for now that will 5662306a36Sopenharmony_ci * work across most input frequency, but it may need to be more dynamic 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ 5962306a36Sopenharmony_ci#define PRESCALE 2048 /* The exponent must match this */ 6062306a36Sopenharmony_ci#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) 6162306a36Sopenharmony_ci#define CLK_CNTRL_PRESCALE_EN 1 6262306a36Sopenharmony_ci#define CNT_CNTRL_RESET (1 << 4) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define MAX_F_ERR 50 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * struct ttc_timer - This definition defines local timer structure 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * @base_addr: Base address of timer 7062306a36Sopenharmony_ci * @freq: Timer input clock frequency 7162306a36Sopenharmony_ci * @clk: Associated clock source 7262306a36Sopenharmony_ci * @clk_rate_change_nb Notifier block for clock rate changes 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistruct ttc_timer { 7562306a36Sopenharmony_ci void __iomem *base_addr; 7662306a36Sopenharmony_ci unsigned long freq; 7762306a36Sopenharmony_ci struct clk *clk; 7862306a36Sopenharmony_ci struct notifier_block clk_rate_change_nb; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define to_ttc_timer(x) \ 8262306a36Sopenharmony_ci container_of(x, struct ttc_timer, clk_rate_change_nb) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct ttc_timer_clocksource { 8562306a36Sopenharmony_ci u32 scale_clk_ctrl_reg_old; 8662306a36Sopenharmony_ci u32 scale_clk_ctrl_reg_new; 8762306a36Sopenharmony_ci struct ttc_timer ttc; 8862306a36Sopenharmony_ci struct clocksource cs; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define to_ttc_timer_clksrc(x) \ 9262306a36Sopenharmony_ci container_of(x, struct ttc_timer_clocksource, cs) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct ttc_timer_clockevent { 9562306a36Sopenharmony_ci struct ttc_timer ttc; 9662306a36Sopenharmony_ci struct clock_event_device ce; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define to_ttc_timer_clkevent(x) \ 10062306a36Sopenharmony_ci container_of(x, struct ttc_timer_clockevent, ce) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void __iomem *ttc_sched_clock_val_reg; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * ttc_set_interval - Set the timer interval value 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * @timer: Pointer to the timer instance 10862306a36Sopenharmony_ci * @cycles: Timer interval ticks 10962306a36Sopenharmony_ci **/ 11062306a36Sopenharmony_cistatic void ttc_set_interval(struct ttc_timer *timer, 11162306a36Sopenharmony_ci unsigned long cycles) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci u32 ctrl_reg; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* Disable the counter, set the counter value and re-enable counter */ 11662306a36Sopenharmony_ci ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); 11762306a36Sopenharmony_ci ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; 11862306a36Sopenharmony_ci writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci writel_relaxed(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Reset the counter (0x10) so that it starts from 0, one-shot 12462306a36Sopenharmony_ci * mode makes this needed for timing to be right. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci ctrl_reg |= CNT_CNTRL_RESET; 12762306a36Sopenharmony_ci ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; 12862306a36Sopenharmony_ci writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/** 13262306a36Sopenharmony_ci * ttc_clock_event_interrupt - Clock event timer interrupt handler 13362306a36Sopenharmony_ci * 13462306a36Sopenharmony_ci * @irq: IRQ number of the Timer 13562306a36Sopenharmony_ci * @dev_id: void pointer to the ttc_timer instance 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * returns: Always IRQ_HANDLED - success 13862306a36Sopenharmony_ci **/ 13962306a36Sopenharmony_cistatic irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct ttc_timer_clockevent *ttce = dev_id; 14262306a36Sopenharmony_ci struct ttc_timer *timer = &ttce->ttc; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Acknowledge the interrupt and call event handler */ 14562306a36Sopenharmony_ci readl_relaxed(timer->base_addr + TTC_ISR_OFFSET); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ttce->ce.event_handler(&ttce->ce); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return IRQ_HANDLED; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * __ttc_clocksource_read - Reads the timer counter register 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * returns: Current timer counter register value 15662306a36Sopenharmony_ci **/ 15762306a36Sopenharmony_cistatic u64 __ttc_clocksource_read(struct clocksource *cs) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return (u64)readl_relaxed(timer->base_addr + 16262306a36Sopenharmony_ci TTC_COUNT_VAL_OFFSET); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic u64 notrace ttc_sched_clock_read(void) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci return readl_relaxed(ttc_sched_clock_val_reg); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/** 17162306a36Sopenharmony_ci * ttc_set_next_event - Sets the time interval for next event 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * @cycles: Timer interval ticks 17462306a36Sopenharmony_ci * @evt: Address of clock event instance 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * returns: Always 0 - success 17762306a36Sopenharmony_ci **/ 17862306a36Sopenharmony_cistatic int ttc_set_next_event(unsigned long cycles, 17962306a36Sopenharmony_ci struct clock_event_device *evt) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); 18262306a36Sopenharmony_ci struct ttc_timer *timer = &ttce->ttc; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ttc_set_interval(timer, cycles); 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * @evt: Address of clock event instance 19262306a36Sopenharmony_ci **/ 19362306a36Sopenharmony_cistatic int ttc_shutdown(struct clock_event_device *evt) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); 19662306a36Sopenharmony_ci struct ttc_timer *timer = &ttce->ttc; 19762306a36Sopenharmony_ci u32 ctrl_reg; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); 20062306a36Sopenharmony_ci ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; 20162306a36Sopenharmony_ci writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int ttc_set_periodic(struct clock_event_device *evt) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); 20862306a36Sopenharmony_ci struct ttc_timer *timer = &ttce->ttc; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ttc_set_interval(timer, 21162306a36Sopenharmony_ci DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ)); 21262306a36Sopenharmony_ci return 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int ttc_resume(struct clock_event_device *evt) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); 21862306a36Sopenharmony_ci struct ttc_timer *timer = &ttce->ttc; 21962306a36Sopenharmony_ci u32 ctrl_reg; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); 22262306a36Sopenharmony_ci ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; 22362306a36Sopenharmony_ci writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int ttc_rate_change_clocksource_cb(struct notifier_block *nb, 22862306a36Sopenharmony_ci unsigned long event, void *data) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct clk_notifier_data *ndata = data; 23162306a36Sopenharmony_ci struct ttc_timer *ttc = to_ttc_timer(nb); 23262306a36Sopenharmony_ci struct ttc_timer_clocksource *ttccs = container_of(ttc, 23362306a36Sopenharmony_ci struct ttc_timer_clocksource, ttc); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci switch (event) { 23662306a36Sopenharmony_ci case PRE_RATE_CHANGE: 23762306a36Sopenharmony_ci { 23862306a36Sopenharmony_ci u32 psv; 23962306a36Sopenharmony_ci unsigned long factor, rate_low, rate_high; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) { 24262306a36Sopenharmony_ci factor = DIV_ROUND_CLOSEST(ndata->new_rate, 24362306a36Sopenharmony_ci ndata->old_rate); 24462306a36Sopenharmony_ci rate_low = ndata->old_rate; 24562306a36Sopenharmony_ci rate_high = ndata->new_rate; 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci factor = DIV_ROUND_CLOSEST(ndata->old_rate, 24862306a36Sopenharmony_ci ndata->new_rate); 24962306a36Sopenharmony_ci rate_low = ndata->new_rate; 25062306a36Sopenharmony_ci rate_high = ndata->old_rate; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!is_power_of_2(factor)) 25462306a36Sopenharmony_ci return NOTIFY_BAD; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (abs(rate_high - (factor * rate_low)) > MAX_F_ERR) 25762306a36Sopenharmony_ci return NOTIFY_BAD; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci factor = __ilog2_u32(factor); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * store timer clock ctrl register so we can restore it in case 26362306a36Sopenharmony_ci * of an abort. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci ttccs->scale_clk_ctrl_reg_old = 26662306a36Sopenharmony_ci readl_relaxed(ttccs->ttc.base_addr + 26762306a36Sopenharmony_ci TTC_CLK_CNTRL_OFFSET); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci psv = (ttccs->scale_clk_ctrl_reg_old & 27062306a36Sopenharmony_ci TTC_CLK_CNTRL_PSV_MASK) >> 27162306a36Sopenharmony_ci TTC_CLK_CNTRL_PSV_SHIFT; 27262306a36Sopenharmony_ci if (ndata->new_rate < ndata->old_rate) 27362306a36Sopenharmony_ci psv -= factor; 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci psv += factor; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* prescaler within legal range? */ 27862306a36Sopenharmony_ci if (psv & ~(TTC_CLK_CNTRL_PSV_MASK >> TTC_CLK_CNTRL_PSV_SHIFT)) 27962306a36Sopenharmony_ci return NOTIFY_BAD; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ttccs->scale_clk_ctrl_reg_new = ttccs->scale_clk_ctrl_reg_old & 28262306a36Sopenharmony_ci ~TTC_CLK_CNTRL_PSV_MASK; 28362306a36Sopenharmony_ci ttccs->scale_clk_ctrl_reg_new |= psv << TTC_CLK_CNTRL_PSV_SHIFT; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* scale down: adjust divider in post-change notification */ 28762306a36Sopenharmony_ci if (ndata->new_rate < ndata->old_rate) 28862306a36Sopenharmony_ci return NOTIFY_DONE; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* scale up: adjust divider now - before frequency change */ 29162306a36Sopenharmony_ci writel_relaxed(ttccs->scale_clk_ctrl_reg_new, 29262306a36Sopenharmony_ci ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci case POST_RATE_CHANGE: 29662306a36Sopenharmony_ci /* scale up: pre-change notification did the adjustment */ 29762306a36Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) 29862306a36Sopenharmony_ci return NOTIFY_OK; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* scale down: adjust divider now - after frequency change */ 30162306a36Sopenharmony_ci writel_relaxed(ttccs->scale_clk_ctrl_reg_new, 30262306a36Sopenharmony_ci ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci case ABORT_RATE_CHANGE: 30662306a36Sopenharmony_ci /* we have to undo the adjustment in case we scale up */ 30762306a36Sopenharmony_ci if (ndata->new_rate < ndata->old_rate) 30862306a36Sopenharmony_ci return NOTIFY_OK; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* restore original register value */ 31162306a36Sopenharmony_ci writel_relaxed(ttccs->scale_clk_ctrl_reg_old, 31262306a36Sopenharmony_ci ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); 31362306a36Sopenharmony_ci fallthrough; 31462306a36Sopenharmony_ci default: 31562306a36Sopenharmony_ci return NOTIFY_DONE; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return NOTIFY_DONE; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, 32262306a36Sopenharmony_ci u32 timer_width) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct ttc_timer_clocksource *ttccs; 32562306a36Sopenharmony_ci int err; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); 32862306a36Sopenharmony_ci if (!ttccs) 32962306a36Sopenharmony_ci return -ENOMEM; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ttccs->ttc.clk = clk; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci err = clk_prepare_enable(ttccs->ttc.clk); 33462306a36Sopenharmony_ci if (err) { 33562306a36Sopenharmony_ci kfree(ttccs); 33662306a36Sopenharmony_ci return err; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ttccs->ttc.freq = clk_get_rate(ttccs->ttc.clk); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ttccs->ttc.clk_rate_change_nb.notifier_call = 34262306a36Sopenharmony_ci ttc_rate_change_clocksource_cb; 34362306a36Sopenharmony_ci ttccs->ttc.clk_rate_change_nb.next = NULL; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci err = clk_notifier_register(ttccs->ttc.clk, 34662306a36Sopenharmony_ci &ttccs->ttc.clk_rate_change_nb); 34762306a36Sopenharmony_ci if (err) 34862306a36Sopenharmony_ci pr_warn("Unable to register clock notifier.\n"); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ttccs->ttc.base_addr = base; 35162306a36Sopenharmony_ci ttccs->cs.name = "ttc_clocksource"; 35262306a36Sopenharmony_ci ttccs->cs.rating = 200; 35362306a36Sopenharmony_ci ttccs->cs.read = __ttc_clocksource_read; 35462306a36Sopenharmony_ci ttccs->cs.mask = CLOCKSOURCE_MASK(timer_width); 35562306a36Sopenharmony_ci ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * Setup the clock source counter to be an incrementing counter 35962306a36Sopenharmony_ci * with no interrupt and it rolls over at 0xFFFF. Pre-scale 36062306a36Sopenharmony_ci * it by 32 also. Let it start running now. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_ci writel_relaxed(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET); 36362306a36Sopenharmony_ci writel_relaxed(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, 36462306a36Sopenharmony_ci ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); 36562306a36Sopenharmony_ci writel_relaxed(CNT_CNTRL_RESET, 36662306a36Sopenharmony_ci ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci err = clocksource_register_hz(&ttccs->cs, ttccs->ttc.freq / PRESCALE); 36962306a36Sopenharmony_ci if (err) { 37062306a36Sopenharmony_ci kfree(ttccs); 37162306a36Sopenharmony_ci return err; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; 37562306a36Sopenharmony_ci sched_clock_register(ttc_sched_clock_read, timer_width, 37662306a36Sopenharmony_ci ttccs->ttc.freq / PRESCALE); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int ttc_rate_change_clockevent_cb(struct notifier_block *nb, 38262306a36Sopenharmony_ci unsigned long event, void *data) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct clk_notifier_data *ndata = data; 38562306a36Sopenharmony_ci struct ttc_timer *ttc = to_ttc_timer(nb); 38662306a36Sopenharmony_ci struct ttc_timer_clockevent *ttcce = container_of(ttc, 38762306a36Sopenharmony_ci struct ttc_timer_clockevent, ttc); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci switch (event) { 39062306a36Sopenharmony_ci case POST_RATE_CHANGE: 39162306a36Sopenharmony_ci /* update cached frequency */ 39262306a36Sopenharmony_ci ttc->freq = ndata->new_rate; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci fallthrough; 39762306a36Sopenharmony_ci case PRE_RATE_CHANGE: 39862306a36Sopenharmony_ci case ABORT_RATE_CHANGE: 39962306a36Sopenharmony_ci default: 40062306a36Sopenharmony_ci return NOTIFY_DONE; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int __init ttc_setup_clockevent(struct clk *clk, 40562306a36Sopenharmony_ci void __iomem *base, u32 irq) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct ttc_timer_clockevent *ttcce; 40862306a36Sopenharmony_ci int err; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); 41162306a36Sopenharmony_ci if (!ttcce) 41262306a36Sopenharmony_ci return -ENOMEM; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ttcce->ttc.clk = clk; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci err = clk_prepare_enable(ttcce->ttc.clk); 41762306a36Sopenharmony_ci if (err) 41862306a36Sopenharmony_ci goto out_kfree; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci ttcce->ttc.clk_rate_change_nb.notifier_call = 42162306a36Sopenharmony_ci ttc_rate_change_clockevent_cb; 42262306a36Sopenharmony_ci ttcce->ttc.clk_rate_change_nb.next = NULL; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci err = clk_notifier_register(ttcce->ttc.clk, 42562306a36Sopenharmony_ci &ttcce->ttc.clk_rate_change_nb); 42662306a36Sopenharmony_ci if (err) { 42762306a36Sopenharmony_ci pr_warn("Unable to register clock notifier.\n"); 42862306a36Sopenharmony_ci goto out_kfree; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ttcce->ttc.base_addr = base; 43462306a36Sopenharmony_ci ttcce->ce.name = "ttc_clockevent"; 43562306a36Sopenharmony_ci ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; 43662306a36Sopenharmony_ci ttcce->ce.set_next_event = ttc_set_next_event; 43762306a36Sopenharmony_ci ttcce->ce.set_state_shutdown = ttc_shutdown; 43862306a36Sopenharmony_ci ttcce->ce.set_state_periodic = ttc_set_periodic; 43962306a36Sopenharmony_ci ttcce->ce.set_state_oneshot = ttc_shutdown; 44062306a36Sopenharmony_ci ttcce->ce.tick_resume = ttc_resume; 44162306a36Sopenharmony_ci ttcce->ce.rating = 200; 44262306a36Sopenharmony_ci ttcce->ce.irq = irq; 44362306a36Sopenharmony_ci ttcce->ce.cpumask = cpu_possible_mask; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * Setup the clock event timer to be an interval timer which 44762306a36Sopenharmony_ci * is prescaled by 32 using the interval interrupt. Leave it 44862306a36Sopenharmony_ci * disabled for now. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci writel_relaxed(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); 45162306a36Sopenharmony_ci writel_relaxed(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, 45262306a36Sopenharmony_ci ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); 45362306a36Sopenharmony_ci writel_relaxed(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci err = request_irq(irq, ttc_clock_event_interrupt, 45662306a36Sopenharmony_ci IRQF_TIMER, ttcce->ce.name, ttcce); 45762306a36Sopenharmony_ci if (err) 45862306a36Sopenharmony_ci goto out_kfree; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci clockevents_config_and_register(&ttcce->ce, 46162306a36Sopenharmony_ci ttcce->ttc.freq / PRESCALE, 1, 0xfffe); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ciout_kfree: 46662306a36Sopenharmony_ci kfree(ttcce); 46762306a36Sopenharmony_ci return err; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int __init ttc_timer_probe(struct platform_device *pdev) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci unsigned int irq; 47362306a36Sopenharmony_ci void __iomem *timer_baseaddr; 47462306a36Sopenharmony_ci struct clk *clk_cs, *clk_ce; 47562306a36Sopenharmony_ci static int initialized; 47662306a36Sopenharmony_ci int clksel, ret; 47762306a36Sopenharmony_ci u32 timer_width = 16; 47862306a36Sopenharmony_ci struct device_node *timer = pdev->dev.of_node; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (initialized) 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci initialized = 1; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* 48662306a36Sopenharmony_ci * Get the 1st Triple Timer Counter (TTC) block from the device tree 48762306a36Sopenharmony_ci * and use it. Note that the event timer uses the interrupt and it's the 48862306a36Sopenharmony_ci * 2nd TTC hence the irq_of_parse_and_map(,1) 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci timer_baseaddr = devm_of_iomap(&pdev->dev, timer, 0, NULL); 49162306a36Sopenharmony_ci if (IS_ERR(timer_baseaddr)) { 49262306a36Sopenharmony_ci pr_err("ERROR: invalid timer base address\n"); 49362306a36Sopenharmony_ci return PTR_ERR(timer_baseaddr); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci irq = irq_of_parse_and_map(timer, 1); 49762306a36Sopenharmony_ci if (irq <= 0) { 49862306a36Sopenharmony_ci pr_err("ERROR: invalid interrupt number\n"); 49962306a36Sopenharmony_ci return -EINVAL; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci of_property_read_u32(timer, "timer-width", &timer_width); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci clksel = readl_relaxed(timer_baseaddr + TTC_CLK_CNTRL_OFFSET); 50562306a36Sopenharmony_ci clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK); 50662306a36Sopenharmony_ci clk_cs = of_clk_get(timer, clksel); 50762306a36Sopenharmony_ci if (IS_ERR(clk_cs)) { 50862306a36Sopenharmony_ci pr_err("ERROR: timer input clock not found\n"); 50962306a36Sopenharmony_ci return PTR_ERR(clk_cs); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci clksel = readl_relaxed(timer_baseaddr + 4 + TTC_CLK_CNTRL_OFFSET); 51362306a36Sopenharmony_ci clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK); 51462306a36Sopenharmony_ci clk_ce = of_clk_get(timer, clksel); 51562306a36Sopenharmony_ci if (IS_ERR(clk_ce)) { 51662306a36Sopenharmony_ci pr_err("ERROR: timer input clock not found\n"); 51762306a36Sopenharmony_ci ret = PTR_ERR(clk_ce); 51862306a36Sopenharmony_ci goto put_clk_cs; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ret = ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci goto put_clk_ce; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ret = ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq); 52662306a36Sopenharmony_ci if (ret) 52762306a36Sopenharmony_ci goto put_clk_ce; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci pr_info("%pOFn #0 at %p, irq=%d\n", timer, timer_baseaddr, irq); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciput_clk_ce: 53462306a36Sopenharmony_ci clk_put(clk_ce); 53562306a36Sopenharmony_ciput_clk_cs: 53662306a36Sopenharmony_ci clk_put(clk_cs); 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic const struct of_device_id ttc_timer_of_match[] = { 54162306a36Sopenharmony_ci {.compatible = "cdns,ttc"}, 54262306a36Sopenharmony_ci {}, 54362306a36Sopenharmony_ci}; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ttc_timer_of_match); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic struct platform_driver ttc_timer_driver = { 54862306a36Sopenharmony_ci .driver = { 54962306a36Sopenharmony_ci .name = "cdns_ttc_timer", 55062306a36Sopenharmony_ci .of_match_table = ttc_timer_of_match, 55162306a36Sopenharmony_ci }, 55262306a36Sopenharmony_ci}; 55362306a36Sopenharmony_cibuiltin_platform_driver_probe(ttc_timer_driver, ttc_timer_probe); 554