1 // SPDX-License-Identifier: GPL-2.0-only !! 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * Copyright (C) 2012 Regents of the Universit !! 3 * Copyright 2001 MontaVista Software Inc. 4 * Copyright (C) 2017 SiFive !! 4 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net >> 5 * Copyright (c) 2003, 2004 Maciej W. Rozycki >> 6 * >> 7 * Common time service routines for MIPS machines. 5 */ 8 */ 6 !! 9 #include <linux/bug.h> 7 #include <linux/acpi.h> << 8 #include <linux/of_clk.h> << 9 #include <linux/clockchips.h> 10 #include <linux/clockchips.h> 10 #include <linux/clocksource.h> !! 11 #include <linux/types.h> >> 12 #include <linux/kernel.h> >> 13 #include <linux/init.h> >> 14 #include <linux/sched.h> >> 15 #include <linux/param.h> >> 16 #include <linux/time.h> >> 17 #include <linux/timex.h> >> 18 #include <linux/smp.h> >> 19 #include <linux/spinlock.h> >> 20 #include <linux/export.h> >> 21 #include <linux/cpufreq.h> 11 #include <linux/delay.h> 22 #include <linux/delay.h> 12 #include <asm/sbi.h> << 13 #include <asm/processor.h> << 14 #include <asm/timex.h> << 15 #include <asm/paravirt.h> << 16 23 17 unsigned long riscv_timebase __ro_after_init; !! 24 #include <asm/cpu-features.h> 18 EXPORT_SYMBOL_GPL(riscv_timebase); !! 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; 19 35 20 void __init time_init(void) !! 36 static int cpufreq_callback(struct notifier_block *nb, >> 37 unsigned long val, void *data) 21 { 38 { 22 struct device_node *cpu; !! 39 struct cpufreq_freqs *freq = data; 23 struct acpi_table_rhct *rhct; !! 40 struct cpumask *cpus = freq->policy->cpus; 24 acpi_status status; !! 41 unsigned long lpj; 25 u32 prop; !! 42 int cpu; 26 !! 43 27 if (acpi_disabled) { !! 44 /* 28 cpu = of_find_node_by_path("/c !! 45 * Skip lpj numbers adjustment if the CPU-freq transition is safe for 29 if (!cpu || of_property_read_u !! 46 * the loops delay. (Is this possible?) 30 panic("RISC-V system w !! 47 */ 31 !! 48 if (freq->flags & CPUFREQ_CONST_LOOPS) 32 of_node_put(cpu); !! 49 return NOTIFY_OK; 33 riscv_timebase = prop; !! 50 34 of_clk_init(NULL); !! 51 /* Save the initial values of the lpjes for future scaling. */ 35 } else { !! 52 if (!glb_lpj_ref) { 36 status = acpi_get_table(ACPI_S !! 53 glb_lpj_ref = boot_cpu_data.udelay_val; 37 if (ACPI_FAILURE(status)) !! 54 glb_lpj_ref_freq = freq->old; 38 panic("RISC-V ACPI sys !! 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 } 39 62 40 riscv_timebase = rhct->time_ba !! 63 /* 41 acpi_put_table((struct acpi_ta !! 64 * Adjust global lpj variable and per-CPU udelay_val number in >> 65 * accordance with the new CPU frequency. >> 66 */ >> 67 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || >> 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 } 42 } 79 } 43 80 44 lpj_fine = riscv_timebase / HZ; !! 81 return NOTIFY_OK; >> 82 } >> 83 >> 84 static struct notifier_block cpufreq_notifier = { >> 85 .notifier_call = cpufreq_callback, >> 86 }; >> 87 >> 88 static int __init register_cpufreq_notifier(void) >> 89 { >> 90 return cpufreq_register_notifier(&cpufreq_notifier, >> 91 CPUFREQ_TRANSITION_NOTIFIER); >> 92 } >> 93 core_initcall(register_cpufreq_notifier); >> 94 >> 95 #endif /* CONFIG_CPU_FREQ */ >> 96 >> 97 /* >> 98 * forward reference >> 99 */ >> 100 DEFINE_SPINLOCK(rtc_lock); >> 101 EXPORT_SYMBOL(rtc_lock); >> 102 >> 103 static int null_perf_irq(void) >> 104 { >> 105 return 0; >> 106 } 45 107 46 timer_probe(); !! 108 int (*perf_irq)(void) = null_perf_irq; 47 109 48 tick_setup_hrtimer_broadcast(); !! 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) >> 127 { >> 128 switch (current_cpu_type()) { >> 129 case CPU_R4000PC: >> 130 case CPU_R4000SC: >> 131 case CPU_R4000MC: >> 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; >> 148 } >> 149 >> 150 return 0; >> 151 } >> 152 >> 153 void __init time_init(void) >> 154 { >> 155 plat_time_init(); 49 156 50 pv_time_init(); !! 157 /* >> 158 * The use of the R4k timer as a clock event takes precedence; >> 159 * if reading the Count register might interfere with the timer >> 160 * interrupt, then we don't use the timer as a clock source. >> 161 * We may still use the timer as a clock source though if the >> 162 * timer interrupt isn't reliable; the interference doesn't >> 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(); 51 } 167 } 52 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.