1 // SPDX-License-Identifier: GPL-2.0
3 * J-Core SoC PIT/clocksource driver
5 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
10 #include <linux/interrupt.h>
11 #include <linux/clockchips.h>
12 #include <linux/clocksource.h>
13 #include <linux/sched_clock.h>
14 #include <linux/cpu.h>
15 #include <linux/cpuhotplug.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
19 #define PIT_IRQ_SHIFT 12
20 #define PIT_PRIO_SHIFT 20
21 #define PIT_ENABLE_SHIFT 26
22 #define PIT_PRIO_MASK 0xf
24 #define REG_PITEN 0x00
25 #define REG_THROT 0x10
26 #define REG_COUNT 0x14
27 #define REG_BUSPD 0x18
28 #define REG_SECHI 0x20
29 #define REG_SECLO 0x24
33 struct clock_event_device ced
;
35 unsigned long periodic_delta
;
39 static void __iomem
*jcore_pit_base
;
40 static struct jcore_pit __percpu
*jcore_pit_percpu
;
42 static notrace u64
jcore_sched_clock_read(void)
44 u32 seclo
, nsec
, seclo0
;
45 __iomem
void *base
= jcore_pit_base
;
47 seclo
= readl(base
+ REG_SECLO
);
50 nsec
= readl(base
+ REG_NSEC
);
51 seclo
= readl(base
+ REG_SECLO
);
52 } while (seclo0
!= seclo
);
54 return seclo
* NSEC_PER_SEC
+ nsec
;
57 static u64
jcore_clocksource_read(struct clocksource
*cs
)
59 return jcore_sched_clock_read();
62 static int jcore_pit_disable(struct jcore_pit
*pit
)
64 writel(0, pit
->base
+ REG_PITEN
);
68 static int jcore_pit_set(unsigned long delta
, struct jcore_pit
*pit
)
70 jcore_pit_disable(pit
);
71 writel(delta
, pit
->base
+ REG_THROT
);
72 writel(pit
->enable_val
, pit
->base
+ REG_PITEN
);
76 static int jcore_pit_set_state_shutdown(struct clock_event_device
*ced
)
78 struct jcore_pit
*pit
= container_of(ced
, struct jcore_pit
, ced
);
80 return jcore_pit_disable(pit
);
83 static int jcore_pit_set_state_oneshot(struct clock_event_device
*ced
)
85 struct jcore_pit
*pit
= container_of(ced
, struct jcore_pit
, ced
);
87 return jcore_pit_disable(pit
);
90 static int jcore_pit_set_state_periodic(struct clock_event_device
*ced
)
92 struct jcore_pit
*pit
= container_of(ced
, struct jcore_pit
, ced
);
94 return jcore_pit_set(pit
->periodic_delta
, pit
);
97 static int jcore_pit_set_next_event(unsigned long delta
,
98 struct clock_event_device
*ced
)
100 struct jcore_pit
*pit
= container_of(ced
, struct jcore_pit
, ced
);
102 return jcore_pit_set(delta
, pit
);
105 static int jcore_pit_local_init(unsigned cpu
)
107 struct jcore_pit
*pit
= this_cpu_ptr(jcore_pit_percpu
);
108 unsigned buspd
, freq
;
110 pr_info("Local J-Core PIT init on cpu %u\n", cpu
);
112 buspd
= readl(pit
->base
+ REG_BUSPD
);
113 freq
= DIV_ROUND_CLOSEST(NSEC_PER_SEC
, buspd
);
114 pit
->periodic_delta
= DIV_ROUND_CLOSEST(NSEC_PER_SEC
, HZ
* buspd
);
116 clockevents_config_and_register(&pit
->ced
, freq
, 1, ULONG_MAX
);
121 static irqreturn_t
jcore_timer_interrupt(int irq
, void *dev_id
)
123 struct jcore_pit
*pit
= dev_id
;
125 if (clockevent_state_oneshot(&pit
->ced
))
126 jcore_pit_disable(pit
);
128 pit
->ced
.event_handler(&pit
->ced
);
133 static int __init
jcore_pit_init(struct device_node
*node
)
136 unsigned pit_irq
, cpu
;
138 u32 irqprio
, enable_val
;
140 jcore_pit_base
= of_iomap(node
, 0);
141 if (!jcore_pit_base
) {
142 pr_err("Error: Cannot map base address for J-Core PIT\n");
146 pit_irq
= irq_of_parse_and_map(node
, 0);
148 pr_err("Error: J-Core PIT has no IRQ\n");
152 pr_info("Initializing J-Core PIT at %p IRQ %d\n",
153 jcore_pit_base
, pit_irq
);
155 err
= clocksource_mmio_init(jcore_pit_base
, "jcore_pit_cs",
156 NSEC_PER_SEC
, 400, 32,
157 jcore_clocksource_read
);
159 pr_err("Error registering clocksource device: %d\n", err
);
163 sched_clock_register(jcore_sched_clock_read
, 32, NSEC_PER_SEC
);
165 jcore_pit_percpu
= alloc_percpu(struct jcore_pit
);
166 if (!jcore_pit_percpu
) {
167 pr_err("Failed to allocate memory for clock event device\n");
171 err
= request_percpu_irq(pit_irq
, jcore_timer_interrupt
,
172 "jcore_pit", jcore_pit_percpu
);
174 pr_err("pit irq request failed: %d\n", err
);
175 free_percpu(jcore_pit_percpu
);
180 * The J-Core PIT is not hard-wired to a particular IRQ, but
181 * integrated with the interrupt controller such that the IRQ it
182 * generates is programmable, as follows:
184 * The bit layout of the PIT enable register is:
186 * .....e..ppppiiiiiiii............
188 * where the .'s indicate unrelated/unused bits, e is enable,
189 * p is priority, and i is hard irq number.
191 * For the PIT included in AIC1 (obsolete but still in use),
192 * any hard irq (trap number) can be programmed via the 8
193 * iiiiiiii bits, and a priority (0-15) is programmable
194 * separately in the pppp bits.
196 * For the PIT included in AIC2 (current), the programming
197 * interface is equivalent modulo interrupt mapping. This is
198 * why a different compatible tag was not used. However only
199 * traps 64-127 (the ones actually intended to be used for
200 * interrupts, rather than syscalls/exceptions/etc.) can be
201 * programmed (the high 2 bits of i are ignored) and the
202 * priority pppp is <<2'd and or'd onto the irq number. This
203 * choice seems to have been made on the hardware engineering
204 * side under an assumption that preserving old AIC1 priority
205 * mappings was important. Future models will likely ignore
208 hwirq
= irq_get_irq_data(pit_irq
)->hwirq
;
209 irqprio
= (hwirq
>> 2) & PIT_PRIO_MASK
;
210 enable_val
= (1U << PIT_ENABLE_SHIFT
)
211 | (hwirq
<< PIT_IRQ_SHIFT
)
212 | (irqprio
<< PIT_PRIO_SHIFT
);
214 for_each_present_cpu(cpu
) {
215 struct jcore_pit
*pit
= per_cpu_ptr(jcore_pit_percpu
, cpu
);
217 pit
->base
= of_iomap(node
, cpu
);
219 pr_err("Unable to map PIT for cpu %u\n", cpu
);
223 pit
->ced
.name
= "jcore_pit";
224 pit
->ced
.features
= CLOCK_EVT_FEAT_PERIODIC
225 | CLOCK_EVT_FEAT_ONESHOT
226 | CLOCK_EVT_FEAT_PERCPU
;
227 pit
->ced
.cpumask
= cpumask_of(cpu
);
228 pit
->ced
.rating
= 400;
229 pit
->ced
.irq
= pit_irq
;
230 pit
->ced
.set_state_shutdown
= jcore_pit_set_state_shutdown
;
231 pit
->ced
.set_state_periodic
= jcore_pit_set_state_periodic
;
232 pit
->ced
.set_state_oneshot
= jcore_pit_set_state_oneshot
;
233 pit
->ced
.set_next_event
= jcore_pit_set_next_event
;
235 pit
->enable_val
= enable_val
;
238 cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING
,
239 "clockevents/jcore:starting",
240 jcore_pit_local_init
, NULL
);
245 TIMER_OF_DECLARE(jcore_pit
, "jcore,pit", jcore_pit_init
);