18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci#include <linux/clk.h> 38c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 48c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 58c2ecf20Sopenharmony_ci#include <linux/cpuhotplug.h> 68c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 78c2ecf20Sopenharmony_ci#include <linux/io.h> 88c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/of_address.h> 128c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 138c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/clk/clk-conf.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <clocksource/timer-ti-dm.h> 188c2ecf20Sopenharmony_ci#include <dt-bindings/bus/ti-sysc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */ 218c2ecf20Sopenharmony_ci#define DMTIMER_TYPE1_ENABLE ((1 << 9) | (SYSC_IDLE_SMART << 3) | \ 228c2ecf20Sopenharmony_ci SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE) 238c2ecf20Sopenharmony_ci#define DMTIMER_TYPE1_DISABLE (SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE) 248c2ecf20Sopenharmony_ci#define DMTIMER_TYPE2_ENABLE (SYSC_IDLE_SMART_WKUP << 2) 258c2ecf20Sopenharmony_ci#define DMTIMER_RESET_WAIT 100000 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define DMTIMER_INST_DONT_CARE ~0U 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int counter_32k; 308c2ecf20Sopenharmony_cistatic u32 clocksource; 318c2ecf20Sopenharmony_cistatic u32 clockevent; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Subset of the timer registers we use. Note that the register offsets 358c2ecf20Sopenharmony_ci * depend on the timer revision detected. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistruct dmtimer_systimer { 388c2ecf20Sopenharmony_ci void __iomem *base; 398c2ecf20Sopenharmony_ci u8 sysc; 408c2ecf20Sopenharmony_ci u8 irq_stat; 418c2ecf20Sopenharmony_ci u8 irq_ena; 428c2ecf20Sopenharmony_ci u8 pend; 438c2ecf20Sopenharmony_ci u8 load; 448c2ecf20Sopenharmony_ci u8 counter; 458c2ecf20Sopenharmony_ci u8 ctrl; 468c2ecf20Sopenharmony_ci u8 wakeup; 478c2ecf20Sopenharmony_ci u8 ifctrl; 488c2ecf20Sopenharmony_ci struct clk *fck; 498c2ecf20Sopenharmony_ci struct clk *ick; 508c2ecf20Sopenharmony_ci unsigned long rate; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct dmtimer_clockevent { 548c2ecf20Sopenharmony_ci struct clock_event_device dev; 558c2ecf20Sopenharmony_ci struct dmtimer_systimer t; 568c2ecf20Sopenharmony_ci u32 period; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct dmtimer_clocksource { 608c2ecf20Sopenharmony_ci struct clocksource dev; 618c2ecf20Sopenharmony_ci struct dmtimer_systimer t; 628c2ecf20Sopenharmony_ci unsigned int loadval; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Assumes v1 ip if bits [31:16] are zero */ 668c2ecf20Sopenharmony_cistatic bool dmtimer_systimer_revision1(struct dmtimer_systimer *t) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci u32 tidr = readl_relaxed(t->base); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return !(tidr >> 16); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void dmtimer_systimer_enable(struct dmtimer_systimer *t) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci u32 val; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (dmtimer_systimer_revision1(t)) 788c2ecf20Sopenharmony_ci val = DMTIMER_TYPE1_ENABLE; 798c2ecf20Sopenharmony_ci else 808c2ecf20Sopenharmony_ci val = DMTIMER_TYPE2_ENABLE; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci writel_relaxed(val, t->base + t->sysc); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void dmtimer_systimer_disable(struct dmtimer_systimer *t) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci if (!dmtimer_systimer_revision1(t)) 888c2ecf20Sopenharmony_ci return; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_type1_reset(struct dmtimer_systimer *t) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci void __iomem *syss = t->base + OMAP_TIMER_V1_SYS_STAT_OFFSET; 968c2ecf20Sopenharmony_ci int ret; 978c2ecf20Sopenharmony_ci u32 l; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dmtimer_systimer_enable(t); 1008c2ecf20Sopenharmony_ci writel_relaxed(BIT(1) | BIT(2), t->base + t->ifctrl); 1018c2ecf20Sopenharmony_ci ret = readl_poll_timeout_atomic(syss, l, l & BIT(0), 100, 1028c2ecf20Sopenharmony_ci DMTIMER_RESET_WAIT); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Note we must use io_base instead of func_base for type2 OCP regs */ 1088c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_type2_reset(struct dmtimer_systimer *t) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci void __iomem *sysc = t->base + t->sysc; 1118c2ecf20Sopenharmony_ci u32 l; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci dmtimer_systimer_enable(t); 1148c2ecf20Sopenharmony_ci l = readl_relaxed(sysc); 1158c2ecf20Sopenharmony_ci l |= BIT(0); 1168c2ecf20Sopenharmony_ci writel_relaxed(l, sysc); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return readl_poll_timeout_atomic(sysc, l, !(l & BIT(0)), 100, 1198c2ecf20Sopenharmony_ci DMTIMER_RESET_WAIT); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_reset(struct dmtimer_systimer *t) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int ret; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (dmtimer_systimer_revision1(t)) 1278c2ecf20Sopenharmony_ci ret = dmtimer_systimer_type1_reset(t); 1288c2ecf20Sopenharmony_ci else 1298c2ecf20Sopenharmony_ci ret = dmtimer_systimer_type2_reset(t); 1308c2ecf20Sopenharmony_ci if (ret < 0) { 1318c2ecf20Sopenharmony_ci pr_err("%s failed with %i\n", __func__, ret); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct of_device_id counter_match_table[] = { 1408c2ecf20Sopenharmony_ci { .compatible = "ti,omap-counter32k" }, 1418c2ecf20Sopenharmony_ci { /* Sentinel */ }, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 1458c2ecf20Sopenharmony_ci * Check if the SoC als has a usable working 32 KiHz counter. The 32 KiHz 1468c2ecf20Sopenharmony_ci * counter is handled by timer-ti-32k, but we need to detect it as it 1478c2ecf20Sopenharmony_ci * affects the preferred dmtimer system timer configuration. There is 1488c2ecf20Sopenharmony_ci * typically no use for a dmtimer clocksource if the 32 KiHz counter is 1498c2ecf20Sopenharmony_ci * present, except on am437x as described below. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic void __init dmtimer_systimer_check_counter32k(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct device_node *np; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (counter_32k) 1568c2ecf20Sopenharmony_ci return; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci np = of_find_matching_node(NULL, counter_match_table); 1598c2ecf20Sopenharmony_ci if (!np) { 1608c2ecf20Sopenharmony_ci counter_32k = -ENODEV; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (of_device_is_available(np)) 1668c2ecf20Sopenharmony_ci counter_32k = 1; 1678c2ecf20Sopenharmony_ci else 1688c2ecf20Sopenharmony_ci counter_32k = -ENODEV; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci of_node_put(np); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct of_device_id dmtimer_match_table[] = { 1748c2ecf20Sopenharmony_ci { .compatible = "ti,omap2420-timer", }, 1758c2ecf20Sopenharmony_ci { .compatible = "ti,omap3430-timer", }, 1768c2ecf20Sopenharmony_ci { .compatible = "ti,omap4430-timer", }, 1778c2ecf20Sopenharmony_ci { .compatible = "ti,omap5430-timer", }, 1788c2ecf20Sopenharmony_ci { .compatible = "ti,am335x-timer", }, 1798c2ecf20Sopenharmony_ci { .compatible = "ti,am335x-timer-1ms", }, 1808c2ecf20Sopenharmony_ci { .compatible = "ti,dm814-timer", }, 1818c2ecf20Sopenharmony_ci { .compatible = "ti,dm816-timer", }, 1828c2ecf20Sopenharmony_ci { /* Sentinel */ }, 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* 1868c2ecf20Sopenharmony_ci * Checks that system timers are configured to not reset and idle during 1878c2ecf20Sopenharmony_ci * the generic timer-ti-dm device driver probe. And that the system timer 1888c2ecf20Sopenharmony_ci * source clocks are properly configured. Also, let's not hog any DSP and 1898c2ecf20Sopenharmony_ci * PWM capable timers unnecessarily as system timers. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic bool __init dmtimer_is_preferred(struct device_node *np) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) 1948c2ecf20Sopenharmony_ci return false; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!of_property_read_bool(np->parent, 1978c2ecf20Sopenharmony_ci "ti,no-reset-on-init")) 1988c2ecf20Sopenharmony_ci return false; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!of_property_read_bool(np->parent, "ti,no-idle")) 2018c2ecf20Sopenharmony_ci return false; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Secure gptimer12 is always clocked with a fixed source */ 2048c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "ti,timer-secure")) { 2058c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "assigned-clocks")) 2068c2ecf20Sopenharmony_ci return false; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "assigned-clock-parents")) 2098c2ecf20Sopenharmony_ci return false; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "ti,timer-dsp")) 2138c2ecf20Sopenharmony_ci return false; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "ti,timer-pwm")) 2168c2ecf20Sopenharmony_ci return false; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return true; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* 2228c2ecf20Sopenharmony_ci * Finds the first available usable always-on timer, and assigns it to either 2238c2ecf20Sopenharmony_ci * clockevent or clocksource depending if the counter_32k is available on the 2248c2ecf20Sopenharmony_ci * SoC or not. 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Some omap3 boards with unreliable oscillator must not use the counter_32k 2278c2ecf20Sopenharmony_ci * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable 2288c2ecf20Sopenharmony_ci * oscillator should really set counter_32k as disabled, and delete dmtimer1 2298c2ecf20Sopenharmony_ci * ti,always-on property, but let's not count on it. For these quirky cases, 2308c2ecf20Sopenharmony_ci * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz 2318c2ecf20Sopenharmony_ci * clock as the clocksource, and any available dmtimer as clockevent. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * For am437x, we are using am335x style dmtimer clocksource. It is unclear 2348c2ecf20Sopenharmony_ci * if this quirk handling is really needed, but let's change it separately 2358c2ecf20Sopenharmony_ci * based on testing as it might cause side effects. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic void __init dmtimer_systimer_assign_alwon(void) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct device_node *np; 2408c2ecf20Sopenharmony_ci u32 pa = 0; 2418c2ecf20Sopenharmony_ci bool quirk_unreliable_oscillator = false; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Quirk unreliable 32 KiHz oscillator with incomplete dts */ 2448c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,omap3-beagle-ab4")) { 2458c2ecf20Sopenharmony_ci quirk_unreliable_oscillator = true; 2468c2ecf20Sopenharmony_ci counter_32k = -ENODEV; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Quirk am437x using am335x style dmtimer clocksource */ 2508c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,am43")) 2518c2ecf20Sopenharmony_ci counter_32k = -ENODEV; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for_each_matching_node(np, dmtimer_match_table) { 2548c2ecf20Sopenharmony_ci if (!dmtimer_is_preferred(np)) 2558c2ecf20Sopenharmony_ci continue; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "ti,timer-alwon")) { 2588c2ecf20Sopenharmony_ci const __be32 *addr; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci addr = of_get_address(np, 0, NULL, NULL); 2618c2ecf20Sopenharmony_ci pa = of_translate_address(np, addr); 2628c2ecf20Sopenharmony_ci if (pa) { 2638c2ecf20Sopenharmony_ci /* Quirky omap3 boards must use dmtimer12 */ 2648c2ecf20Sopenharmony_ci if (quirk_unreliable_oscillator && 2658c2ecf20Sopenharmony_ci pa == 0x48318000) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci of_node_put(np); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Usually no need for dmtimer clocksource if we have counter32 */ 2758c2ecf20Sopenharmony_ci if (counter_32k >= 0) { 2768c2ecf20Sopenharmony_ci clockevent = pa; 2778c2ecf20Sopenharmony_ci clocksource = 0; 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci clocksource = pa; 2808c2ecf20Sopenharmony_ci clockevent = DMTIMER_INST_DONT_CARE; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* Finds the first usable dmtimer, used for the don't care case */ 2858c2ecf20Sopenharmony_cistatic u32 __init dmtimer_systimer_find_first_available(void) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct device_node *np; 2888c2ecf20Sopenharmony_ci const __be32 *addr; 2898c2ecf20Sopenharmony_ci u32 pa = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for_each_matching_node(np, dmtimer_match_table) { 2928c2ecf20Sopenharmony_ci if (!dmtimer_is_preferred(np)) 2938c2ecf20Sopenharmony_ci continue; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci addr = of_get_address(np, 0, NULL, NULL); 2968c2ecf20Sopenharmony_ci pa = of_translate_address(np, addr); 2978c2ecf20Sopenharmony_ci if (pa) { 2988c2ecf20Sopenharmony_ci if (pa == clocksource || pa == clockevent) { 2998c2ecf20Sopenharmony_ci pa = 0; 3008c2ecf20Sopenharmony_ci continue; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci of_node_put(np); 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return pa; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* Selects the best clocksource and clockevent to use */ 3128c2ecf20Sopenharmony_cistatic void __init dmtimer_systimer_select_best(void) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci dmtimer_systimer_check_counter32k(); 3158c2ecf20Sopenharmony_ci dmtimer_systimer_assign_alwon(); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (clockevent == DMTIMER_INST_DONT_CARE) 3188c2ecf20Sopenharmony_ci clockevent = dmtimer_systimer_find_first_available(); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci pr_debug("%s: counter_32k: %i clocksource: %08x clockevent: %08x\n", 3218c2ecf20Sopenharmony_ci __func__, counter_32k, clocksource, clockevent); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* Interface clocks are only available on some SoCs variants */ 3258c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t, 3268c2ecf20Sopenharmony_ci struct device_node *np, 3278c2ecf20Sopenharmony_ci const char *name, 3288c2ecf20Sopenharmony_ci unsigned long *rate) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct clk *clock; 3318c2ecf20Sopenharmony_ci unsigned long r; 3328c2ecf20Sopenharmony_ci bool is_ick = false; 3338c2ecf20Sopenharmony_ci int error; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci is_ick = !strncmp(name, "ick", 3); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci clock = of_clk_get_by_name(np, name); 3388c2ecf20Sopenharmony_ci if ((PTR_ERR(clock) == -EINVAL) && is_ick) 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci else if (IS_ERR(clock)) 3418c2ecf20Sopenharmony_ci return PTR_ERR(clock); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci error = clk_prepare_enable(clock); 3448c2ecf20Sopenharmony_ci if (error) 3458c2ecf20Sopenharmony_ci return error; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci r = clk_get_rate(clock); 3488c2ecf20Sopenharmony_ci if (!r) { 3498c2ecf20Sopenharmony_ci clk_disable_unprepare(clock); 3508c2ecf20Sopenharmony_ci return -ENODEV; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (is_ick) 3548c2ecf20Sopenharmony_ci t->ick = clock; 3558c2ecf20Sopenharmony_ci else 3568c2ecf20Sopenharmony_ci t->fck = clock; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci *rate = r; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_setup(struct device_node *np, 3648c2ecf20Sopenharmony_ci struct dmtimer_systimer *t) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci unsigned long rate; 3678c2ecf20Sopenharmony_ci u8 regbase; 3688c2ecf20Sopenharmony_ci int error; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!of_device_is_compatible(np->parent, "ti,sysc")) 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci t->base = of_iomap(np, 0); 3748c2ecf20Sopenharmony_ci if (!t->base) 3758c2ecf20Sopenharmony_ci return -ENXIO; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Enable optional assigned-clock-parents configured at the timer 3798c2ecf20Sopenharmony_ci * node level. For regular device drivers, this is done automatically 3808c2ecf20Sopenharmony_ci * by bus related code such as platform_drv_probe(). 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci error = of_clk_set_defaults(np, false); 3838c2ecf20Sopenharmony_ci if (error < 0) 3848c2ecf20Sopenharmony_ci pr_err("%s: clock source init failed: %i\n", __func__, error); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* For ti-sysc, we have timer clocks at the parent module level */ 3878c2ecf20Sopenharmony_ci error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate); 3888c2ecf20Sopenharmony_ci if (error) 3898c2ecf20Sopenharmony_ci goto err_unmap; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci t->rate = rate; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate); 3948c2ecf20Sopenharmony_ci if (error) 3958c2ecf20Sopenharmony_ci goto err_unmap; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (dmtimer_systimer_revision1(t)) { 3988c2ecf20Sopenharmony_ci t->irq_stat = OMAP_TIMER_V1_STAT_OFFSET; 3998c2ecf20Sopenharmony_ci t->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET; 4008c2ecf20Sopenharmony_ci t->pend = _OMAP_TIMER_WRITE_PEND_OFFSET; 4018c2ecf20Sopenharmony_ci regbase = 0; 4028c2ecf20Sopenharmony_ci } else { 4038c2ecf20Sopenharmony_ci t->irq_stat = OMAP_TIMER_V2_IRQSTATUS; 4048c2ecf20Sopenharmony_ci t->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET; 4058c2ecf20Sopenharmony_ci regbase = OMAP_TIMER_V2_FUNC_OFFSET; 4068c2ecf20Sopenharmony_ci t->pend = regbase + _OMAP_TIMER_WRITE_PEND_OFFSET; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci t->sysc = OMAP_TIMER_OCP_CFG_OFFSET; 4108c2ecf20Sopenharmony_ci t->load = regbase + _OMAP_TIMER_LOAD_OFFSET; 4118c2ecf20Sopenharmony_ci t->counter = regbase + _OMAP_TIMER_COUNTER_OFFSET; 4128c2ecf20Sopenharmony_ci t->ctrl = regbase + _OMAP_TIMER_CTRL_OFFSET; 4138c2ecf20Sopenharmony_ci t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET; 4148c2ecf20Sopenharmony_ci t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci dmtimer_systimer_reset(t); 4178c2ecf20Sopenharmony_ci dmtimer_systimer_enable(t); 4188c2ecf20Sopenharmony_ci pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base), 4198c2ecf20Sopenharmony_ci readl_relaxed(t->base + t->sysc)); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cierr_unmap: 4248c2ecf20Sopenharmony_ci iounmap(t->base); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return error; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* Clockevent */ 4308c2ecf20Sopenharmony_cistatic struct dmtimer_clockevent * 4318c2ecf20Sopenharmony_cito_dmtimer_clockevent(struct clock_event_device *clockevent) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci return container_of(clockevent, struct dmtimer_clockevent, dev); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic irqreturn_t dmtimer_clockevent_interrupt(int irq, void *data) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = data; 4398c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 4428c2ecf20Sopenharmony_ci clkevt->dev.event_handler(&clkevt->dev); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int dmtimer_set_next_event(unsigned long cycles, 4488c2ecf20Sopenharmony_ci struct clock_event_device *evt) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 4518c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 4528c2ecf20Sopenharmony_ci void __iomem *pend = t->base + t->pend; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci while (readl_relaxed(pend) & WP_TCRR) 4558c2ecf20Sopenharmony_ci cpu_relax(); 4568c2ecf20Sopenharmony_ci writel_relaxed(0xffffffff - cycles, t->base + t->counter); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci while (readl_relaxed(pend) & WP_TCLR) 4598c2ecf20Sopenharmony_ci cpu_relax(); 4608c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int dmtimer_clockevent_shutdown(struct clock_event_device *evt) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 4688c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 4698c2ecf20Sopenharmony_ci void __iomem *ctrl = t->base + t->ctrl; 4708c2ecf20Sopenharmony_ci u32 l; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci l = readl_relaxed(ctrl); 4738c2ecf20Sopenharmony_ci if (l & OMAP_TIMER_CTRL_ST) { 4748c2ecf20Sopenharmony_ci l &= ~BIT(0); 4758c2ecf20Sopenharmony_ci writel_relaxed(l, ctrl); 4768c2ecf20Sopenharmony_ci /* Flush posted write */ 4778c2ecf20Sopenharmony_ci l = readl_relaxed(ctrl); 4788c2ecf20Sopenharmony_ci /* Wait for functional clock period x 3.5 */ 4798c2ecf20Sopenharmony_ci udelay(3500000 / t->rate + 1); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int dmtimer_set_periodic(struct clock_event_device *evt) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 4898c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 4908c2ecf20Sopenharmony_ci void __iomem *pend = t->base + t->pend; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dmtimer_clockevent_shutdown(evt); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* Looks like we need to first set the load value separately */ 4958c2ecf20Sopenharmony_ci while (readl_relaxed(pend) & WP_TLDR) 4968c2ecf20Sopenharmony_ci cpu_relax(); 4978c2ecf20Sopenharmony_ci writel_relaxed(clkevt->period, t->base + t->load); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci while (readl_relaxed(pend) & WP_TCRR) 5008c2ecf20Sopenharmony_ci cpu_relax(); 5018c2ecf20Sopenharmony_ci writel_relaxed(clkevt->period, t->base + t->counter); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci while (readl_relaxed(pend) & WP_TCLR) 5048c2ecf20Sopenharmony_ci cpu_relax(); 5058c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, 5068c2ecf20Sopenharmony_ci t->base + t->ctrl); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void omap_clockevent_idle(struct clock_event_device *evt) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 5148c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci dmtimer_systimer_disable(t); 5178c2ecf20Sopenharmony_ci clk_disable(t->fck); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void omap_clockevent_unidle(struct clock_event_device *evt) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 5238c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 5248c2ecf20Sopenharmony_ci int error; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci error = clk_enable(t->fck); 5278c2ecf20Sopenharmony_ci if (error) 5288c2ecf20Sopenharmony_ci pr_err("could not enable timer fck on resume: %i\n", error); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci dmtimer_systimer_enable(t); 5318c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 5328c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, 5368c2ecf20Sopenharmony_ci struct device_node *np, 5378c2ecf20Sopenharmony_ci unsigned int features, 5388c2ecf20Sopenharmony_ci const struct cpumask *cpumask, 5398c2ecf20Sopenharmony_ci const char *name, 5408c2ecf20Sopenharmony_ci int rating) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct clock_event_device *dev; 5438c2ecf20Sopenharmony_ci struct dmtimer_systimer *t; 5448c2ecf20Sopenharmony_ci int error; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci t = &clkevt->t; 5478c2ecf20Sopenharmony_ci dev = &clkevt->dev; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * We mostly use cpuidle_coupled with ARM local timers for runtime, 5518c2ecf20Sopenharmony_ci * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci dev->features = features; 5548c2ecf20Sopenharmony_ci dev->rating = rating; 5558c2ecf20Sopenharmony_ci dev->set_next_event = dmtimer_set_next_event; 5568c2ecf20Sopenharmony_ci dev->set_state_shutdown = dmtimer_clockevent_shutdown; 5578c2ecf20Sopenharmony_ci dev->set_state_periodic = dmtimer_set_periodic; 5588c2ecf20Sopenharmony_ci dev->set_state_oneshot = dmtimer_clockevent_shutdown; 5598c2ecf20Sopenharmony_ci dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown; 5608c2ecf20Sopenharmony_ci dev->tick_resume = dmtimer_clockevent_shutdown; 5618c2ecf20Sopenharmony_ci dev->cpumask = cpumask; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci dev->irq = irq_of_parse_and_map(np, 0); 5648c2ecf20Sopenharmony_ci if (!dev->irq) 5658c2ecf20Sopenharmony_ci return -ENXIO; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci error = dmtimer_systimer_setup(np, &clkevt->t); 5688c2ecf20Sopenharmony_ci if (error) 5698c2ecf20Sopenharmony_ci return error; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * For clock-event timers we never read the timer counter and 5758c2ecf20Sopenharmony_ci * so we are not impacted by errata i103 and i767. Therefore, 5768c2ecf20Sopenharmony_ci * we can safely ignore this errata for clock-event timers. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci error = request_irq(dev->irq, dmtimer_clockevent_interrupt, 5818c2ecf20Sopenharmony_ci IRQF_TIMER, name, clkevt); 5828c2ecf20Sopenharmony_ci if (error) 5838c2ecf20Sopenharmony_ci goto err_out_unmap; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 5868c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci pr_info("TI gptimer %s: %s%lu Hz at %pOF\n", 5898c2ecf20Sopenharmony_ci name, of_find_property(np, "ti,timer-alwon", NULL) ? 5908c2ecf20Sopenharmony_ci "always-on " : "", t->rate, np->parent); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cierr_out_unmap: 5958c2ecf20Sopenharmony_ci iounmap(t->base); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return error; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int __init dmtimer_clockevent_init(struct device_node *np) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt; 6038c2ecf20Sopenharmony_ci int error; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); 6068c2ecf20Sopenharmony_ci if (!clkevt) 6078c2ecf20Sopenharmony_ci return -ENOMEM; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci error = dmtimer_clkevt_init_common(clkevt, np, 6108c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_PERIODIC | 6118c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT, 6128c2ecf20Sopenharmony_ci cpu_possible_mask, "clockevent", 6138c2ecf20Sopenharmony_ci 300); 6148c2ecf20Sopenharmony_ci if (error) 6158c2ecf20Sopenharmony_ci goto err_out_free; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci clockevents_config_and_register(&clkevt->dev, clkevt->t.rate, 6188c2ecf20Sopenharmony_ci 3, /* Timer internal resync latency */ 6198c2ecf20Sopenharmony_ci 0xffffffff); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,am33xx") || 6228c2ecf20Sopenharmony_ci of_machine_is_compatible("ti,am43")) { 6238c2ecf20Sopenharmony_ci clkevt->dev.suspend = omap_clockevent_idle; 6248c2ecf20Sopenharmony_ci clkevt->dev.resume = omap_clockevent_unidle; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cierr_out_free: 6308c2ecf20Sopenharmony_ci kfree(clkevt); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return error; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */ 6368c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt; 6418c2ecf20Sopenharmony_ci int error; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!cpu_possible(cpu)) 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") || 6478c2ecf20Sopenharmony_ci !of_property_read_bool(np->parent, "ti,no-idle")) 6488c2ecf20Sopenharmony_ci pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT, 6538c2ecf20Sopenharmony_ci cpumask_of(cpu), "percpu-dmtimer", 6548c2ecf20Sopenharmony_ci 500); 6558c2ecf20Sopenharmony_ci if (error) 6568c2ecf20Sopenharmony_ci return error; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci/* See TRM for timer internal resynch latency */ 6628c2ecf20Sopenharmony_cistatic int omap_dmtimer_starting_cpu(unsigned int cpu) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 6658c2ecf20Sopenharmony_ci struct clock_event_device *dev = &clkevt->dev; 6668c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX); 6698c2ecf20Sopenharmony_ci irq_force_affinity(dev->irq, cpumask_of(cpu)); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic int __init dmtimer_percpu_timer_startup(void) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0); 6778c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clkevt->t; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (t->sysc) { 6808c2ecf20Sopenharmony_ci cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING, 6818c2ecf20Sopenharmony_ci "clockevents/omap/gptimer:starting", 6828c2ecf20Sopenharmony_ci omap_dmtimer_starting_cpu, NULL); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_cisubsys_initcall(dmtimer_percpu_timer_startup); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct device_node *arm_timer; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); 6948c2ecf20Sopenharmony_ci if (of_device_is_available(arm_timer)) { 6958c2ecf20Sopenharmony_ci pr_warn_once("ARM architected timer wrap issue i940 detected\n"); 6968c2ecf20Sopenharmony_ci return 0; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (pa == 0x4882c000) /* dra7 dmtimer15 */ 7008c2ecf20Sopenharmony_ci return dmtimer_percpu_timer_init(np, 0); 7018c2ecf20Sopenharmony_ci else if (pa == 0x4882e000) /* dra7 dmtimer16 */ 7028c2ecf20Sopenharmony_ci return dmtimer_percpu_timer_init(np, 1); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/* Clocksource */ 7088c2ecf20Sopenharmony_cistatic struct dmtimer_clocksource * 7098c2ecf20Sopenharmony_cito_dmtimer_clocksource(struct clocksource *cs) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci return container_of(cs, struct dmtimer_clocksource, dev); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic u64 dmtimer_clocksource_read_cycles(struct clocksource *cs) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 7178c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return (u64)readl_relaxed(t->base + t->counter); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void __iomem *dmtimer_sched_clock_counter; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic u64 notrace dmtimer_read_sched_clock(void) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci return readl_relaxed(dmtimer_sched_clock_counter); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void dmtimer_clocksource_suspend(struct clocksource *cs) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 7328c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci clksrc->loadval = readl_relaxed(t->base + t->counter); 7358c2ecf20Sopenharmony_ci dmtimer_systimer_disable(t); 7368c2ecf20Sopenharmony_ci clk_disable(t->fck); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void dmtimer_clocksource_resume(struct clocksource *cs) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 7428c2ecf20Sopenharmony_ci struct dmtimer_systimer *t = &clksrc->t; 7438c2ecf20Sopenharmony_ci int error; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci error = clk_enable(t->fck); 7468c2ecf20Sopenharmony_ci if (error) 7478c2ecf20Sopenharmony_ci pr_err("could not enable timer fck on resume: %i\n", error); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci dmtimer_systimer_enable(t); 7508c2ecf20Sopenharmony_ci writel_relaxed(clksrc->loadval, t->base + t->counter); 7518c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 7528c2ecf20Sopenharmony_ci t->base + t->ctrl); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int __init dmtimer_clocksource_init(struct device_node *np) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct dmtimer_clocksource *clksrc; 7588c2ecf20Sopenharmony_ci struct dmtimer_systimer *t; 7598c2ecf20Sopenharmony_ci struct clocksource *dev; 7608c2ecf20Sopenharmony_ci int error; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL); 7638c2ecf20Sopenharmony_ci if (!clksrc) 7648c2ecf20Sopenharmony_ci return -ENOMEM; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci dev = &clksrc->dev; 7678c2ecf20Sopenharmony_ci t = &clksrc->t; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci error = dmtimer_systimer_setup(np, t); 7708c2ecf20Sopenharmony_ci if (error) 7718c2ecf20Sopenharmony_ci goto err_out_free; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci dev->name = "dmtimer"; 7748c2ecf20Sopenharmony_ci dev->rating = 300; 7758c2ecf20Sopenharmony_ci dev->read = dmtimer_clocksource_read_cycles; 7768c2ecf20Sopenharmony_ci dev->mask = CLOCKSOURCE_MASK(32); 7778c2ecf20Sopenharmony_ci dev->flags = CLOCK_SOURCE_IS_CONTINUOUS; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Unlike for clockevent, legacy code sets suspend only for am4 */ 7808c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,am43")) { 7818c2ecf20Sopenharmony_ci dev->suspend = dmtimer_clocksource_suspend; 7828c2ecf20Sopenharmony_ci dev->resume = dmtimer_clocksource_resume; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci writel_relaxed(0, t->base + t->counter); 7868c2ecf20Sopenharmony_ci writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 7878c2ecf20Sopenharmony_ci t->base + t->ctrl); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci pr_info("TI gptimer clocksource: %s%pOF\n", 7908c2ecf20Sopenharmony_ci of_find_property(np, "ti,timer-alwon", NULL) ? 7918c2ecf20Sopenharmony_ci "always-on " : "", np->parent); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (!dmtimer_sched_clock_counter) { 7948c2ecf20Sopenharmony_ci dmtimer_sched_clock_counter = t->base + t->counter; 7958c2ecf20Sopenharmony_ci sched_clock_register(dmtimer_read_sched_clock, 32, t->rate); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (clocksource_register_hz(dev, t->rate)) 7998c2ecf20Sopenharmony_ci pr_err("Could not register clocksource %pOF\n", np); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cierr_out_free: 8048c2ecf20Sopenharmony_ci kfree(clksrc); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return -ENODEV; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* 8108c2ecf20Sopenharmony_ci * To detect between a clocksource and clockevent, we assume the device tree 8118c2ecf20Sopenharmony_ci * has no interrupts configured for a clocksource timer. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_cistatic int __init dmtimer_systimer_init(struct device_node *np) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci const __be32 *addr; 8168c2ecf20Sopenharmony_ci u32 pa; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* One time init for the preferred timer configuration */ 8198c2ecf20Sopenharmony_ci if (!clocksource && !clockevent) 8208c2ecf20Sopenharmony_ci dmtimer_systimer_select_best(); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (!clocksource && !clockevent) { 8238c2ecf20Sopenharmony_ci pr_err("%s: unable to detect system timers, update dtb?\n", 8248c2ecf20Sopenharmony_ci __func__); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return -EINVAL; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci addr = of_get_address(np, 0, NULL, NULL); 8308c2ecf20Sopenharmony_ci pa = of_translate_address(np, addr); 8318c2ecf20Sopenharmony_ci if (!pa) 8328c2ecf20Sopenharmony_ci return -EINVAL; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (counter_32k <= 0 && clocksource == pa) 8358c2ecf20Sopenharmony_ci return dmtimer_clocksource_init(np); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (clockevent == pa) 8388c2ecf20Sopenharmony_ci return dmtimer_clockevent_init(np); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,dra7")) 8418c2ecf20Sopenharmony_ci return dmtimer_percpu_quirk_init(np, pa); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return 0; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap2, "ti,omap2420-timer", dmtimer_systimer_init); 8478c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap3, "ti,omap3430-timer", dmtimer_systimer_init); 8488c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap4, "ti,omap4430-timer", dmtimer_systimer_init); 8498c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap5, "ti,omap5430-timer", dmtimer_systimer_init); 8508c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_am33x, "ti,am335x-timer", dmtimer_systimer_init); 8518c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_am3ms, "ti,am335x-timer-1ms", dmtimer_systimer_init); 8528c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm814, "ti,dm814-timer", dmtimer_systimer_init); 8538c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm816, "ti,dm816-timer", dmtimer_systimer_init); 854