1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /* linux/include/linux/clockchips.h
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This file contains the structure definitions for clockchips.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * If you are not a clockchip, or the time of day code, you should
7*4882a593Smuzhiyun * not be including this file!
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #ifndef _LINUX_CLOCKCHIPS_H
10*4882a593Smuzhiyun #define _LINUX_CLOCKCHIPS_H
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #ifdef CONFIG_GENERIC_CLOCKEVENTS
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun # include <linux/clocksource.h>
15*4882a593Smuzhiyun # include <linux/cpumask.h>
16*4882a593Smuzhiyun # include <linux/ktime.h>
17*4882a593Smuzhiyun # include <linux/notifier.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun struct clock_event_device;
20*4882a593Smuzhiyun struct module;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * Possible states of a clock event device.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * DETACHED: Device is not used by clockevents core. Initial state or can be
26*4882a593Smuzhiyun * reached from SHUTDOWN.
27*4882a593Smuzhiyun * SHUTDOWN: Device is powered-off. Can be reached from PERIODIC or ONESHOT.
28*4882a593Smuzhiyun * PERIODIC: Device is programmed to generate events periodically. Can be
29*4882a593Smuzhiyun * reached from DETACHED or SHUTDOWN.
30*4882a593Smuzhiyun * ONESHOT: Device is programmed to generate event only once. Can be reached
31*4882a593Smuzhiyun * from DETACHED or SHUTDOWN.
32*4882a593Smuzhiyun * ONESHOT_STOPPED: Device was programmed in ONESHOT mode and is temporarily
33*4882a593Smuzhiyun * stopped.
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun enum clock_event_state {
36*4882a593Smuzhiyun CLOCK_EVT_STATE_DETACHED,
37*4882a593Smuzhiyun CLOCK_EVT_STATE_SHUTDOWN,
38*4882a593Smuzhiyun CLOCK_EVT_STATE_PERIODIC,
39*4882a593Smuzhiyun CLOCK_EVT_STATE_ONESHOT,
40*4882a593Smuzhiyun CLOCK_EVT_STATE_ONESHOT_STOPPED,
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun * Clock event features
45*4882a593Smuzhiyun */
46*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_PERIODIC 0x000001
47*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_ONESHOT 0x000002
48*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_KTIME 0x000004
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun * x86(64) specific (mis)features:
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * - Clockevent source stops in C3 State and needs broadcast support.
54*4882a593Smuzhiyun * - Local APIC timer is used as a dummy device.
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_C3STOP 0x000008
57*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_DUMMY 0x000010
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * Core shall set the interrupt affinity dynamically in broadcast mode
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_DYNIRQ 0x000020
63*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_PERCPU 0x000040
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * Clockevent device is based on a hrtimer for broadcast
67*4882a593Smuzhiyun */
68*4882a593Smuzhiyun # define CLOCK_EVT_FEAT_HRTIMER 0x000080
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /**
71*4882a593Smuzhiyun * struct clock_event_device - clock event device descriptor
72*4882a593Smuzhiyun * @event_handler: Assigned by the framework to be called by the low
73*4882a593Smuzhiyun * level handler of the event source
74*4882a593Smuzhiyun * @set_next_event: set next event function using a clocksource delta
75*4882a593Smuzhiyun * @set_next_ktime: set next event function using a direct ktime value
76*4882a593Smuzhiyun * @next_event: local storage for the next event in oneshot mode
77*4882a593Smuzhiyun * @max_delta_ns: maximum delta value in ns
78*4882a593Smuzhiyun * @min_delta_ns: minimum delta value in ns
79*4882a593Smuzhiyun * @mult: nanosecond to cycles multiplier
80*4882a593Smuzhiyun * @shift: nanoseconds to cycles divisor (power of two)
81*4882a593Smuzhiyun * @state_use_accessors:current state of the device, assigned by the core code
82*4882a593Smuzhiyun * @features: features
83*4882a593Smuzhiyun * @retries: number of forced programming retries
84*4882a593Smuzhiyun * @set_state_periodic: switch state to periodic
85*4882a593Smuzhiyun * @set_state_oneshot: switch state to oneshot
86*4882a593Smuzhiyun * @set_state_oneshot_stopped: switch state to oneshot_stopped
87*4882a593Smuzhiyun * @set_state_shutdown: switch state to shutdown
88*4882a593Smuzhiyun * @tick_resume: resume clkevt device
89*4882a593Smuzhiyun * @broadcast: function to broadcast events
90*4882a593Smuzhiyun * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration
91*4882a593Smuzhiyun * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration
92*4882a593Smuzhiyun * @name: ptr to clock event name
93*4882a593Smuzhiyun * @rating: variable to rate clock event devices
94*4882a593Smuzhiyun * @irq: IRQ number (only for non CPU local devices)
95*4882a593Smuzhiyun * @bound_on: Bound on CPU
96*4882a593Smuzhiyun * @cpumask: cpumask to indicate for which CPUs this device works
97*4882a593Smuzhiyun * @list: list head for the management code
98*4882a593Smuzhiyun * @owner: module reference
99*4882a593Smuzhiyun */
100*4882a593Smuzhiyun struct clock_event_device {
101*4882a593Smuzhiyun void (*event_handler)(struct clock_event_device *);
102*4882a593Smuzhiyun int (*set_next_event)(unsigned long evt, struct clock_event_device *);
103*4882a593Smuzhiyun int (*set_next_ktime)(ktime_t expires, struct clock_event_device *);
104*4882a593Smuzhiyun ktime_t next_event;
105*4882a593Smuzhiyun u64 max_delta_ns;
106*4882a593Smuzhiyun u64 min_delta_ns;
107*4882a593Smuzhiyun u32 mult;
108*4882a593Smuzhiyun u32 shift;
109*4882a593Smuzhiyun enum clock_event_state state_use_accessors;
110*4882a593Smuzhiyun unsigned int features;
111*4882a593Smuzhiyun unsigned long retries;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun int (*set_state_periodic)(struct clock_event_device *);
114*4882a593Smuzhiyun int (*set_state_oneshot)(struct clock_event_device *);
115*4882a593Smuzhiyun int (*set_state_oneshot_stopped)(struct clock_event_device *);
116*4882a593Smuzhiyun int (*set_state_shutdown)(struct clock_event_device *);
117*4882a593Smuzhiyun int (*tick_resume)(struct clock_event_device *);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun void (*broadcast)(const struct cpumask *mask);
120*4882a593Smuzhiyun void (*suspend)(struct clock_event_device *);
121*4882a593Smuzhiyun void (*resume)(struct clock_event_device *);
122*4882a593Smuzhiyun unsigned long min_delta_ticks;
123*4882a593Smuzhiyun unsigned long max_delta_ticks;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun const char *name;
126*4882a593Smuzhiyun int rating;
127*4882a593Smuzhiyun int irq;
128*4882a593Smuzhiyun int bound_on;
129*4882a593Smuzhiyun const struct cpumask *cpumask;
130*4882a593Smuzhiyun struct list_head list;
131*4882a593Smuzhiyun struct module *owner;
132*4882a593Smuzhiyun } ____cacheline_aligned;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Helpers to verify state of a clockevent device */
clockevent_state_detached(struct clock_event_device * dev)135*4882a593Smuzhiyun static inline bool clockevent_state_detached(struct clock_event_device *dev)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun return dev->state_use_accessors == CLOCK_EVT_STATE_DETACHED;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
clockevent_state_shutdown(struct clock_event_device * dev)140*4882a593Smuzhiyun static inline bool clockevent_state_shutdown(struct clock_event_device *dev)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun return dev->state_use_accessors == CLOCK_EVT_STATE_SHUTDOWN;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
clockevent_state_periodic(struct clock_event_device * dev)145*4882a593Smuzhiyun static inline bool clockevent_state_periodic(struct clock_event_device *dev)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun return dev->state_use_accessors == CLOCK_EVT_STATE_PERIODIC;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
clockevent_state_oneshot(struct clock_event_device * dev)150*4882a593Smuzhiyun static inline bool clockevent_state_oneshot(struct clock_event_device *dev)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
clockevent_state_oneshot_stopped(struct clock_event_device * dev)155*4882a593Smuzhiyun static inline bool clockevent_state_oneshot_stopped(struct clock_event_device *dev)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT_STOPPED;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun * Calculate a multiplication factor for scaled math, which is used to convert
162*4882a593Smuzhiyun * nanoseconds based values to clock ticks:
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * clock_ticks = (nanoseconds * factor) >> shift.
165*4882a593Smuzhiyun *
166*4882a593Smuzhiyun * div_sc is the rearranged equation to calculate a factor from a given clock
167*4882a593Smuzhiyun * ticks / nanoseconds ratio:
168*4882a593Smuzhiyun *
169*4882a593Smuzhiyun * factor = (clock_ticks << shift) / nanoseconds
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun static inline unsigned long
div_sc(unsigned long ticks,unsigned long nsec,int shift)172*4882a593Smuzhiyun div_sc(unsigned long ticks, unsigned long nsec, int shift)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun u64 tmp = ((u64)ticks) << shift;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun do_div(tmp, nsec);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return (unsigned long) tmp;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* Clock event layer functions */
182*4882a593Smuzhiyun extern u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt);
183*4882a593Smuzhiyun extern void clockevents_register_device(struct clock_event_device *dev);
184*4882a593Smuzhiyun extern int clockevents_unbind_device(struct clock_event_device *ced, int cpu);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun extern void clockevents_config_and_register(struct clock_event_device *dev,
187*4882a593Smuzhiyun u32 freq, unsigned long min_delta,
188*4882a593Smuzhiyun unsigned long max_delta);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun extern int clockevents_update_freq(struct clock_event_device *ce, u32 freq);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun static inline void
clockevents_calc_mult_shift(struct clock_event_device * ce,u32 freq,u32 maxsec)193*4882a593Smuzhiyun clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 maxsec)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun return clocks_calc_mult_shift(&ce->mult, &ce->shift, NSEC_PER_SEC, freq, maxsec);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun extern void clockevents_suspend(void);
199*4882a593Smuzhiyun extern void clockevents_resume(void);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
202*4882a593Smuzhiyun # ifdef CONFIG_ARCH_HAS_TICK_BROADCAST
203*4882a593Smuzhiyun extern void tick_broadcast(const struct cpumask *mask);
204*4882a593Smuzhiyun # else
205*4882a593Smuzhiyun # define tick_broadcast NULL
206*4882a593Smuzhiyun # endif
207*4882a593Smuzhiyun extern int tick_receive_broadcast(void);
208*4882a593Smuzhiyun # endif
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun # if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
211*4882a593Smuzhiyun extern void tick_setup_hrtimer_broadcast(void);
212*4882a593Smuzhiyun extern int tick_check_broadcast_expired(void);
213*4882a593Smuzhiyun # else
tick_check_broadcast_expired(void)214*4882a593Smuzhiyun static inline int tick_check_broadcast_expired(void) { return 0; }
tick_setup_hrtimer_broadcast(void)215*4882a593Smuzhiyun static inline void tick_setup_hrtimer_broadcast(void) { }
216*4882a593Smuzhiyun # endif
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun #else /* !CONFIG_GENERIC_CLOCKEVENTS: */
219*4882a593Smuzhiyun
clockevents_suspend(void)220*4882a593Smuzhiyun static inline void clockevents_suspend(void) { }
clockevents_resume(void)221*4882a593Smuzhiyun static inline void clockevents_resume(void) { }
tick_check_broadcast_expired(void)222*4882a593Smuzhiyun static inline int tick_check_broadcast_expired(void) { return 0; }
tick_setup_hrtimer_broadcast(void)223*4882a593Smuzhiyun static inline void tick_setup_hrtimer_broadcast(void) { }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun #endif /* _LINUX_CLOCKCHIPS_H */
228