| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | * drivers/clocksource/arm_global_timer.c | 
|---|
| 3 | 4 | * | 
|---|
| 4 | 5 | * Copyright (C) 2013 STMicroelectronics (R&D) Limited. | 
|---|
| 5 | 6 | * Author: Stuart Menefy <stuart.menefy@st.com> | 
|---|
| 6 | 7 | * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com> | 
|---|
| 7 |  | - * | 
|---|
| 8 |  | - * This program is free software; you can redistribute it and/or modify | 
|---|
| 9 |  | - * it under the terms of the GNU General Public License version 2 as | 
|---|
| 10 |  | - * published by the Free Software Foundation. | 
|---|
| 11 | 8 | */ | 
|---|
| 12 | 9 |  | 
|---|
| 13 | 10 | #include <linux/init.h> | 
|---|
| .. | .. | 
|---|
| 49 | 46 | * the units for all operations. | 
|---|
| 50 | 47 | */ | 
|---|
| 51 | 48 | static void __iomem *gt_base; | 
|---|
| 52 |  | -static struct clk *gt_clk; | 
|---|
| 53 | 49 | static unsigned long gt_clk_rate; | 
|---|
| 54 | 50 | static int gt_ppi; | 
|---|
| 55 | 51 | static struct clock_event_device __percpu *gt_evt; | 
|---|
| .. | .. | 
|---|
| 137 | 133 | gt_compare_set(evt, 0); | 
|---|
| 138 | 134 | return 0; | 
|---|
| 139 | 135 | } | 
|---|
| 140 |  | - | 
|---|
| 141 |  | -#ifdef CONFIG_COMMON_CLK | 
|---|
| 142 |  | - | 
|---|
| 143 |  | -/* | 
|---|
| 144 |  | - * Updates clockevent frequency when the cpu frequency changes. | 
|---|
| 145 |  | - * Called on the cpu that is changing frequency with interrupts disabled. | 
|---|
| 146 |  | - */ | 
|---|
| 147 |  | -static void gt_update_frequency(void *new_rate) | 
|---|
| 148 |  | -{ | 
|---|
| 149 |  | -	gt_clk_rate = *((unsigned long *) new_rate); | 
|---|
| 150 |  | - | 
|---|
| 151 |  | -	clockevents_update_freq(raw_cpu_ptr(gt_evt), gt_clk_rate); | 
|---|
| 152 |  | -} | 
|---|
| 153 |  | - | 
|---|
| 154 |  | -static int gt_rate_change(struct notifier_block *nb, | 
|---|
| 155 |  | -	unsigned long flags, void *data) | 
|---|
| 156 |  | -{ | 
|---|
| 157 |  | -	struct clk_notifier_data *cnd = data; | 
|---|
| 158 |  | - | 
|---|
| 159 |  | -	/* | 
|---|
| 160 |  | -	 * The gt clock events must be reprogrammed to account for the new | 
|---|
| 161 |  | -	 * frequency.  The timer is local to a cpu, so cross-call to the | 
|---|
| 162 |  | -	 * changing cpu. | 
|---|
| 163 |  | -	 */ | 
|---|
| 164 |  | -	if (flags == POST_RATE_CHANGE) | 
|---|
| 165 |  | -		on_each_cpu(gt_update_frequency, | 
|---|
| 166 |  | -				  (void *)&cnd->new_rate, 1); | 
|---|
| 167 |  | - | 
|---|
| 168 |  | -	return NOTIFY_OK; | 
|---|
| 169 |  | -} | 
|---|
| 170 |  | - | 
|---|
| 171 |  | -static struct notifier_block gt_clk_nb = { | 
|---|
| 172 |  | -	.notifier_call = gt_rate_change, | 
|---|
| 173 |  | -}; | 
|---|
| 174 |  | - | 
|---|
| 175 |  | -static int gt_clk_init(void) | 
|---|
| 176 |  | -{ | 
|---|
| 177 |  | -	if (gt_evt && raw_cpu_ptr(gt_evt) && !IS_ERR(gt_clk)) | 
|---|
| 178 |  | -		return clk_notifier_register(gt_clk, >_clk_nb); | 
|---|
| 179 |  | - | 
|---|
| 180 |  | -	return 0; | 
|---|
| 181 |  | -} | 
|---|
| 182 |  | -core_initcall(gt_clk_init); | 
|---|
| 183 |  | - | 
|---|
| 184 |  | -#elif defined (CONFIG_CPU_FREQ) | 
|---|
| 185 |  | - | 
|---|
| 186 |  | -#include <linux/cpufreq.h> | 
|---|
| 187 |  | - | 
|---|
| 188 |  | -/* | 
|---|
| 189 |  | - * Updates clockevent frequency when the cpu frequency changes. | 
|---|
| 190 |  | - * Called on the cpu that is changing frequency with interrupts disabled. | 
|---|
| 191 |  | - */ | 
|---|
| 192 |  | -static void gt_update_frequency(void *data) | 
|---|
| 193 |  | -{ | 
|---|
| 194 |  | -	gt_clk_rate = clk_get_rate(gt_clk); | 
|---|
| 195 |  | - | 
|---|
| 196 |  | -	clockevents_update_freq(raw_cpu_ptr(gt_evt), gt_clk_rate); | 
|---|
| 197 |  | -} | 
|---|
| 198 |  | - | 
|---|
| 199 |  | -static int gt_cpufreq_transition(struct notifier_block *nb, | 
|---|
| 200 |  | -	unsigned long state, void *data) | 
|---|
| 201 |  | -{ | 
|---|
| 202 |  | -	struct cpufreq_freqs *freqs = data; | 
|---|
| 203 |  | - | 
|---|
| 204 |  | -	/* | 
|---|
| 205 |  | -	 * The gt clock events must be reprogrammed to account for the new | 
|---|
| 206 |  | -	 * frequency.  The timer is local to a cpu, so cross-call to the | 
|---|
| 207 |  | -	 * changing cpu. | 
|---|
| 208 |  | -	 */ | 
|---|
| 209 |  | -	if (state == CPUFREQ_POSTCHANGE) | 
|---|
| 210 |  | -		smp_call_function_single(freqs->cpu, gt_update_frequency, | 
|---|
| 211 |  | -			NULL, 1); | 
|---|
| 212 |  | - | 
|---|
| 213 |  | -	return NOTIFY_OK; | 
|---|
| 214 |  | -} | 
|---|
| 215 |  | - | 
|---|
| 216 |  | -static struct notifier_block gt_cpufreq_nb = { | 
|---|
| 217 |  | -	.notifier_call = gt_cpufreq_transition, | 
|---|
| 218 |  | -}; | 
|---|
| 219 |  | - | 
|---|
| 220 |  | -static int gt_cpufreq_init(void) | 
|---|
| 221 |  | -{ | 
|---|
| 222 |  | -	if (gt_evt && raw_cpu_ptr(gt_evt) && !IS_ERR(gt_clk)) | 
|---|
| 223 |  | -		return cpufreq_register_notifier(>_cpufreq_nb, | 
|---|
| 224 |  | -			CPUFREQ_TRANSITION_NOTIFIER); | 
|---|
| 225 |  | - | 
|---|
| 226 |  | -	return 0; | 
|---|
| 227 |  | -} | 
|---|
| 228 |  | -core_initcall(gt_cpufreq_init); | 
|---|
| 229 |  | - | 
|---|
| 230 |  | -#endif | 
|---|
| 231 | 136 |  | 
|---|
| 232 | 137 | static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) | 
|---|
| 233 | 138 | { | 
|---|
| .. | .. | 
|---|
| 349 | 254 |  | 
|---|
| 350 | 255 | static int __init global_timer_of_register(struct device_node *np) | 
|---|
| 351 | 256 | { | 
|---|
|  | 257 | +	struct clk *gt_clk; | 
|---|
| 352 | 258 | int err = 0; | 
|---|
| 353 | 259 |  | 
|---|
| 354 | 260 | /* | 
|---|