1 // SPDX-License-Identifier: GPL-2.0-only !! 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * linux/arch/arm/kernel/time.c !! 3 * Copyright 2001 MontaVista Software Inc. >> 4 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net >> 5 * Copyright (c) 2003, 2004 Maciej W. Rozycki 4 * 6 * 5 * Copyright (C) 1991, 1992, 1995 Linus Torv !! 7 * Common time service routines for MIPS machines. 6 * Modifications for ARM (C) 1994-2001 Russel << 7 * << 8 * This file contains the ARM-specific time h << 9 * reading the RTC at bootup, etc... << 10 */ 8 */ >> 9 #include <linux/bug.h> 11 #include <linux/clockchips.h> 10 #include <linux/clockchips.h> 12 #include <linux/clocksource.h> !! 11 #include <linux/types.h> 13 #include <linux/errno.h> << 14 #include <linux/export.h> << 15 #include <linux/init.h> << 16 #include <linux/interrupt.h> << 17 #include <linux/irq.h> << 18 #include <linux/kernel.h> 12 #include <linux/kernel.h> 19 #include <linux/of_clk.h> !! 13 #include <linux/init.h> 20 #include <linux/profile.h> << 21 #include <linux/sched.h> 14 #include <linux/sched.h> 22 #include <linux/sched_clock.h> !! 15 #include <linux/param.h> 23 #include <linux/smp.h> << 24 #include <linux/time.h> 16 #include <linux/time.h> 25 #include <linux/timex.h> 17 #include <linux/timex.h> 26 #include <linux/timer.h> !! 18 #include <linux/smp.h> 27 !! 19 #include <linux/spinlock.h> 28 #include <asm/mach/arch.h> !! 20 #include <linux/export.h> 29 #include <asm/mach/time.h> !! 21 #include <linux/cpufreq.h> 30 #include <asm/stacktrace.h> !! 22 #include <linux/delay.h> 31 #include <asm/thread_info.h> << 32 << 33 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CO << 34 defined(CONFIG_NVRAM) || defined(CONFIG_NV << 35 /* this needs a better home */ << 36 DEFINE_SPINLOCK(rtc_lock); << 37 EXPORT_SYMBOL(rtc_lock); << 38 #endif /* pc-style 'CMOS' RTC support */ << 39 23 40 /* change this if you have some constant time !! 24 #include <asm/cpu-features.h> 41 #define USECS_PER_JIFFY (1000000/HZ) !! 25 #include <asm/cpu-type.h> >> 26 #include <asm/div64.h> >> 27 #include <asm/time.h> >> 28 >> 29 #ifdef CONFIG_CPU_FREQ >> 30 >> 31 static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref); >> 32 static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref_freq); >> 33 static unsigned long glb_lpj_ref; >> 34 static unsigned long glb_lpj_ref_freq; 42 35 43 #ifdef CONFIG_SMP !! 36 static int cpufreq_callback(struct notifier_block *nb, 44 unsigned long profile_pc(struct pt_regs *regs) !! 37 unsigned long val, void *data) 45 { 38 { 46 struct stackframe frame; !! 39 struct cpufreq_freqs *freq = data; 47 !! 40 struct cpumask *cpus = freq->policy->cpus; 48 if (!in_lock_functions(regs->ARM_pc)) !! 41 unsigned long lpj; 49 return regs->ARM_pc; !! 42 int cpu; >> 43 >> 44 /* >> 45 * Skip lpj numbers adjustment if the CPU-freq transition is safe for >> 46 * the loops delay. (Is this possible?) >> 47 */ >> 48 if (freq->flags & CPUFREQ_CONST_LOOPS) >> 49 return NOTIFY_OK; >> 50 >> 51 /* Save the initial values of the lpjes for future scaling. */ >> 52 if (!glb_lpj_ref) { >> 53 glb_lpj_ref = boot_cpu_data.udelay_val; >> 54 glb_lpj_ref_freq = freq->old; >> 55 >> 56 for_each_online_cpu(cpu) { >> 57 per_cpu(pcp_lpj_ref, cpu) = >> 58 cpu_data[cpu].udelay_val; >> 59 per_cpu(pcp_lpj_ref_freq, cpu) = freq->old; >> 60 } >> 61 } 50 62 51 arm_get_current_stackframe(regs, &fram !! 63 /* 52 do { !! 64 * Adjust global lpj variable and per-CPU udelay_val number in 53 int ret = unwind_frame(&frame) !! 65 * accordance with the new CPU frequency. 54 if (ret < 0) !! 66 */ 55 return 0; !! 67 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || 56 } while (in_lock_functions(frame.pc)); !! 68 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { >> 69 loops_per_jiffy = cpufreq_scale(glb_lpj_ref, >> 70 glb_lpj_ref_freq, >> 71 freq->new); >> 72 >> 73 for_each_cpu(cpu, cpus) { >> 74 lpj = cpufreq_scale(per_cpu(pcp_lpj_ref, cpu), >> 75 per_cpu(pcp_lpj_ref_freq, cpu), >> 76 freq->new); >> 77 cpu_data[cpu].udelay_val = (unsigned int)lpj; >> 78 } >> 79 } 57 80 58 return frame.pc; !! 81 return NOTIFY_OK; 59 } 82 } 60 EXPORT_SYMBOL(profile_pc); << 61 #endif << 62 83 63 static void dummy_clock_access(struct timespec !! 84 static struct notifier_block cpufreq_notifier = { >> 85 .notifier_call = cpufreq_callback, >> 86 }; >> 87 >> 88 static int __init register_cpufreq_notifier(void) 64 { 89 { 65 ts->tv_sec = 0; !! 90 return cpufreq_register_notifier(&cpufreq_notifier, 66 ts->tv_nsec = 0; !! 91 CPUFREQ_TRANSITION_NOTIFIER); 67 } 92 } >> 93 core_initcall(register_cpufreq_notifier); 68 94 69 static clock_access_fn __read_persistent_clock !! 95 #endif /* CONFIG_CPU_FREQ */ 70 96 71 void read_persistent_clock64(struct timespec64 !! 97 /* >> 98 * forward reference >> 99 */ >> 100 DEFINE_SPINLOCK(rtc_lock); >> 101 EXPORT_SYMBOL(rtc_lock); >> 102 >> 103 static int null_perf_irq(void) 72 { 104 { 73 __read_persistent_clock(ts); !! 105 return 0; 74 } 106 } 75 107 76 int __init register_persistent_clock(clock_acc !! 108 int (*perf_irq)(void) = null_perf_irq; >> 109 >> 110 EXPORT_SYMBOL(perf_irq); >> 111 >> 112 /* >> 113 * time_init() - it does the following things. >> 114 * >> 115 * 1) plat_time_init() - >> 116 * a) (optional) set up RTC routines, >> 117 * b) (optional) calibrate and set the mips_hpt_frequency >> 118 * (only needed if you intended to use cpu counter as timer interrupt >> 119 * source) >> 120 * 2) calculate a couple of cached variables for later usage >> 121 */ >> 122 >> 123 unsigned int mips_hpt_frequency; >> 124 EXPORT_SYMBOL_GPL(mips_hpt_frequency); >> 125 >> 126 static __init int cpu_has_mfc0_count_bug(void) 77 { 127 { 78 /* Only allow the clockaccess function !! 128 switch (current_cpu_type()) { 79 if (__read_persistent_clock == dummy_c !! 129 case CPU_R4000PC: 80 if (read_persistent) !! 130 case CPU_R4000SC: 81 __read_persistent_cloc !! 131 case CPU_R4000MC: 82 return 0; !! 132 /* >> 133 * V3.0 is documented as suffering from the mfc0 from count bug. >> 134 * Afaik this is the last version of the R4000. Later versions >> 135 * were marketed as R4400. >> 136 */ >> 137 return 1; >> 138 >> 139 case CPU_R4400PC: >> 140 case CPU_R4400SC: >> 141 case CPU_R4400MC: >> 142 /* >> 143 * The published errata for the R4400 up to 3.0 say the CPU >> 144 * has the mfc0 from count bug. This seems the last version >> 145 * produced. >> 146 */ >> 147 return 1; 83 } 148 } 84 149 85 return -EINVAL; !! 150 return 0; 86 } 151 } 87 152 88 void __init time_init(void) 153 void __init time_init(void) 89 { 154 { 90 if (machine_desc->init_time) { !! 155 plat_time_init(); 91 machine_desc->init_time(); !! 156 92 } else { !! 157 /* 93 #ifdef CONFIG_COMMON_CLK !! 158 * The use of the R4k timer as a clock event takes precedence; 94 of_clk_init(NULL); !! 159 * if reading the Count register might interfere with the timer 95 #endif !! 160 * interrupt, then we don't use the timer as a clock source. 96 timer_probe(); !! 161 * We may still use the timer as a clock source though if the 97 tick_setup_hrtimer_broadcast() !! 162 * timer interrupt isn't reliable; the interference doesn't 98 } !! 163 * matter then, because we don't use the interrupt. >> 164 */ >> 165 if (mips_clockevent_init() != 0 || !cpu_has_mfc0_count_bug()) >> 166 init_mips_clocksource(); 99 } 167 } 100 168
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.