| 1 | |
| 2 | |
| 3 |
|
| 4 | #define pr_fmt(fmt) "mips-gic-timer: " fmt
|
| 5 |
|
| 6 | #include <linux/clk.h>
|
| 7 | #include <linux/clockchips.h>
|
| 8 | #include <linux/cpu.h>
|
| 9 | #include <linux/init.h>
|
| 10 | #include <linux/interrupt.h>
|
| 11 | #include <linux/notifier.h>
|
| 12 | #include <linux/of_irq.h>
|
| 13 | #include <linux/percpu.h>
|
| 14 | #include <linux/sched_clock.h>
|
| 15 | #include <linux/smp.h>
|
| 16 | #include <linux/time.h>
|
| 17 | #include <asm/mips-cps.h>
|
| 18 |
|
| 19 | static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
|
| 20 | static int gic_timer_irq;
|
| 21 | static unsigned int gic_frequency;
|
| 22 | static unsigned int gic_count_width;
|
| 23 | static bool __read_mostly gic_clock_unstable;
|
| 24 |
|
| 25 | static void gic_clocksource_unstable(char *reason);
|
| 26 |
|
| 27 | static u64 notrace gic_read_count_2x32(void)
|
| 28 | {
|
| 29 | unsigned int hi, hi2, lo;
|
| 30 |
|
| 31 | do {
|
| 32 | hi = read_gic_counter_32h();
|
| 33 | lo = read_gic_counter_32l();
|
| 34 | hi2 = read_gic_counter_32h();
|
| 35 | } while (hi2 != hi);
|
| 36 |
|
| 37 | return (((u64) hi) << 32) + lo;
|
| 38 | }
|
| 39 |
|
| 40 | static u64 notrace gic_read_count_64(void)
|
| 41 | {
|
| 42 | return read_gic_counter();
|
| 43 | }
|
| 44 |
|
| 45 | static u64 notrace gic_read_count(void)
|
| 46 | {
|
| 47 | if (mips_cm_is64)
|
| 48 | return gic_read_count_64();
|
| 49 |
|
| 50 | return gic_read_count_2x32();
|
| 51 | }
|
| 52 |
|
| 53 | static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
|
| 54 | {
|
| 55 | int cpu = cpumask_first(evt->cpumask);
|
| 56 | u64 cnt;
|
| 57 | int res;
|
| 58 |
|
| 59 | cnt = gic_read_count();
|
| 60 | cnt += (u64)delta;
|
| 61 | if (cpu == raw_smp_processor_id()) {
|
| 62 | write_gic_vl_compare(cnt);
|
| 63 | } else {
|
| 64 | write_gic_vl_other(mips_cm_vp_id(cpu));
|
| 65 | write_gic_vo_compare(cnt);
|
| 66 | }
|
| 67 | res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
|
| 68 | return res;
|
| 69 | }
|
| 70 |
|
| 71 | static irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
|
| 72 | {
|
| 73 | struct clock_event_device *cd = dev_id;
|
| 74 |
|
| 75 | write_gic_vl_compare(read_gic_vl_compare());
|
| 76 | cd->event_handler(cd);
|
| 77 | return IRQ_HANDLED;
|
| 78 | }
|
| 79 |
|
| 80 | static void gic_clockevent_cpu_init(unsigned int cpu,
|
| 81 | struct clock_event_device *cd)
|
| 82 | {
|
| 83 | cd->name = "MIPS GIC";
|
| 84 | cd->features = CLOCK_EVT_FEAT_ONESHOT |
|
| 85 | CLOCK_EVT_FEAT_C3STOP;
|
| 86 |
|
| 87 | cd->rating = 350;
|
| 88 | cd->irq = gic_timer_irq;
|
| 89 | cd->cpumask = cpumask_of(cpu);
|
| 90 | cd->set_next_event = gic_next_event;
|
| 91 |
|
| 92 | clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff);
|
| 93 |
|
| 94 | enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE);
|
| 95 | }
|
| 96 |
|
| 97 | static void gic_clockevent_cpu_exit(struct clock_event_device *cd)
|
| 98 | {
|
| 99 | disable_percpu_irq(gic_timer_irq);
|
| 100 | }
|
| 101 |
|
| 102 | static void gic_update_frequency(void *data)
|
| 103 | {
|
| 104 | unsigned long rate = (unsigned long)data;
|
| 105 |
|
| 106 | clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate);
|
| 107 | }
|
| 108 |
|
| 109 | static int gic_starting_cpu(unsigned int cpu)
|
| 110 | {
|
| 111 |
|
| 112 | clear_gic_config(GIC_CONFIG_COUNTSTOP);
|
| 113 |
|
| 114 | gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device));
|
| 115 | return 0;
|
| 116 | }
|
| 117 |
|
| 118 | static int gic_clk_notifier(struct notifier_block *nb, unsigned long action,
|
| 119 | void *data)
|
| 120 | {
|
| 121 | struct clk_notifier_data *cnd = data;
|
| 122 |
|
| 123 | if (action == POST_RATE_CHANGE) {
|
| 124 | gic_clocksource_unstable("ref clock rate change");
|
| 125 | on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1);
|
| 126 | }
|
| 127 |
|
| 128 | return NOTIFY_OK;
|
| 129 | }
|
| 130 |
|
| 131 | static int gic_dying_cpu(unsigned int cpu)
|
| 132 | {
|
| 133 | gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device));
|
| 134 | return 0;
|
| 135 | }
|
| 136 |
|
| 137 | static struct notifier_block gic_clk_nb = {
|
| 138 | .notifier_call = gic_clk_notifier,
|
| 139 | };
|
| 140 |
|
| 141 | static int gic_clockevent_init(void)
|
| 142 | {
|
| 143 | int ret;
|
| 144 |
|
| 145 | if (!gic_frequency)
|
| 146 | return -ENXIO;
|
| 147 |
|
| 148 | ret = request_percpu_irq(gic_timer_irq, gic_compare_interrupt,
|
| 149 | "timer", &gic_clockevent_device);
|
| 150 | if (ret < 0) {
|
| 151 | pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret);
|
| 152 | return ret;
|
| 153 | }
|
| 154 |
|
| 155 | cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING,
|
| 156 | "clockevents/mips/gic/timer:starting",
|
| 157 | gic_starting_cpu, gic_dying_cpu);
|
| 158 | return 0;
|
| 159 | }
|
| 160 |
|
| 161 | static u64 gic_hpt_read(struct clocksource *cs)
|
| 162 | {
|
| 163 | return gic_read_count();
|
| 164 | }
|
| 165 |
|
| 166 | static u64 gic_hpt_read_multicluster(struct clocksource *cs)
|
| 167 | {
|
| 168 | unsigned int hi, hi2, lo;
|
| 169 | u64 count;
|
| 170 |
|
| 171 | mips_cm_lock_other(0, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
|
| 172 |
|
| 173 | if (mips_cm_is64) {
|
| 174 | count = read_gic_redir_counter();
|
| 175 | goto out;
|
| 176 | }
|
| 177 |
|
| 178 | hi = read_gic_redir_counter_32h();
|
| 179 | while (true) {
|
| 180 | lo = read_gic_redir_counter_32l();
|
| 181 |
|
| 182 |
|
| 183 | hi2 = read_gic_redir_counter_32h();
|
| 184 | if (hi2 == hi)
|
| 185 | break;
|
| 186 |
|
| 187 |
|
| 188 | hi = hi2;
|
| 189 | }
|
| 190 |
|
| 191 | count = (((u64)hi) << 32) + lo;
|
| 192 | out:
|
| 193 | mips_cm_unlock_other();
|
| 194 | return count;
|
| 195 | }
|
| 196 |
|
| 197 | static struct clocksource gic_clocksource = {
|
| 198 | .name = "GIC",
|
| 199 | .read = gic_hpt_read,
|
| 200 | .flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
| 201 | .vdso_clock_mode = VDSO_CLOCKMODE_GIC,
|
| 202 | };
|
| 203 |
|
| 204 | static void gic_clocksource_unstable(char *reason)
|
| 205 | {
|
| 206 | if (gic_clock_unstable)
|
| 207 | return;
|
| 208 |
|
| 209 | gic_clock_unstable = true;
|
| 210 |
|
| 211 | pr_info("GIC timer is unstable due to %s\n", reason);
|
| 212 |
|
| 213 | clocksource_mark_unstable(&gic_clocksource);
|
| 214 | }
|
| 215 |
|
| 216 | static int __init __gic_clocksource_init(void)
|
| 217 | {
|
| 218 | int ret;
|
| 219 |
|
| 220 |
|
| 221 | gic_count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
|
| 222 | gic_count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
|
| 223 | gic_count_width *= 4;
|
| 224 | gic_count_width += 32;
|
| 225 | gic_clocksource.mask = CLOCKSOURCE_MASK(gic_count_width);
|
| 226 |
|
| 227 |
|
| 228 | if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ))
|
| 229 | gic_clocksource.rating = 300;
|
| 230 | else
|
| 231 | gic_clocksource.rating = 200;
|
| 232 | gic_clocksource.rating += clamp(gic_frequency / 10000000, 0, 99);
|
| 233 |
|
| 234 | if (mips_cps_multicluster_cpus()) {
|
| 235 | gic_clocksource.read = &gic_hpt_read_multicluster;
|
| 236 | gic_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_NONE;
|
| 237 | }
|
| 238 |
|
| 239 | ret = clocksource_register_hz(&gic_clocksource, gic_frequency);
|
| 240 | if (ret < 0)
|
| 241 | pr_warn("Unable to register clocksource\n");
|
| 242 |
|
| 243 | return ret;
|
| 244 | }
|
| 245 |
|
| 246 | static int __init gic_clocksource_of_init(struct device_node *node)
|
| 247 | {
|
| 248 | struct clk *clk;
|
| 249 | int ret;
|
| 250 |
|
| 251 | if (!mips_gic_present() || !node->parent ||
|
| 252 | !of_device_is_compatible(node->parent, "mti,gic")) {
|
| 253 | pr_warn("No DT definition\n");
|
| 254 | return -ENXIO;
|
| 255 | }
|
| 256 |
|
| 257 | clk = of_clk_get(node, 0);
|
| 258 | if (!IS_ERR(clk)) {
|
| 259 | ret = clk_prepare_enable(clk);
|
| 260 | if (ret < 0) {
|
| 261 | pr_err("Failed to enable clock\n");
|
| 262 | clk_put(clk);
|
| 263 | return ret;
|
| 264 | }
|
| 265 |
|
| 266 | gic_frequency = clk_get_rate(clk);
|
| 267 | } else if (of_property_read_u32(node, "clock-frequency",
|
| 268 | &gic_frequency)) {
|
| 269 | pr_err("Frequency not specified\n");
|
| 270 | return -EINVAL;
|
| 271 | }
|
| 272 | gic_timer_irq = irq_of_parse_and_map(node, 0);
|
| 273 | if (!gic_timer_irq) {
|
| 274 | pr_err("IRQ not specified\n");
|
| 275 | return -EINVAL;
|
| 276 | }
|
| 277 |
|
| 278 | ret = __gic_clocksource_init();
|
| 279 | if (ret)
|
| 280 | return ret;
|
| 281 |
|
| 282 | ret = gic_clockevent_init();
|
| 283 | if (!ret && !IS_ERR(clk)) {
|
| 284 | if (clk_notifier_register(clk, &gic_clk_nb) < 0)
|
| 285 | pr_warn("Unable to register clock notifier\n");
|
| 286 | }
|
| 287 |
|
| 288 | |
| 289 | * It's safe to use the MIPS GIC timer as a sched clock source only if
|
| 290 | * its ticks are stable, which is true on either the platforms with
|
| 291 | * stable CPU frequency or on the platforms with CM3 and CPU frequency
|
| 292 | * change performed by the CPC core clocks divider.
|
| 293 |
|
| 294 | if ((mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) &&
|
| 295 | !mips_cps_multicluster_cpus()) {
|
| 296 | sched_clock_register(mips_cm_is64 ?
|
| 297 | gic_read_count_64 : gic_read_count_2x32,
|
| 298 | gic_count_width, gic_frequency);
|
| 299 | }
|
| 300 |
|
| 301 | return 0;
|
| 302 | }
|
| 303 | TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer",
|
| 304 | gic_clocksource_of_init);
|