2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <linux/interrupt.h>
34 #include <linux/clocksource.h>
35 #include <linux/clockchips.h>
36 #include <linux/clk.h>
38 #include <linux/of_irq.h>
39 #include <linux/cpu.h>
40 #include <soc/nps/common.h>
42 #define NPS_MSU_TICK_LOW 0xC8
43 #define NPS_CLUSTER_OFFSET 8
44 #define NPS_CLUSTER_NUM 16
46 /* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */
47 static void *nps_msu_reg_low_addr
[NPS_CLUSTER_NUM
] __read_mostly
;
49 static int __init
nps_get_timer_clk(struct device_node
*node
,
50 unsigned long *timer_freq
,
55 *clk
= of_clk_get(node
, 0);
56 ret
= PTR_ERR_OR_ZERO(*clk
);
58 pr_err("timer missing clk");
62 ret
= clk_prepare_enable(*clk
);
64 pr_err("Couldn't enable parent clk\n");
69 *timer_freq
= clk_get_rate(*clk
);
71 pr_err("Couldn't get clk rate\n");
72 clk_disable_unprepare(*clk
);
80 static u64
nps_clksrc_read(struct clocksource
*clksrc
)
82 int cluster
= raw_smp_processor_id() >> NPS_CLUSTER_OFFSET
;
84 return (u64
)ioread32be(nps_msu_reg_low_addr
[cluster
]);
87 static int __init
nps_setup_clocksource(struct device_node
*node
)
91 unsigned long nps_timer1_freq
;
94 for (cluster
= 0; cluster
< NPS_CLUSTER_NUM
; cluster
++)
95 nps_msu_reg_low_addr
[cluster
] =
96 nps_host_reg((cluster
<< NPS_CLUSTER_OFFSET
),
97 NPS_MSU_BLKID
, NPS_MSU_TICK_LOW
);
99 ret
= nps_get_timer_clk(node
, &nps_timer1_freq
, &clk
);
103 ret
= clocksource_mmio_init(nps_msu_reg_low_addr
, "nps-tick",
104 nps_timer1_freq
, 300, 32, nps_clksrc_read
);
106 pr_err("Couldn't register clock source.\n");
107 clk_disable_unprepare(clk
);
113 CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc
, "ezchip,nps400-timer",
114 nps_setup_clocksource
);
115 CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_src
, "ezchip,nps400-timer1",
116 nps_setup_clocksource
);
118 #ifdef CONFIG_EZNPS_MTM_EXT
119 #include <soc/nps/mtm.h>
121 /* Timer related Aux registers */
122 #define NPS_REG_TIMER0_TSI 0xFFFFF850
123 #define NPS_REG_TIMER0_LIMIT 0x23
124 #define NPS_REG_TIMER0_CTRL 0x22
125 #define NPS_REG_TIMER0_CNT 0x21
128 * Interrupt Enabled (IE) - re-arm the timer
129 * Not Halted (NH) - is cleared when working with JTAG (for debug)
131 #define TIMER0_CTRL_IE BIT(0)
132 #define TIMER0_CTRL_NH BIT(1)
134 static unsigned long nps_timer0_freq
;
135 static unsigned long nps_timer0_irq
;
137 static void nps_clkevent_rm_thread(void)
140 unsigned int cflags
, enabled_threads
;
142 hw_schd_save(&cflags
);
144 enabled_threads
= read_aux_reg(NPS_REG_TIMER0_TSI
);
146 /* remove thread from TSI1 */
147 thread
= read_aux_reg(CTOP_AUX_THREAD_ID
);
148 enabled_threads
&= ~(1 << thread
);
149 write_aux_reg(NPS_REG_TIMER0_TSI
, enabled_threads
);
151 /* Acknowledge and if needed re-arm the timer */
152 if (!enabled_threads
)
153 write_aux_reg(NPS_REG_TIMER0_CTRL
, TIMER0_CTRL_NH
);
155 write_aux_reg(NPS_REG_TIMER0_CTRL
,
156 TIMER0_CTRL_IE
| TIMER0_CTRL_NH
);
158 hw_schd_restore(cflags
);
161 static void nps_clkevent_add_thread(unsigned long delta
)
164 unsigned int cflags
, enabled_threads
;
166 hw_schd_save(&cflags
);
168 /* add thread to TSI1 */
169 thread
= read_aux_reg(CTOP_AUX_THREAD_ID
);
170 enabled_threads
= read_aux_reg(NPS_REG_TIMER0_TSI
);
171 enabled_threads
|= (1 << thread
);
172 write_aux_reg(NPS_REG_TIMER0_TSI
, enabled_threads
);
174 /* set next timer event */
175 write_aux_reg(NPS_REG_TIMER0_LIMIT
, delta
);
176 write_aux_reg(NPS_REG_TIMER0_CNT
, 0);
177 write_aux_reg(NPS_REG_TIMER0_CTRL
,
178 TIMER0_CTRL_IE
| TIMER0_CTRL_NH
);
180 hw_schd_restore(cflags
);
184 * Whenever anyone tries to change modes, we just mask interrupts
185 * and wait for the next event to get set.
187 static int nps_clkevent_set_state(struct clock_event_device
*dev
)
189 nps_clkevent_rm_thread();
190 disable_percpu_irq(nps_timer0_irq
);
195 static int nps_clkevent_set_next_event(unsigned long delta
,
196 struct clock_event_device
*dev
)
198 nps_clkevent_add_thread(delta
);
199 enable_percpu_irq(nps_timer0_irq
, IRQ_TYPE_NONE
);
204 static DEFINE_PER_CPU(struct clock_event_device
, nps_clockevent_device
) = {
205 .name
= "NPS Timer0",
206 .features
= CLOCK_EVT_FEAT_ONESHOT
,
208 .set_next_event
= nps_clkevent_set_next_event
,
209 .set_state_oneshot
= nps_clkevent_set_state
,
210 .set_state_oneshot_stopped
= nps_clkevent_set_state
,
211 .set_state_shutdown
= nps_clkevent_set_state
,
212 .tick_resume
= nps_clkevent_set_state
,
215 static irqreturn_t
timer_irq_handler(int irq
, void *dev_id
)
217 struct clock_event_device
*evt
= dev_id
;
219 nps_clkevent_rm_thread();
220 evt
->event_handler(evt
);
225 static int nps_timer_starting_cpu(unsigned int cpu
)
227 struct clock_event_device
*evt
= this_cpu_ptr(&nps_clockevent_device
);
229 evt
->cpumask
= cpumask_of(smp_processor_id());
231 clockevents_config_and_register(evt
, nps_timer0_freq
, 0, ULONG_MAX
);
232 enable_percpu_irq(nps_timer0_irq
, IRQ_TYPE_NONE
);
237 static int nps_timer_dying_cpu(unsigned int cpu
)
239 disable_percpu_irq(nps_timer0_irq
);
243 static int __init
nps_setup_clockevent(struct device_node
*node
)
248 nps_timer0_irq
= irq_of_parse_and_map(node
, 0);
249 if (nps_timer0_irq
<= 0) {
250 pr_err("clockevent: missing irq");
254 ret
= nps_get_timer_clk(node
, &nps_timer0_freq
, &clk
);
258 /* Needs apriori irq_set_percpu_devid() done in intc map function */
259 ret
= request_percpu_irq(nps_timer0_irq
, timer_irq_handler
,
260 "Timer0 (per-cpu-tick)",
261 &nps_clockevent_device
);
263 pr_err("Couldn't request irq\n");
264 clk_disable_unprepare(clk
);
268 ret
= cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING
,
269 "clockevents/nps:starting",
270 nps_timer_starting_cpu
,
271 nps_timer_dying_cpu
);
273 pr_err("Failed to setup hotplug state");
274 clk_disable_unprepare(clk
);
275 free_percpu_irq(nps_timer0_irq
, &nps_clockevent_device
);
282 CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_evt
, "ezchip,nps400-timer0",
283 nps_setup_clockevent
);
284 #endif /* CONFIG_EZNPS_MTM_EXT */