1 | /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ |
2 | /* |
3 | * DSA driver for: |
4 | * Hirschmann Hellcreek TSN switch. |
5 | * |
6 | * Copyright (C) 2019-2021 Linutronix GmbH |
7 | * Author Kurt Kanzenbach <kurt@linutronix.de> |
8 | */ |
9 | |
10 | #ifndef _HELLCREEK_H_ |
11 | #define _HELLCREEK_H_ |
12 | |
13 | #include <linux/bitmap.h> |
14 | #include <linux/bitops.h> |
15 | #include <linux/device.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/mutex.h> |
18 | #include <linux/workqueue.h> |
19 | #include <linux/leds.h> |
20 | #include <linux/platform_data/hirschmann-hellcreek.h> |
21 | #include <linux/ptp_clock_kernel.h> |
22 | #include <linux/timecounter.h> |
23 | #include <net/dsa.h> |
24 | #include <net/pkt_sched.h> |
25 | |
26 | /* Ports: |
27 | * - 0: CPU |
28 | * - 1: Tunnel |
29 | * - 2: TSN front port 1 |
30 | * - 3: TSN front port 2 |
31 | * - ... |
32 | */ |
33 | #define CPU_PORT 0 |
34 | #define TUNNEL_PORT 1 |
35 | |
36 | #define HELLCREEK_VLAN_NO_MEMBER 0x0 |
37 | #define HELLCREEK_VLAN_UNTAGGED_MEMBER 0x1 |
38 | #define HELLCREEK_VLAN_TAGGED_MEMBER 0x3 |
39 | #define HELLCREEK_NUM_EGRESS_QUEUES 8 |
40 | #define HELLCREEK_DEFAULT_MAX_SDU 1536 |
41 | |
42 | /* Register definitions */ |
43 | #define HR_MODID_C (0 * 2) |
44 | #define HR_REL_L_C (1 * 2) |
45 | #define HR_REL_H_C (2 * 2) |
46 | #define HR_BLD_L_C (3 * 2) |
47 | #define HR_BLD_H_C (4 * 2) |
48 | #define HR_CTRL_C (5 * 2) |
49 | #define HR_CTRL_C_READY BIT(14) |
50 | #define HR_CTRL_C_TRANSITION BIT(13) |
51 | #define HR_CTRL_C_ENABLE BIT(0) |
52 | |
53 | #define HR_PSEL (0xa6 * 2) |
54 | #define HR_PSEL_PTWSEL_SHIFT 4 |
55 | #define HR_PSEL_PTWSEL_MASK GENMASK(5, 4) |
56 | #define HR_PSEL_PRTCWSEL_SHIFT 0 |
57 | #define HR_PSEL_PRTCWSEL_MASK GENMASK(2, 0) |
58 | |
59 | #define HR_PTCFG (0xa7 * 2) |
60 | #define HR_PTCFG_MLIMIT_EN BIT(13) |
61 | #define HR_PTCFG_UMC_FLT BIT(10) |
62 | #define HR_PTCFG_UUC_FLT BIT(9) |
63 | #define HR_PTCFG_UNTRUST BIT(8) |
64 | #define HR_PTCFG_TAG_REQUIRED BIT(7) |
65 | #define HR_PTCFG_PPRIO_SHIFT 4 |
66 | #define HR_PTCFG_PPRIO_MASK GENMASK(6, 4) |
67 | #define HR_PTCFG_INGRESSFLT BIT(3) |
68 | #define HR_PTCFG_BLOCKED BIT(2) |
69 | #define HR_PTCFG_LEARNING_EN BIT(1) |
70 | #define HR_PTCFG_ADMIN_EN BIT(0) |
71 | |
72 | #define HR_PRTCCFG (0xa8 * 2) |
73 | #define HR_PRTCCFG_PCP_TC_MAP_SHIFT 0 |
74 | #define HR_PRTCCFG_PCP_TC_MAP_MASK GENMASK(2, 0) |
75 | |
76 | #define HR_PTPRTCCFG (0xa9 * 2) |
77 | #define HR_PTPRTCCFG_SET_QTRACK BIT(15) |
78 | #define HR_PTPRTCCFG_REJECT BIT(14) |
79 | #define HR_PTPRTCCFG_MAXSDU_SHIFT 0 |
80 | #define HR_PTPRTCCFG_MAXSDU_MASK GENMASK(10, 0) |
81 | |
82 | #define HR_CSEL (0x8d * 2) |
83 | #define HR_CSEL_SHIFT 0 |
84 | #define HR_CSEL_MASK GENMASK(7, 0) |
85 | #define HR_CRDL (0x8e * 2) |
86 | #define HR_CRDH (0x8f * 2) |
87 | |
88 | #define HR_SWTRC_CFG (0x90 * 2) |
89 | #define HR_SWTRC0 (0x91 * 2) |
90 | #define HR_SWTRC1 (0x92 * 2) |
91 | #define HR_PFREE (0x93 * 2) |
92 | #define HR_MFREE (0x94 * 2) |
93 | |
94 | #define HR_FDBAGE (0x97 * 2) |
95 | #define HR_FDBMAX (0x98 * 2) |
96 | #define HR_FDBRDL (0x99 * 2) |
97 | #define HR_FDBRDM (0x9a * 2) |
98 | #define HR_FDBRDH (0x9b * 2) |
99 | |
100 | #define HR_FDBMDRD (0x9c * 2) |
101 | #define HR_FDBMDRD_PORTMASK_SHIFT 0 |
102 | #define HR_FDBMDRD_PORTMASK_MASK GENMASK(3, 0) |
103 | #define HR_FDBMDRD_AGE_SHIFT 4 |
104 | #define HR_FDBMDRD_AGE_MASK GENMASK(7, 4) |
105 | #define HR_FDBMDRD_OBT BIT(8) |
106 | #define HR_FDBMDRD_PASS_BLOCKED BIT(9) |
107 | #define HR_FDBMDRD_STATIC BIT(11) |
108 | #define HR_FDBMDRD_REPRIO_TC_SHIFT 12 |
109 | #define HR_FDBMDRD_REPRIO_TC_MASK GENMASK(14, 12) |
110 | #define HR_FDBMDRD_REPRIO_EN BIT(15) |
111 | |
112 | #define HR_FDBWDL (0x9d * 2) |
113 | #define HR_FDBWDM (0x9e * 2) |
114 | #define HR_FDBWDH (0x9f * 2) |
115 | #define HR_FDBWRM0 (0xa0 * 2) |
116 | #define HR_FDBWRM0_PORTMASK_SHIFT 0 |
117 | #define HR_FDBWRM0_PORTMASK_MASK GENMASK(3, 0) |
118 | #define HR_FDBWRM0_OBT BIT(8) |
119 | #define HR_FDBWRM0_PASS_BLOCKED BIT(9) |
120 | #define HR_FDBWRM0_REPRIO_TC_SHIFT 12 |
121 | #define HR_FDBWRM0_REPRIO_TC_MASK GENMASK(14, 12) |
122 | #define HR_FDBWRM0_REPRIO_EN BIT(15) |
123 | #define HR_FDBWRM1 (0xa1 * 2) |
124 | |
125 | #define HR_FDBWRCMD (0xa2 * 2) |
126 | #define HR_FDBWRCMD_FDBDEL BIT(9) |
127 | |
128 | #define HR_SWCFG (0xa3 * 2) |
129 | #define HR_SWCFG_GM_STATEMD BIT(15) |
130 | #define HR_SWCFG_LAS_MODE_SHIFT 12 |
131 | #define HR_SWCFG_LAS_MODE_MASK GENMASK(13, 12) |
132 | #define HR_SWCFG_LAS_OFF (0x00) |
133 | #define HR_SWCFG_LAS_ON (0x01) |
134 | #define HR_SWCFG_LAS_STATIC (0x10) |
135 | #define HR_SWCFG_CT_EN BIT(11) |
136 | #define HR_SWCFG_VLAN_UNAWARE BIT(10) |
137 | #define HR_SWCFG_ALWAYS_OBT BIT(9) |
138 | #define HR_SWCFG_FDBAGE_EN BIT(5) |
139 | #define HR_SWCFG_FDBLRN_EN BIT(4) |
140 | |
141 | #define HR_SWSTAT (0xa4 * 2) |
142 | #define HR_SWSTAT_FAIL BIT(4) |
143 | #define HR_SWSTAT_BUSY BIT(0) |
144 | |
145 | #define HR_SWCMD (0xa5 * 2) |
146 | #define HW_SWCMD_FLUSH BIT(0) |
147 | |
148 | #define HR_VIDCFG (0xaa * 2) |
149 | #define HR_VIDCFG_VID_SHIFT 0 |
150 | #define HR_VIDCFG_VID_MASK GENMASK(11, 0) |
151 | #define HR_VIDCFG_PVID BIT(12) |
152 | |
153 | #define HR_VIDMBRCFG (0xab * 2) |
154 | #define HR_VIDMBRCFG_P0MBR_SHIFT 0 |
155 | #define HR_VIDMBRCFG_P0MBR_MASK GENMASK(1, 0) |
156 | #define HR_VIDMBRCFG_P1MBR_SHIFT 2 |
157 | #define HR_VIDMBRCFG_P1MBR_MASK GENMASK(3, 2) |
158 | #define HR_VIDMBRCFG_P2MBR_SHIFT 4 |
159 | #define HR_VIDMBRCFG_P2MBR_MASK GENMASK(5, 4) |
160 | #define HR_VIDMBRCFG_P3MBR_SHIFT 6 |
161 | #define HR_VIDMBRCFG_P3MBR_MASK GENMASK(7, 6) |
162 | |
163 | #define HR_FEABITS0 (0xac * 2) |
164 | #define HR_FEABITS0_FDBBINS_SHIFT 4 |
165 | #define HR_FEABITS0_FDBBINS_MASK GENMASK(7, 4) |
166 | #define HR_FEABITS0_PCNT_SHIFT 8 |
167 | #define HR_FEABITS0_PCNT_MASK GENMASK(11, 8) |
168 | #define HR_FEABITS0_MCNT_SHIFT 12 |
169 | #define HR_FEABITS0_MCNT_MASK GENMASK(15, 12) |
170 | |
171 | #define TR_QTRACK (0xb1 * 2) |
172 | #define TR_TGDVER (0xb3 * 2) |
173 | #define TR_TGDVER_REV_MIN_MASK GENMASK(7, 0) |
174 | #define TR_TGDVER_REV_MIN_SHIFT 0 |
175 | #define TR_TGDVER_REV_MAJ_MASK GENMASK(15, 8) |
176 | #define TR_TGDVER_REV_MAJ_SHIFT 8 |
177 | #define TR_TGDSEL (0xb4 * 2) |
178 | #define TR_TGDSEL_TDGSEL_MASK GENMASK(1, 0) |
179 | #define TR_TGDSEL_TDGSEL_SHIFT 0 |
180 | #define TR_TGDCTRL (0xb5 * 2) |
181 | #define TR_TGDCTRL_GATE_EN BIT(0) |
182 | #define TR_TGDCTRL_CYC_SNAP BIT(4) |
183 | #define TR_TGDCTRL_SNAP_EST BIT(5) |
184 | #define TR_TGDCTRL_ADMINGATESTATES_MASK GENMASK(15, 8) |
185 | #define TR_TGDCTRL_ADMINGATESTATES_SHIFT 8 |
186 | #define TR_TGDSTAT0 (0xb6 * 2) |
187 | #define TR_TGDSTAT1 (0xb7 * 2) |
188 | #define TR_ESTWRL (0xb8 * 2) |
189 | #define TR_ESTWRH (0xb9 * 2) |
190 | #define TR_ESTCMD (0xba * 2) |
191 | #define TR_ESTCMD_ESTSEC_MASK GENMASK(2, 0) |
192 | #define TR_ESTCMD_ESTSEC_SHIFT 0 |
193 | #define TR_ESTCMD_ESTARM BIT(4) |
194 | #define TR_ESTCMD_ESTSWCFG BIT(5) |
195 | #define TR_EETWRL (0xbb * 2) |
196 | #define TR_EETWRH (0xbc * 2) |
197 | #define TR_EETCMD (0xbd * 2) |
198 | #define TR_EETCMD_EETSEC_MASK GEMASK(2, 0) |
199 | #define TR_EETCMD_EETSEC_SHIFT 0 |
200 | #define TR_EETCMD_EETARM BIT(4) |
201 | #define TR_CTWRL (0xbe * 2) |
202 | #define TR_CTWRH (0xbf * 2) |
203 | #define TR_LCNSL (0xc1 * 2) |
204 | #define TR_LCNSH (0xc2 * 2) |
205 | #define TR_LCS (0xc3 * 2) |
206 | #define TR_GCLDAT (0xc4 * 2) |
207 | #define TR_GCLDAT_GCLWRGATES_MASK GENMASK(7, 0) |
208 | #define TR_GCLDAT_GCLWRGATES_SHIFT 0 |
209 | #define TR_GCLDAT_GCLWRLAST BIT(8) |
210 | #define TR_GCLDAT_GCLOVRI BIT(9) |
211 | #define TR_GCLTIL (0xc5 * 2) |
212 | #define TR_GCLTIH (0xc6 * 2) |
213 | #define TR_GCLCMD (0xc7 * 2) |
214 | #define TR_GCLCMD_GCLWRADR_MASK GENMASK(7, 0) |
215 | #define TR_GCLCMD_GCLWRADR_SHIFT 0 |
216 | #define TR_GCLCMD_INIT_GATE_STATES_MASK GENMASK(15, 8) |
217 | #define TR_GCLCMD_INIT_GATE_STATES_SHIFT 8 |
218 | |
219 | struct hellcreek_counter { |
220 | u8 offset; |
221 | const char *name; |
222 | }; |
223 | |
224 | struct hellcreek; |
225 | |
226 | /* State flags for hellcreek_port_hwtstamp::state */ |
227 | enum { |
228 | HELLCREEK_HWTSTAMP_ENABLED, |
229 | HELLCREEK_HWTSTAMP_TX_IN_PROGRESS, |
230 | }; |
231 | |
232 | /* A structure to hold hardware timestamping information per port */ |
233 | struct hellcreek_port_hwtstamp { |
234 | /* Timestamping state */ |
235 | unsigned long state; |
236 | |
237 | /* Resources for receive timestamping */ |
238 | struct sk_buff_head rx_queue; /* For synchronization messages */ |
239 | |
240 | /* Resources for transmit timestamping */ |
241 | unsigned long tx_tstamp_start; |
242 | struct sk_buff *tx_skb; |
243 | |
244 | /* Current timestamp configuration */ |
245 | struct hwtstamp_config tstamp_config; |
246 | }; |
247 | |
248 | struct hellcreek_port { |
249 | struct hellcreek *hellcreek; |
250 | unsigned long *vlan_dev_bitmap; |
251 | int port; |
252 | u16 ptcfg; /* ptcfg shadow */ |
253 | u64 *counter_values; |
254 | |
255 | /* Per-port timestamping resources */ |
256 | struct hellcreek_port_hwtstamp port_hwtstamp; |
257 | |
258 | /* Per-port Qbv schedule information */ |
259 | struct tc_taprio_qopt_offload *current_schedule; |
260 | struct delayed_work schedule_work; |
261 | }; |
262 | |
263 | struct hellcreek_fdb_entry { |
264 | size_t idx; |
265 | unsigned char mac[ETH_ALEN]; |
266 | u8 portmask; |
267 | u8 age; |
268 | u8 is_obt; |
269 | u8 pass_blocked; |
270 | u8 is_static; |
271 | u8 reprio_tc; |
272 | u8 reprio_en; |
273 | }; |
274 | |
275 | struct hellcreek { |
276 | const struct hellcreek_platform_data *pdata; |
277 | struct device *dev; |
278 | struct dsa_switch *ds; |
279 | struct ptp_clock *ptp_clock; |
280 | struct ptp_clock_info ptp_clock_info; |
281 | struct hellcreek_port *ports; |
282 | struct delayed_work overflow_work; |
283 | struct led_classdev led_is_gm; |
284 | struct led_classdev led_sync_good; |
285 | struct mutex reg_lock; /* Switch IP register lock */ |
286 | struct mutex vlan_lock; /* VLAN bitmaps lock */ |
287 | struct mutex ptp_lock; /* PTP IP register lock */ |
288 | struct devlink_region *vlan_region; |
289 | struct devlink_region *fdb_region; |
290 | void __iomem *base; |
291 | void __iomem *ptp_base; |
292 | u16 swcfg; /* swcfg shadow */ |
293 | u8 *vidmbrcfg; /* vidmbrcfg shadow */ |
294 | u64 seconds; /* PTP seconds */ |
295 | u64 last_ts; /* Used for overflow detection */ |
296 | u16 status_out; /* ptp.status_out shadow */ |
297 | size_t fdb_entries; |
298 | }; |
299 | |
300 | /* A Qbv schedule can only started up to 8 seconds in the future. If the delta |
301 | * between the base time and the current ptp time is larger than 8 seconds, then |
302 | * use periodic work to check for the schedule to be started. The delayed work |
303 | * cannot be armed directly to $base_time - 8 + X, because for large deltas the |
304 | * PTP frequency matters. |
305 | */ |
306 | #define HELLCREEK_SCHEDULE_PERIOD (2 * HZ) |
307 | #define dw_to_hellcreek_port(dw) \ |
308 | container_of(dw, struct hellcreek_port, schedule_work) |
309 | |
310 | /* Devlink resources */ |
311 | enum hellcreek_devlink_resource_id { |
312 | HELLCREEK_DEVLINK_PARAM_ID_VLAN_TABLE, |
313 | HELLCREEK_DEVLINK_PARAM_ID_FDB_TABLE, |
314 | }; |
315 | |
316 | struct hellcreek_devlink_vlan_entry { |
317 | u16 vid; |
318 | u16 member; |
319 | }; |
320 | |
321 | #endif /* _HELLCREEK_H_ */ |
322 | |