1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com> |
3 | */ |
4 | #ifndef _SJA1105_PTP_H |
5 | #define _SJA1105_PTP_H |
6 | |
7 | #include <linux/timer.h> |
8 | |
9 | #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) |
10 | |
11 | /* Timestamps are in units of 8 ns clock ticks (equivalent to |
12 | * a fixed 125 MHz clock). |
13 | */ |
14 | #define SJA1105_TICK_NS 8 |
15 | |
16 | static inline s64 ns_to_sja1105_ticks(s64 ns) |
17 | { |
18 | return ns / SJA1105_TICK_NS; |
19 | } |
20 | |
21 | static inline s64 sja1105_ticks_to_ns(s64 ticks) |
22 | { |
23 | return ticks * SJA1105_TICK_NS; |
24 | } |
25 | |
26 | /* Calculate the first base_time in the future that satisfies this |
27 | * relationship: |
28 | * |
29 | * future_base_time = base_time + N x cycle_time >= now, or |
30 | * |
31 | * now - base_time |
32 | * N >= --------------- |
33 | * cycle_time |
34 | * |
35 | * Because N is an integer, the ceiling value of the above "a / b" ratio |
36 | * is in fact precisely the floor value of "(a + b - 1) / b", which is |
37 | * easier to calculate only having integer division tools. |
38 | */ |
39 | static inline s64 future_base_time(s64 base_time, s64 cycle_time, s64 now) |
40 | { |
41 | s64 a, b, n; |
42 | |
43 | if (base_time >= now) |
44 | return base_time; |
45 | |
46 | a = now - base_time; |
47 | b = cycle_time; |
48 | n = div_s64(dividend: a + b - 1, divisor: b); |
49 | |
50 | return base_time + n * cycle_time; |
51 | } |
52 | |
53 | /* This is not a preprocessor macro because the "ns" argument may or may not be |
54 | * s64 at caller side. This ensures it is properly type-cast before div_s64. |
55 | */ |
56 | static inline s64 ns_to_sja1105_delta(s64 ns) |
57 | { |
58 | return div_s64(dividend: ns, divisor: 200); |
59 | } |
60 | |
61 | static inline s64 sja1105_delta_to_ns(s64 delta) |
62 | { |
63 | return delta * 200; |
64 | } |
65 | |
66 | struct sja1105_ptp_cmd { |
67 | u64 startptpcp; /* start toggling PTP_CLK pin */ |
68 | u64 stopptpcp; /* stop toggling PTP_CLK pin */ |
69 | u64 ptpstrtsch; /* start schedule */ |
70 | u64 ptpstopsch; /* stop schedule */ |
71 | u64 resptp; /* reset */ |
72 | u64 corrclk4ts; /* use the corrected clock for timestamps */ |
73 | u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ |
74 | }; |
75 | |
76 | struct sja1105_ptp_data { |
77 | struct timer_list extts_timer; |
78 | /* Used only on SJA1105 to reconstruct partial timestamps */ |
79 | struct sk_buff_head skb_rxtstamp_queue; |
80 | /* Used on SJA1110 where meta frames are generated only for |
81 | * 2-step TX timestamps |
82 | */ |
83 | struct sk_buff_head skb_txtstamp_queue; |
84 | struct ptp_clock_info caps; |
85 | struct ptp_clock *clock; |
86 | struct sja1105_ptp_cmd cmd; |
87 | /* Serializes all operations on the PTP hardware clock */ |
88 | struct mutex lock; |
89 | bool extts_enabled; |
90 | u64 ptpsyncts; |
91 | }; |
92 | |
93 | int sja1105_ptp_clock_register(struct dsa_switch *ds); |
94 | |
95 | void sja1105_ptp_clock_unregister(struct dsa_switch *ds); |
96 | |
97 | void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, |
98 | enum packing_op op); |
99 | |
100 | void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, |
101 | enum packing_op op); |
102 | |
103 | int sja1105_get_ts_info(struct dsa_switch *ds, int port, |
104 | struct ethtool_ts_info *ts); |
105 | |
106 | void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, |
107 | struct sk_buff *clone); |
108 | |
109 | bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, |
110 | struct sk_buff *skb, unsigned int type); |
111 | |
112 | void sja1105_port_txtstamp(struct dsa_switch *ds, int port, |
113 | struct sk_buff *skb); |
114 | |
115 | int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); |
116 | |
117 | int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); |
118 | |
119 | int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, |
120 | struct ptp_system_timestamp *sts); |
121 | |
122 | int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, |
123 | struct ptp_system_timestamp *ptp_sts); |
124 | |
125 | int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta); |
126 | |
127 | int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd, |
128 | sja1105_spi_rw_mode_t rw); |
129 | |
130 | bool sja1105_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); |
131 | bool sja1110_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); |
132 | void sja1110_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); |
133 | |
134 | void sja1110_process_meta_tstamp(struct dsa_switch *ds, int port, u8 ts_id, |
135 | enum sja1110_meta_tstamp dir, u64 tstamp); |
136 | |
137 | #else |
138 | |
139 | struct sja1105_ptp_cmd; |
140 | |
141 | /* Structures cannot be empty in C. Bah! |
142 | * Keep the mutex as the only element, which is a bit more difficult to |
143 | * refactor out of sja1105_main.c anyway. |
144 | */ |
145 | struct sja1105_ptp_data { |
146 | struct mutex lock; |
147 | }; |
148 | |
149 | static inline int sja1105_ptp_clock_register(struct dsa_switch *ds) |
150 | { |
151 | return 0; |
152 | } |
153 | |
154 | static inline void sja1105_ptp_clock_unregister(struct dsa_switch *ds) { } |
155 | |
156 | static inline void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, |
157 | struct sk_buff *clone) |
158 | { |
159 | } |
160 | |
161 | static inline int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, |
162 | struct ptp_system_timestamp *sts) |
163 | { |
164 | return 0; |
165 | } |
166 | |
167 | static inline int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, |
168 | struct ptp_system_timestamp *ptp_sts) |
169 | { |
170 | return 0; |
171 | } |
172 | |
173 | static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) |
174 | { |
175 | return 0; |
176 | } |
177 | |
178 | static inline int sja1105_ptp_commit(struct dsa_switch *ds, |
179 | struct sja1105_ptp_cmd *cmd, |
180 | sja1105_spi_rw_mode_t rw) |
181 | { |
182 | return 0; |
183 | } |
184 | |
185 | #define sja1105et_ptp_cmd_packing NULL |
186 | |
187 | #define sja1105pqrs_ptp_cmd_packing NULL |
188 | |
189 | #define sja1105_get_ts_info NULL |
190 | |
191 | #define sja1105_port_rxtstamp NULL |
192 | |
193 | #define sja1105_port_txtstamp NULL |
194 | |
195 | #define sja1105_hwtstamp_get NULL |
196 | |
197 | #define sja1105_hwtstamp_set NULL |
198 | |
199 | #define sja1105_rxtstamp NULL |
200 | #define sja1110_rxtstamp NULL |
201 | #define sja1110_txtstamp NULL |
202 | |
203 | #define sja1110_process_meta_tstamp NULL |
204 | |
205 | #endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) */ |
206 | |
207 | #endif /* _SJA1105_PTP_H */ |
208 | |