162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci#include <linux/clk.h> 362306a36Sopenharmony_ci#include <linux/clocksource.h> 462306a36Sopenharmony_ci#include <linux/clockchips.h> 562306a36Sopenharmony_ci#include <linux/cpuhotplug.h> 662306a36Sopenharmony_ci#include <linux/interrupt.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/iopoll.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/of_address.h> 1262306a36Sopenharmony_ci#include <linux/of_irq.h> 1362306a36Sopenharmony_ci#include <linux/sched_clock.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/clk/clk-conf.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <clocksource/timer-ti-dm.h> 1862306a36Sopenharmony_ci#include <dt-bindings/bus/ti-sysc.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */ 2162306a36Sopenharmony_ci#define DMTIMER_TYPE1_ENABLE ((1 << 9) | (SYSC_IDLE_SMART << 3) | \ 2262306a36Sopenharmony_ci SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE) 2362306a36Sopenharmony_ci#define DMTIMER_TYPE1_DISABLE (SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE) 2462306a36Sopenharmony_ci#define DMTIMER_TYPE2_ENABLE (SYSC_IDLE_SMART_WKUP << 2) 2562306a36Sopenharmony_ci#define DMTIMER_RESET_WAIT 100000 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DMTIMER_INST_DONT_CARE ~0U 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int counter_32k; 3062306a36Sopenharmony_cistatic u32 clocksource; 3162306a36Sopenharmony_cistatic u32 clockevent; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * Subset of the timer registers we use. Note that the register offsets 3562306a36Sopenharmony_ci * depend on the timer revision detected. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistruct dmtimer_systimer { 3862306a36Sopenharmony_ci void __iomem *base; 3962306a36Sopenharmony_ci u8 sysc; 4062306a36Sopenharmony_ci u8 irq_stat; 4162306a36Sopenharmony_ci u8 irq_ena; 4262306a36Sopenharmony_ci u8 pend; 4362306a36Sopenharmony_ci u8 load; 4462306a36Sopenharmony_ci u8 counter; 4562306a36Sopenharmony_ci u8 ctrl; 4662306a36Sopenharmony_ci u8 wakeup; 4762306a36Sopenharmony_ci u8 ifctrl; 4862306a36Sopenharmony_ci struct clk *fck; 4962306a36Sopenharmony_ci struct clk *ick; 5062306a36Sopenharmony_ci unsigned long rate; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct dmtimer_clockevent { 5462306a36Sopenharmony_ci struct clock_event_device dev; 5562306a36Sopenharmony_ci struct dmtimer_systimer t; 5662306a36Sopenharmony_ci u32 period; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct dmtimer_clocksource { 6062306a36Sopenharmony_ci struct clocksource dev; 6162306a36Sopenharmony_ci struct dmtimer_systimer t; 6262306a36Sopenharmony_ci unsigned int loadval; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Assumes v1 ip if bits [31:16] are zero */ 6662306a36Sopenharmony_cistatic bool dmtimer_systimer_revision1(struct dmtimer_systimer *t) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci u32 tidr = readl_relaxed(t->base); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return !(tidr >> 16); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void dmtimer_systimer_enable(struct dmtimer_systimer *t) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci u32 val; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (dmtimer_systimer_revision1(t)) 7862306a36Sopenharmony_ci val = DMTIMER_TYPE1_ENABLE; 7962306a36Sopenharmony_ci else 8062306a36Sopenharmony_ci val = DMTIMER_TYPE2_ENABLE; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci writel_relaxed(val, t->base + t->sysc); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void dmtimer_systimer_disable(struct dmtimer_systimer *t) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (!dmtimer_systimer_revision1(t)) 8862306a36Sopenharmony_ci return; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int __init dmtimer_systimer_type1_reset(struct dmtimer_systimer *t) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci void __iomem *syss = t->base + OMAP_TIMER_V1_SYS_STAT_OFFSET; 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci u32 l; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci dmtimer_systimer_enable(t); 10062306a36Sopenharmony_ci writel_relaxed(BIT(1) | BIT(2), t->base + t->ifctrl); 10162306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(syss, l, l & BIT(0), 100, 10262306a36Sopenharmony_ci DMTIMER_RESET_WAIT); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return ret; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Note we must use io_base instead of func_base for type2 OCP regs */ 10862306a36Sopenharmony_cistatic int __init dmtimer_systimer_type2_reset(struct dmtimer_systimer *t) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci void __iomem *sysc = t->base + t->sysc; 11162306a36Sopenharmony_ci u32 l; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci dmtimer_systimer_enable(t); 11462306a36Sopenharmony_ci l = readl_relaxed(sysc); 11562306a36Sopenharmony_ci l |= BIT(0); 11662306a36Sopenharmony_ci writel_relaxed(l, sysc); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return readl_poll_timeout_atomic(sysc, l, !(l & BIT(0)), 100, 11962306a36Sopenharmony_ci DMTIMER_RESET_WAIT); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int __init dmtimer_systimer_reset(struct dmtimer_systimer *t) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int ret; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (dmtimer_systimer_revision1(t)) 12762306a36Sopenharmony_ci ret = dmtimer_systimer_type1_reset(t); 12862306a36Sopenharmony_ci else 12962306a36Sopenharmony_ci ret = dmtimer_systimer_type2_reset(t); 13062306a36Sopenharmony_ci if (ret < 0) { 13162306a36Sopenharmony_ci pr_err("%s failed with %i\n", __func__, ret); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return ret; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic const struct of_device_id counter_match_table[] = { 14062306a36Sopenharmony_ci { .compatible = "ti,omap-counter32k" }, 14162306a36Sopenharmony_ci { /* Sentinel */ }, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * Check if the SoC als has a usable working 32 KiHz counter. The 32 KiHz 14662306a36Sopenharmony_ci * counter is handled by timer-ti-32k, but we need to detect it as it 14762306a36Sopenharmony_ci * affects the preferred dmtimer system timer configuration. There is 14862306a36Sopenharmony_ci * typically no use for a dmtimer clocksource if the 32 KiHz counter is 14962306a36Sopenharmony_ci * present, except on am437x as described below. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic void __init dmtimer_systimer_check_counter32k(void) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct device_node *np; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (counter_32k) 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci np = of_find_matching_node(NULL, counter_match_table); 15962306a36Sopenharmony_ci if (!np) { 16062306a36Sopenharmony_ci counter_32k = -ENODEV; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (of_device_is_available(np)) 16662306a36Sopenharmony_ci counter_32k = 1; 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci counter_32k = -ENODEV; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci of_node_put(np); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const struct of_device_id dmtimer_match_table[] = { 17462306a36Sopenharmony_ci { .compatible = "ti,omap2420-timer", }, 17562306a36Sopenharmony_ci { .compatible = "ti,omap3430-timer", }, 17662306a36Sopenharmony_ci { .compatible = "ti,omap4430-timer", }, 17762306a36Sopenharmony_ci { .compatible = "ti,omap5430-timer", }, 17862306a36Sopenharmony_ci { .compatible = "ti,am335x-timer", }, 17962306a36Sopenharmony_ci { .compatible = "ti,am335x-timer-1ms", }, 18062306a36Sopenharmony_ci { .compatible = "ti,dm814-timer", }, 18162306a36Sopenharmony_ci { .compatible = "ti,dm816-timer", }, 18262306a36Sopenharmony_ci { /* Sentinel */ }, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* 18662306a36Sopenharmony_ci * Checks that system timers are configured to not reset and idle during 18762306a36Sopenharmony_ci * the generic timer-ti-dm device driver probe. And that the system timer 18862306a36Sopenharmony_ci * source clocks are properly configured. Also, let's not hog any DSP and 18962306a36Sopenharmony_ci * PWM capable timers unnecessarily as system timers. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic bool __init dmtimer_is_preferred(struct device_node *np) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (!of_device_is_available(np)) 19462306a36Sopenharmony_ci return false; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (!of_property_read_bool(np->parent, 19762306a36Sopenharmony_ci "ti,no-reset-on-init")) 19862306a36Sopenharmony_ci return false; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!of_property_read_bool(np->parent, "ti,no-idle")) 20162306a36Sopenharmony_ci return false; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Secure gptimer12 is always clocked with a fixed source */ 20462306a36Sopenharmony_ci if (!of_property_read_bool(np, "ti,timer-secure")) { 20562306a36Sopenharmony_ci if (!of_property_read_bool(np, "assigned-clocks")) 20662306a36Sopenharmony_ci return false; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (!of_property_read_bool(np, "assigned-clock-parents")) 20962306a36Sopenharmony_ci return false; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (of_property_read_bool(np, "ti,timer-dsp")) 21362306a36Sopenharmony_ci return false; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (of_property_read_bool(np, "ti,timer-pwm")) 21662306a36Sopenharmony_ci return false; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return true; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Finds the first available usable always-on timer, and assigns it to either 22362306a36Sopenharmony_ci * clockevent or clocksource depending if the counter_32k is available on the 22462306a36Sopenharmony_ci * SoC or not. 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Some omap3 boards with unreliable oscillator must not use the counter_32k 22762306a36Sopenharmony_ci * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable 22862306a36Sopenharmony_ci * oscillator should really set counter_32k as disabled, and delete dmtimer1 22962306a36Sopenharmony_ci * ti,always-on property, but let's not count on it. For these quirky cases, 23062306a36Sopenharmony_ci * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz 23162306a36Sopenharmony_ci * clock as the clocksource, and any available dmtimer as clockevent. 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * For am437x, we are using am335x style dmtimer clocksource. It is unclear 23462306a36Sopenharmony_ci * if this quirk handling is really needed, but let's change it separately 23562306a36Sopenharmony_ci * based on testing as it might cause side effects. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_cistatic void __init dmtimer_systimer_assign_alwon(void) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct device_node *np; 24062306a36Sopenharmony_ci u32 pa = 0; 24162306a36Sopenharmony_ci bool quirk_unreliable_oscillator = false; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Quirk unreliable 32 KiHz oscillator with incomplete dts */ 24462306a36Sopenharmony_ci if (of_machine_is_compatible("ti,omap3-beagle-ab4")) { 24562306a36Sopenharmony_ci quirk_unreliable_oscillator = true; 24662306a36Sopenharmony_ci counter_32k = -ENODEV; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Quirk am437x using am335x style dmtimer clocksource */ 25062306a36Sopenharmony_ci if (of_machine_is_compatible("ti,am43")) 25162306a36Sopenharmony_ci counter_32k = -ENODEV; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci for_each_matching_node(np, dmtimer_match_table) { 25462306a36Sopenharmony_ci struct resource res; 25562306a36Sopenharmony_ci if (!dmtimer_is_preferred(np)) 25662306a36Sopenharmony_ci continue; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!of_property_read_bool(np, "ti,timer-alwon")) 25962306a36Sopenharmony_ci continue; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) 26262306a36Sopenharmony_ci continue; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci pa = res.start; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Quirky omap3 boards must use dmtimer12 */ 26762306a36Sopenharmony_ci if (quirk_unreliable_oscillator && pa == 0x48318000) 26862306a36Sopenharmony_ci continue; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci of_node_put(np); 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Usually no need for dmtimer clocksource if we have counter32 */ 27562306a36Sopenharmony_ci if (counter_32k >= 0) { 27662306a36Sopenharmony_ci clockevent = pa; 27762306a36Sopenharmony_ci clocksource = 0; 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci clocksource = pa; 28062306a36Sopenharmony_ci clockevent = DMTIMER_INST_DONT_CARE; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* Finds the first usable dmtimer, used for the don't care case */ 28562306a36Sopenharmony_cistatic u32 __init dmtimer_systimer_find_first_available(void) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct device_node *np; 28862306a36Sopenharmony_ci u32 pa = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for_each_matching_node(np, dmtimer_match_table) { 29162306a36Sopenharmony_ci struct resource res; 29262306a36Sopenharmony_ci if (!dmtimer_is_preferred(np)) 29362306a36Sopenharmony_ci continue; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) 29662306a36Sopenharmony_ci continue; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (res.start == clocksource || res.start == clockevent) 29962306a36Sopenharmony_ci continue; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci pa = res.start; 30262306a36Sopenharmony_ci of_node_put(np); 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return pa; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* Selects the best clocksource and clockevent to use */ 31062306a36Sopenharmony_cistatic void __init dmtimer_systimer_select_best(void) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci dmtimer_systimer_check_counter32k(); 31362306a36Sopenharmony_ci dmtimer_systimer_assign_alwon(); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (clockevent == DMTIMER_INST_DONT_CARE) 31662306a36Sopenharmony_ci clockevent = dmtimer_systimer_find_first_available(); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci pr_debug("%s: counter_32k: %i clocksource: %08x clockevent: %08x\n", 31962306a36Sopenharmony_ci __func__, counter_32k, clocksource, clockevent); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* Interface clocks are only available on some SoCs variants */ 32362306a36Sopenharmony_cistatic int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t, 32462306a36Sopenharmony_ci struct device_node *np, 32562306a36Sopenharmony_ci const char *name, 32662306a36Sopenharmony_ci unsigned long *rate) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct clk *clock; 32962306a36Sopenharmony_ci unsigned long r; 33062306a36Sopenharmony_ci bool is_ick = false; 33162306a36Sopenharmony_ci int error; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci is_ick = !strncmp(name, "ick", 3); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci clock = of_clk_get_by_name(np, name); 33662306a36Sopenharmony_ci if ((PTR_ERR(clock) == -EINVAL) && is_ick) 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci else if (IS_ERR(clock)) 33962306a36Sopenharmony_ci return PTR_ERR(clock); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci error = clk_prepare_enable(clock); 34262306a36Sopenharmony_ci if (error) 34362306a36Sopenharmony_ci return error; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci r = clk_get_rate(clock); 34662306a36Sopenharmony_ci if (!r) { 34762306a36Sopenharmony_ci clk_disable_unprepare(clock); 34862306a36Sopenharmony_ci return -ENODEV; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (is_ick) 35262306a36Sopenharmony_ci t->ick = clock; 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci t->fck = clock; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci *rate = r; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int __init dmtimer_systimer_setup(struct device_node *np, 36262306a36Sopenharmony_ci struct dmtimer_systimer *t) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci unsigned long rate; 36562306a36Sopenharmony_ci u8 regbase; 36662306a36Sopenharmony_ci int error; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (!of_device_is_compatible(np->parent, "ti,sysc")) 36962306a36Sopenharmony_ci return -EINVAL; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci t->base = of_iomap(np, 0); 37262306a36Sopenharmony_ci if (!t->base) 37362306a36Sopenharmony_ci return -ENXIO; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Enable optional assigned-clock-parents configured at the timer 37762306a36Sopenharmony_ci * node level. For regular device drivers, this is done automatically 37862306a36Sopenharmony_ci * by bus related code such as platform_drv_probe(). 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci error = of_clk_set_defaults(np, false); 38162306a36Sopenharmony_ci if (error < 0) 38262306a36Sopenharmony_ci pr_err("%s: clock source init failed: %i\n", __func__, error); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* For ti-sysc, we have timer clocks at the parent module level */ 38562306a36Sopenharmony_ci error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate); 38662306a36Sopenharmony_ci if (error) 38762306a36Sopenharmony_ci goto err_unmap; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci t->rate = rate; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate); 39262306a36Sopenharmony_ci if (error) 39362306a36Sopenharmony_ci goto err_unmap; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (dmtimer_systimer_revision1(t)) { 39662306a36Sopenharmony_ci t->irq_stat = OMAP_TIMER_V1_STAT_OFFSET; 39762306a36Sopenharmony_ci t->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET; 39862306a36Sopenharmony_ci t->pend = _OMAP_TIMER_WRITE_PEND_OFFSET; 39962306a36Sopenharmony_ci regbase = 0; 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci t->irq_stat = OMAP_TIMER_V2_IRQSTATUS; 40262306a36Sopenharmony_ci t->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET; 40362306a36Sopenharmony_ci regbase = OMAP_TIMER_V2_FUNC_OFFSET; 40462306a36Sopenharmony_ci t->pend = regbase + _OMAP_TIMER_WRITE_PEND_OFFSET; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci t->sysc = OMAP_TIMER_OCP_CFG_OFFSET; 40862306a36Sopenharmony_ci t->load = regbase + _OMAP_TIMER_LOAD_OFFSET; 40962306a36Sopenharmony_ci t->counter = regbase + _OMAP_TIMER_COUNTER_OFFSET; 41062306a36Sopenharmony_ci t->ctrl = regbase + _OMAP_TIMER_CTRL_OFFSET; 41162306a36Sopenharmony_ci t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET; 41262306a36Sopenharmony_ci t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci dmtimer_systimer_reset(t); 41562306a36Sopenharmony_ci dmtimer_systimer_enable(t); 41662306a36Sopenharmony_ci pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base), 41762306a36Sopenharmony_ci readl_relaxed(t->base + t->sysc)); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cierr_unmap: 42262306a36Sopenharmony_ci iounmap(t->base); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return error; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/* Clockevent */ 42862306a36Sopenharmony_cistatic struct dmtimer_clockevent * 42962306a36Sopenharmony_cito_dmtimer_clockevent(struct clock_event_device *clockevent) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci return container_of(clockevent, struct dmtimer_clockevent, dev); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic irqreturn_t dmtimer_clockevent_interrupt(int irq, void *data) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = data; 43762306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 44062306a36Sopenharmony_ci clkevt->dev.event_handler(&clkevt->dev); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return IRQ_HANDLED; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int dmtimer_set_next_event(unsigned long cycles, 44662306a36Sopenharmony_ci struct clock_event_device *evt) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 44962306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 45062306a36Sopenharmony_ci void __iomem *pend = t->base + t->pend; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci while (readl_relaxed(pend) & WP_TCRR) 45362306a36Sopenharmony_ci cpu_relax(); 45462306a36Sopenharmony_ci writel_relaxed(0xffffffff - cycles, t->base + t->counter); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci while (readl_relaxed(pend) & WP_TCLR) 45762306a36Sopenharmony_ci cpu_relax(); 45862306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int dmtimer_clockevent_shutdown(struct clock_event_device *evt) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 46662306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 46762306a36Sopenharmony_ci void __iomem *ctrl = t->base + t->ctrl; 46862306a36Sopenharmony_ci u32 l; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci l = readl_relaxed(ctrl); 47162306a36Sopenharmony_ci if (l & OMAP_TIMER_CTRL_ST) { 47262306a36Sopenharmony_ci l &= ~BIT(0); 47362306a36Sopenharmony_ci writel_relaxed(l, ctrl); 47462306a36Sopenharmony_ci /* Flush posted write */ 47562306a36Sopenharmony_ci l = readl_relaxed(ctrl); 47662306a36Sopenharmony_ci /* Wait for functional clock period x 3.5 */ 47762306a36Sopenharmony_ci udelay(3500000 / t->rate + 1); 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int dmtimer_set_periodic(struct clock_event_device *evt) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 48762306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 48862306a36Sopenharmony_ci void __iomem *pend = t->base + t->pend; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci dmtimer_clockevent_shutdown(evt); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Looks like we need to first set the load value separately */ 49362306a36Sopenharmony_ci while (readl_relaxed(pend) & WP_TLDR) 49462306a36Sopenharmony_ci cpu_relax(); 49562306a36Sopenharmony_ci writel_relaxed(clkevt->period, t->base + t->load); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci while (readl_relaxed(pend) & WP_TCRR) 49862306a36Sopenharmony_ci cpu_relax(); 49962306a36Sopenharmony_ci writel_relaxed(clkevt->period, t->base + t->counter); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci while (readl_relaxed(pend) & WP_TCLR) 50262306a36Sopenharmony_ci cpu_relax(); 50362306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, 50462306a36Sopenharmony_ci t->base + t->ctrl); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void omap_clockevent_idle(struct clock_event_device *evt) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 51262306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dmtimer_systimer_disable(t); 51562306a36Sopenharmony_ci clk_disable(t->fck); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void omap_clockevent_unidle(struct clock_event_device *evt) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 52162306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 52262306a36Sopenharmony_ci int error; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci error = clk_enable(t->fck); 52562306a36Sopenharmony_ci if (error) 52662306a36Sopenharmony_ci pr_err("could not enable timer fck on resume: %i\n", error); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci dmtimer_systimer_enable(t); 52962306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 53062306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, 53462306a36Sopenharmony_ci struct device_node *np, 53562306a36Sopenharmony_ci unsigned int features, 53662306a36Sopenharmony_ci const struct cpumask *cpumask, 53762306a36Sopenharmony_ci const char *name, 53862306a36Sopenharmony_ci int rating) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct clock_event_device *dev; 54162306a36Sopenharmony_ci struct dmtimer_systimer *t; 54262306a36Sopenharmony_ci int error; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci t = &clkevt->t; 54562306a36Sopenharmony_ci dev = &clkevt->dev; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * We mostly use cpuidle_coupled with ARM local timers for runtime, 54962306a36Sopenharmony_ci * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci dev->features = features; 55262306a36Sopenharmony_ci dev->rating = rating; 55362306a36Sopenharmony_ci dev->set_next_event = dmtimer_set_next_event; 55462306a36Sopenharmony_ci dev->set_state_shutdown = dmtimer_clockevent_shutdown; 55562306a36Sopenharmony_ci dev->set_state_periodic = dmtimer_set_periodic; 55662306a36Sopenharmony_ci dev->set_state_oneshot = dmtimer_clockevent_shutdown; 55762306a36Sopenharmony_ci dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown; 55862306a36Sopenharmony_ci dev->tick_resume = dmtimer_clockevent_shutdown; 55962306a36Sopenharmony_ci dev->cpumask = cpumask; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci dev->irq = irq_of_parse_and_map(np, 0); 56262306a36Sopenharmony_ci if (!dev->irq) 56362306a36Sopenharmony_ci return -ENXIO; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci error = dmtimer_systimer_setup(np, &clkevt->t); 56662306a36Sopenharmony_ci if (error) 56762306a36Sopenharmony_ci return error; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * For clock-event timers we never read the timer counter and 57362306a36Sopenharmony_ci * so we are not impacted by errata i103 and i767. Therefore, 57462306a36Sopenharmony_ci * we can safely ignore this errata for clock-event timers. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci error = request_irq(dev->irq, dmtimer_clockevent_interrupt, 57962306a36Sopenharmony_ci IRQF_TIMER, name, clkevt); 58062306a36Sopenharmony_ci if (error) 58162306a36Sopenharmony_ci goto err_out_unmap; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 58462306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci pr_info("TI gptimer %s: %s%lu Hz at %pOF\n", 58762306a36Sopenharmony_ci name, of_property_read_bool(np, "ti,timer-alwon") ? 58862306a36Sopenharmony_ci "always-on " : "", t->rate, np->parent); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cierr_out_unmap: 59362306a36Sopenharmony_ci iounmap(t->base); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return error; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int __init dmtimer_clockevent_init(struct device_node *np) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt; 60162306a36Sopenharmony_ci int error; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); 60462306a36Sopenharmony_ci if (!clkevt) 60562306a36Sopenharmony_ci return -ENOMEM; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci error = dmtimer_clkevt_init_common(clkevt, np, 60862306a36Sopenharmony_ci CLOCK_EVT_FEAT_PERIODIC | 60962306a36Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT, 61062306a36Sopenharmony_ci cpu_possible_mask, "clockevent", 61162306a36Sopenharmony_ci 300); 61262306a36Sopenharmony_ci if (error) 61362306a36Sopenharmony_ci goto err_out_free; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci clockevents_config_and_register(&clkevt->dev, clkevt->t.rate, 61662306a36Sopenharmony_ci 3, /* Timer internal resync latency */ 61762306a36Sopenharmony_ci 0xffffffff); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (of_machine_is_compatible("ti,am33xx") || 62062306a36Sopenharmony_ci of_machine_is_compatible("ti,am43")) { 62162306a36Sopenharmony_ci clkevt->dev.suspend = omap_clockevent_idle; 62262306a36Sopenharmony_ci clkevt->dev.resume = omap_clockevent_unidle; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cierr_out_free: 62862306a36Sopenharmony_ci kfree(clkevt); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return error; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */ 63462306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt; 63962306a36Sopenharmony_ci int error; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (!cpu_possible(cpu)) 64262306a36Sopenharmony_ci return -EINVAL; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") || 64562306a36Sopenharmony_ci !of_property_read_bool(np->parent, "ti,no-idle")) 64662306a36Sopenharmony_ci pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT, 65162306a36Sopenharmony_ci cpumask_of(cpu), "percpu-dmtimer", 65262306a36Sopenharmony_ci 500); 65362306a36Sopenharmony_ci if (error) 65462306a36Sopenharmony_ci return error; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* See TRM for timer internal resynch latency */ 66062306a36Sopenharmony_cistatic int omap_dmtimer_starting_cpu(unsigned int cpu) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 66362306a36Sopenharmony_ci struct clock_event_device *dev = &clkevt->dev; 66462306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX); 66762306a36Sopenharmony_ci irq_force_affinity(dev->irq, cpumask_of(cpu)); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic int __init dmtimer_percpu_timer_startup(void) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0); 67562306a36Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (t->sysc) { 67862306a36Sopenharmony_ci cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING, 67962306a36Sopenharmony_ci "clockevents/omap/gptimer:starting", 68062306a36Sopenharmony_ci omap_dmtimer_starting_cpu, NULL); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_cisubsys_initcall(dmtimer_percpu_timer_startup); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct device_node *arm_timer; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); 69262306a36Sopenharmony_ci if (of_device_is_available(arm_timer)) { 69362306a36Sopenharmony_ci pr_warn_once("ARM architected timer wrap issue i940 detected\n"); 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (pa == 0x4882c000) /* dra7 dmtimer15 */ 69862306a36Sopenharmony_ci return dmtimer_percpu_timer_init(np, 0); 69962306a36Sopenharmony_ci else if (pa == 0x4882e000) /* dra7 dmtimer16 */ 70062306a36Sopenharmony_ci return dmtimer_percpu_timer_init(np, 1); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return 0; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* Clocksource */ 70662306a36Sopenharmony_cistatic struct dmtimer_clocksource * 70762306a36Sopenharmony_cito_dmtimer_clocksource(struct clocksource *cs) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci return container_of(cs, struct dmtimer_clocksource, dev); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic u64 dmtimer_clocksource_read_cycles(struct clocksource *cs) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 71562306a36Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return (u64)readl_relaxed(t->base + t->counter); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic void __iomem *dmtimer_sched_clock_counter; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic u64 notrace dmtimer_read_sched_clock(void) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci return readl_relaxed(dmtimer_sched_clock_counter); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic void dmtimer_clocksource_suspend(struct clocksource *cs) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 73062306a36Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci clksrc->loadval = readl_relaxed(t->base + t->counter); 73362306a36Sopenharmony_ci dmtimer_systimer_disable(t); 73462306a36Sopenharmony_ci clk_disable(t->fck); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic void dmtimer_clocksource_resume(struct clocksource *cs) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 74062306a36Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 74162306a36Sopenharmony_ci int error; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci error = clk_enable(t->fck); 74462306a36Sopenharmony_ci if (error) 74562306a36Sopenharmony_ci pr_err("could not enable timer fck on resume: %i\n", error); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci dmtimer_systimer_enable(t); 74862306a36Sopenharmony_ci writel_relaxed(clksrc->loadval, t->base + t->counter); 74962306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 75062306a36Sopenharmony_ci t->base + t->ctrl); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int __init dmtimer_clocksource_init(struct device_node *np) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct dmtimer_clocksource *clksrc; 75662306a36Sopenharmony_ci struct dmtimer_systimer *t; 75762306a36Sopenharmony_ci struct clocksource *dev; 75862306a36Sopenharmony_ci int error; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL); 76162306a36Sopenharmony_ci if (!clksrc) 76262306a36Sopenharmony_ci return -ENOMEM; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci dev = &clksrc->dev; 76562306a36Sopenharmony_ci t = &clksrc->t; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci error = dmtimer_systimer_setup(np, t); 76862306a36Sopenharmony_ci if (error) 76962306a36Sopenharmony_ci goto err_out_free; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci dev->name = "dmtimer"; 77262306a36Sopenharmony_ci dev->rating = 300; 77362306a36Sopenharmony_ci dev->read = dmtimer_clocksource_read_cycles; 77462306a36Sopenharmony_ci dev->mask = CLOCKSOURCE_MASK(32); 77562306a36Sopenharmony_ci dev->flags = CLOCK_SOURCE_IS_CONTINUOUS; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Unlike for clockevent, legacy code sets suspend only for am4 */ 77862306a36Sopenharmony_ci if (of_machine_is_compatible("ti,am43")) { 77962306a36Sopenharmony_ci dev->suspend = dmtimer_clocksource_suspend; 78062306a36Sopenharmony_ci dev->resume = dmtimer_clocksource_resume; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci writel_relaxed(0, t->base + t->counter); 78462306a36Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 78562306a36Sopenharmony_ci t->base + t->ctrl); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci pr_info("TI gptimer clocksource: %s%pOF\n", 78862306a36Sopenharmony_ci of_property_read_bool(np, "ti,timer-alwon") ? 78962306a36Sopenharmony_ci "always-on " : "", np->parent); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (!dmtimer_sched_clock_counter) { 79262306a36Sopenharmony_ci dmtimer_sched_clock_counter = t->base + t->counter; 79362306a36Sopenharmony_ci sched_clock_register(dmtimer_read_sched_clock, 32, t->rate); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (clocksource_register_hz(dev, t->rate)) 79762306a36Sopenharmony_ci pr_err("Could not register clocksource %pOF\n", np); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 0; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cierr_out_free: 80262306a36Sopenharmony_ci kfree(clksrc); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return -ENODEV; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/* 80862306a36Sopenharmony_ci * To detect between a clocksource and clockevent, we assume the device tree 80962306a36Sopenharmony_ci * has no interrupts configured for a clocksource timer. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_cistatic int __init dmtimer_systimer_init(struct device_node *np) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct resource res; 81462306a36Sopenharmony_ci u32 pa; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* One time init for the preferred timer configuration */ 81762306a36Sopenharmony_ci if (!clocksource && !clockevent) 81862306a36Sopenharmony_ci dmtimer_systimer_select_best(); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (!clocksource && !clockevent) { 82162306a36Sopenharmony_ci pr_err("%s: unable to detect system timers, update dtb?\n", 82262306a36Sopenharmony_ci __func__); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return -EINVAL; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci of_address_to_resource(np, 0, &res); 82962306a36Sopenharmony_ci pa = (u32)res.start; 83062306a36Sopenharmony_ci if (!pa) 83162306a36Sopenharmony_ci return -EINVAL; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (counter_32k <= 0 && clocksource == pa) 83462306a36Sopenharmony_ci return dmtimer_clocksource_init(np); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (clockevent == pa) 83762306a36Sopenharmony_ci return dmtimer_clockevent_init(np); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (of_machine_is_compatible("ti,dra7")) 84062306a36Sopenharmony_ci return dmtimer_percpu_quirk_init(np, pa); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return 0; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap2, "ti,omap2420-timer", dmtimer_systimer_init); 84662306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap3, "ti,omap3430-timer", dmtimer_systimer_init); 84762306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap4, "ti,omap4430-timer", dmtimer_systimer_init); 84862306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap5, "ti,omap5430-timer", dmtimer_systimer_init); 84962306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_am33x, "ti,am335x-timer", dmtimer_systimer_init); 85062306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_am3ms, "ti,am335x-timer-1ms", dmtimer_systimer_init); 85162306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm814, "ti,dm814-timer", dmtimer_systimer_init); 85262306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm816, "ti,dm816-timer", dmtimer_systimer_init); 853