xref: /openbmc/linux/arch/hexagon/kernel/time.c (revision 2a598d0b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Time related functions for Hexagon architecture
4  *
5  * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
6  */
7 
8 #include <linux/init.h>
9 #include <linux/clockchips.h>
10 #include <linux/clocksource.h>
11 #include <linux/interrupt.h>
12 #include <linux/err.h>
13 #include <linux/platform_device.h>
14 #include <linux/ioport.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
18 #include <linux/module.h>
19 
20 #include <asm/hexagon_vm.h>
21 
22 #define TIMER_ENABLE		BIT(0)
23 
24 /*
25  * For the clocksource we need:
26  *	pcycle frequency (600MHz)
27  * For the loops_per_jiffy we need:
28  *	thread/cpu frequency (100MHz)
29  * And for the timer, we need:
30  *	sleep clock rate
31  */
32 
33 cycles_t	pcycle_freq_mhz;
34 cycles_t	thread_freq_mhz;
35 cycles_t	sleep_clk_freq;
36 
37 /*
38  * 8x50 HDD Specs 5-8.  Simulator co-sim not fixed until
39  * release 1.1, and then it's "adjustable" and probably not defaulted.
40  */
41 #define RTOS_TIMER_INT		3
42 #define RTOS_TIMER_REGS_ADDR	0xAB000000UL
43 
44 static struct resource rtos_timer_resources[] = {
45 	{
46 		.start	= RTOS_TIMER_REGS_ADDR,
47 		.end	= RTOS_TIMER_REGS_ADDR+PAGE_SIZE-1,
48 		.flags	= IORESOURCE_MEM,
49 	},
50 };
51 
52 static struct platform_device rtos_timer_device = {
53 	.name		= "rtos_timer",
54 	.id		= -1,
55 	.num_resources	= ARRAY_SIZE(rtos_timer_resources),
56 	.resource	= rtos_timer_resources,
57 };
58 
59 /*  A lot of this stuff should move into a platform specific section.  */
60 struct adsp_hw_timer_struct {
61 	u32 match;   /*  Match value  */
62 	u32 count;
63 	u32 enable;  /*  [1] - CLR_ON_MATCH_EN, [0] - EN  */
64 	u32 clear;   /*  one-shot register that clears the count  */
65 };
66 
67 /*  Look for "TCX0" for related constants.  */
68 static __iomem struct adsp_hw_timer_struct *rtos_timer;
69 
70 static u64 timer_get_cycles(struct clocksource *cs)
71 {
72 	return (u64) __vmgettime();
73 }
74 
75 static struct clocksource hexagon_clocksource = {
76 	.name		= "pcycles",
77 	.rating		= 250,
78 	.read		= timer_get_cycles,
79 	.mask		= CLOCKSOURCE_MASK(64),
80 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
81 };
82 
83 static int set_next_event(unsigned long delta, struct clock_event_device *evt)
84 {
85 	/*  Assuming the timer will be disabled when we enter here.  */
86 
87 	iowrite32(1, &rtos_timer->clear);
88 	iowrite32(0, &rtos_timer->clear);
89 
90 	iowrite32(delta, &rtos_timer->match);
91 	iowrite32(TIMER_ENABLE, &rtos_timer->enable);
92 	return 0;
93 }
94 
95 #ifdef CONFIG_SMP
96 /*  Broadcast mechanism  */
97 static void broadcast(const struct cpumask *mask)
98 {
99 	send_ipi(mask, IPI_TIMER);
100 }
101 #endif
102 
103 /* XXX Implement set_state_shutdown() */
104 static struct clock_event_device hexagon_clockevent_dev = {
105 	.name		= "clockevent",
106 	.features	= CLOCK_EVT_FEAT_ONESHOT,
107 	.rating		= 400,
108 	.irq		= RTOS_TIMER_INT,
109 	.set_next_event = set_next_event,
110 #ifdef CONFIG_SMP
111 	.broadcast	= broadcast,
112 #endif
113 };
114 
115 #ifdef CONFIG_SMP
116 static DEFINE_PER_CPU(struct clock_event_device, clock_events);
117 
118 void setup_percpu_clockdev(void)
119 {
120 	int cpu = smp_processor_id();
121 	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
122 	struct clock_event_device *dummy_clock_dev =
123 		&per_cpu(clock_events, cpu);
124 
125 	memcpy(dummy_clock_dev, ce_dev, sizeof(*dummy_clock_dev));
126 	INIT_LIST_HEAD(&dummy_clock_dev->list);
127 
128 	dummy_clock_dev->features = CLOCK_EVT_FEAT_DUMMY;
129 	dummy_clock_dev->cpumask = cpumask_of(cpu);
130 
131 	clockevents_register_device(dummy_clock_dev);
132 }
133 
134 /*  Called from smp.c for each CPU's timer ipi call  */
135 void ipi_timer(void)
136 {
137 	int cpu = smp_processor_id();
138 	struct clock_event_device *ce_dev = &per_cpu(clock_events, cpu);
139 
140 	ce_dev->event_handler(ce_dev);
141 }
142 #endif /* CONFIG_SMP */
143 
144 static irqreturn_t timer_interrupt(int irq, void *devid)
145 {
146 	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
147 
148 	iowrite32(0, &rtos_timer->enable);
149 	ce_dev->event_handler(ce_dev);
150 
151 	return IRQ_HANDLED;
152 }
153 
154 /*
155  * time_init_deferred - called by start_kernel to set up timer/clock source
156  *
157  * Install the IRQ handler for the clock, setup timers.
158  * This is done late, as that way, we can use ioremap().
159  *
160  * This runs just before the delay loop is calibrated, and
161  * is used for delay calibration.
162  */
163 void __init time_init_deferred(void)
164 {
165 	struct resource *resource = NULL;
166 	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
167 	unsigned long flag = IRQF_TIMER | IRQF_TRIGGER_RISING;
168 
169 	ce_dev->cpumask = cpu_all_mask;
170 
171 	if (!resource)
172 		resource = rtos_timer_device.resource;
173 
174 	/*  ioremap here means this has to run later, after paging init  */
175 	rtos_timer = ioremap(resource->start, resource_size(resource));
176 
177 	if (!rtos_timer) {
178 		release_mem_region(resource->start, resource_size(resource));
179 	}
180 	clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
181 
182 	/*  Note: the sim generic RTOS clock is apparently really 18750Hz  */
183 
184 	/*
185 	 * Last arg is some guaranteed seconds for which the conversion will
186 	 * work without overflow.
187 	 */
188 	clockevents_calc_mult_shift(ce_dev, sleep_clk_freq, 4);
189 
190 	ce_dev->max_delta_ns = clockevent_delta2ns(0x7fffffff, ce_dev);
191 	ce_dev->max_delta_ticks = 0x7fffffff;
192 	ce_dev->min_delta_ns = clockevent_delta2ns(0xf, ce_dev);
193 	ce_dev->min_delta_ticks = 0xf;
194 
195 #ifdef CONFIG_SMP
196 	setup_percpu_clockdev();
197 #endif
198 
199 	clockevents_register_device(ce_dev);
200 	if (request_irq(ce_dev->irq, timer_interrupt, flag, "rtos_timer", NULL))
201 		pr_err("Failed to register rtos_timer interrupt\n");
202 }
203 
204 void __init time_init(void)
205 {
206 	late_time_init = time_init_deferred;
207 }
208 
209 void __delay(unsigned long cycles)
210 {
211 	unsigned long long start = __vmgettime();
212 
213 	while ((__vmgettime() - start) < cycles)
214 		cpu_relax();
215 }
216 EXPORT_SYMBOL(__delay);
217 
218 /*
219  * This could become parametric or perhaps even computed at run-time,
220  * but for now we take the observed simulator jitter.
221  */
222 static long long fudgefactor = 350;  /* Maybe lower if kernel optimized. */
223 
224 void __udelay(unsigned long usecs)
225 {
226 	unsigned long long start = __vmgettime();
227 	unsigned long long finish = (pcycle_freq_mhz * usecs) - fudgefactor;
228 
229 	while ((__vmgettime() - start) < finish)
230 		cpu_relax(); /*  not sure how this improves readability  */
231 }
232 EXPORT_SYMBOL(__udelay);
233