Commit | Line | Data |
---|---|---|
a556c76a AB |
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* | |
3 | * Microsemi Ocelot Switch driver | |
4 | * | |
5 | * Copyright (c) 2017 Microsemi Corporation | |
6 | */ | |
40d3f295 | 7 | #include <linux/dsa/ocelot.h> |
a556c76a AB |
8 | #include <linux/interrupt.h> |
9 | #include <linux/module.h> | |
71e32a20 | 10 | #include <linux/of_net.h> |
a556c76a | 11 | #include <linux/netdevice.h> |
e6e12df6 | 12 | #include <linux/phylink.h> |
a556c76a AB |
13 | #include <linux/of_mdio.h> |
14 | #include <linux/of_platform.h> | |
19aedfbe | 15 | #include <linux/mfd/syscon.h> |
a556c76a | 16 | #include <linux/skbuff.h> |
0e332c85 | 17 | #include <net/switchdev.h> |
a556c76a | 18 | |
e0632940 | 19 | #include <soc/mscc/ocelot_vcap.h> |
d9feb904 | 20 | #include <soc/mscc/ocelot_hsio.h> |
32ecd22b | 21 | #include <soc/mscc/vsc7514_regs.h> |
753a026c | 22 | #include "ocelot_fdma.h" |
a556c76a AB |
23 | #include "ocelot.h" |
24 | ||
77043c37 XY |
25 | #define VSC7514_VCAP_POLICER_BASE 128 |
26 | #define VSC7514_VCAP_POLICER_MAX 191 | |
27 | ||
91c724cf | 28 | static const u32 *ocelot_regmap[TARGET_MAX] = { |
32ecd22b CF |
29 | [ANA] = vsc7514_ana_regmap, |
30 | [QS] = vsc7514_qs_regmap, | |
31 | [QSYS] = vsc7514_qsys_regmap, | |
32 | [REW] = vsc7514_rew_regmap, | |
33 | [SYS] = vsc7514_sys_regmap, | |
34 | [S0] = vsc7514_vcap_regmap, | |
35 | [S1] = vsc7514_vcap_regmap, | |
36 | [S2] = vsc7514_vcap_regmap, | |
37 | [PTP] = vsc7514_ptp_regmap, | |
38 | [DEV_GMII] = vsc7514_dev_gmii_regmap, | |
d9feb904 VO |
39 | }; |
40 | ||
2789658f | 41 | static const struct reg_field ocelot_regfields[REGFIELD_MAX] = { |
d9feb904 VO |
42 | [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11), |
43 | [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10), | |
44 | [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27), | |
45 | [ANA_ANEVENTS_ACLKILL] = REG_FIELD(ANA_ANEVENTS, 26, 26), | |
46 | [ANA_ANEVENTS_ACLUSED] = REG_FIELD(ANA_ANEVENTS, 25, 25), | |
47 | [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 24, 24), | |
48 | [ANA_ANEVENTS_VS2TTL1] = REG_FIELD(ANA_ANEVENTS, 23, 23), | |
49 | [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 22, 22), | |
50 | [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 21, 21), | |
51 | [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 20, 20), | |
52 | [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 19, 19), | |
53 | [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 18, 18), | |
54 | [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 17, 17), | |
55 | [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 16, 16), | |
56 | [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 15, 15), | |
57 | [ANA_ANEVENTS_DROPPED] = REG_FIELD(ANA_ANEVENTS, 14, 14), | |
58 | [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 13, 13), | |
59 | [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 12, 12), | |
60 | [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 11, 11), | |
61 | [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 10, 10), | |
62 | [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 9, 9), | |
63 | [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 8, 8), | |
64 | [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 7, 7), | |
65 | [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), | |
66 | [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), | |
67 | [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 4, 4), | |
68 | [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 3, 3), | |
69 | [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 2, 2), | |
70 | [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 1, 1), | |
71 | [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 0, 0), | |
72 | [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 18, 18), | |
73 | [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 10, 11), | |
74 | [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 9), | |
75 | [QSYS_TIMED_FRAME_ENTRY_TFRM_VLD] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 20, 20), | |
76 | [QSYS_TIMED_FRAME_ENTRY_TFRM_FP] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 8, 19), | |
77 | [QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 4, 7), | |
78 | [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 1, 3), | |
79 | [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 0, 0), | |
80 | [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2), | |
81 | [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1), | |
82 | [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0), | |
8bb849d6 VO |
83 | /* Replicated per number of ports (12), register size 4 per port */ |
84 | [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 12, 4), | |
85 | [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 12, 4), | |
86 | [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 12, 4), | |
87 | [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 12, 4), | |
88 | [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 12, 4), | |
89 | [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 12, 4), | |
90 | [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 12, 4), | |
91 | [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 12, 4), | |
92 | [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 12, 4), | |
93 | [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 12, 4), | |
94 | [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 12, 4), | |
95 | [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 12, 4), | |
96 | [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4), | |
d9feb904 VO |
97 | }; |
98 | ||
91904600 VO |
99 | static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = { |
100 | [OCELOT_STAT_RX_OCTETS] = { | |
101 | .name = "rx_octets", | |
d4c36765 | 102 | .reg = SYS_COUNT_RX_OCTETS, |
91904600 VO |
103 | }, |
104 | [OCELOT_STAT_RX_UNICAST] = { | |
105 | .name = "rx_unicast", | |
d4c36765 | 106 | .reg = SYS_COUNT_RX_UNICAST, |
91904600 VO |
107 | }, |
108 | [OCELOT_STAT_RX_MULTICAST] = { | |
109 | .name = "rx_multicast", | |
d4c36765 | 110 | .reg = SYS_COUNT_RX_MULTICAST, |
91904600 VO |
111 | }, |
112 | [OCELOT_STAT_RX_BROADCAST] = { | |
113 | .name = "rx_broadcast", | |
d4c36765 | 114 | .reg = SYS_COUNT_RX_BROADCAST, |
91904600 VO |
115 | }, |
116 | [OCELOT_STAT_RX_SHORTS] = { | |
117 | .name = "rx_shorts", | |
d4c36765 | 118 | .reg = SYS_COUNT_RX_SHORTS, |
91904600 VO |
119 | }, |
120 | [OCELOT_STAT_RX_FRAGMENTS] = { | |
121 | .name = "rx_fragments", | |
d4c36765 | 122 | .reg = SYS_COUNT_RX_FRAGMENTS, |
91904600 VO |
123 | }, |
124 | [OCELOT_STAT_RX_JABBERS] = { | |
125 | .name = "rx_jabbers", | |
d4c36765 | 126 | .reg = SYS_COUNT_RX_JABBERS, |
91904600 VO |
127 | }, |
128 | [OCELOT_STAT_RX_CRC_ALIGN_ERRS] = { | |
129 | .name = "rx_crc_align_errs", | |
d4c36765 | 130 | .reg = SYS_COUNT_RX_CRC_ALIGN_ERRS, |
91904600 VO |
131 | }, |
132 | [OCELOT_STAT_RX_SYM_ERRS] = { | |
133 | .name = "rx_sym_errs", | |
d4c36765 | 134 | .reg = SYS_COUNT_RX_SYM_ERRS, |
91904600 VO |
135 | }, |
136 | [OCELOT_STAT_RX_64] = { | |
137 | .name = "rx_frames_below_65_octets", | |
d4c36765 | 138 | .reg = SYS_COUNT_RX_64, |
91904600 VO |
139 | }, |
140 | [OCELOT_STAT_RX_65_127] = { | |
141 | .name = "rx_frames_65_to_127_octets", | |
d4c36765 | 142 | .reg = SYS_COUNT_RX_65_127, |
91904600 VO |
143 | }, |
144 | [OCELOT_STAT_RX_128_255] = { | |
145 | .name = "rx_frames_128_to_255_octets", | |
d4c36765 | 146 | .reg = SYS_COUNT_RX_128_255, |
91904600 VO |
147 | }, |
148 | [OCELOT_STAT_RX_256_511] = { | |
149 | .name = "rx_frames_256_to_511_octets", | |
d4c36765 | 150 | .reg = SYS_COUNT_RX_256_511, |
91904600 VO |
151 | }, |
152 | [OCELOT_STAT_RX_512_1023] = { | |
153 | .name = "rx_frames_512_to_1023_octets", | |
d4c36765 | 154 | .reg = SYS_COUNT_RX_512_1023, |
91904600 VO |
155 | }, |
156 | [OCELOT_STAT_RX_1024_1526] = { | |
157 | .name = "rx_frames_1024_to_1526_octets", | |
d4c36765 | 158 | .reg = SYS_COUNT_RX_1024_1526, |
91904600 VO |
159 | }, |
160 | [OCELOT_STAT_RX_1527_MAX] = { | |
161 | .name = "rx_frames_over_1526_octets", | |
d4c36765 | 162 | .reg = SYS_COUNT_RX_1527_MAX, |
91904600 VO |
163 | }, |
164 | [OCELOT_STAT_RX_PAUSE] = { | |
165 | .name = "rx_pause", | |
d4c36765 | 166 | .reg = SYS_COUNT_RX_PAUSE, |
91904600 VO |
167 | }, |
168 | [OCELOT_STAT_RX_CONTROL] = { | |
169 | .name = "rx_control", | |
d4c36765 | 170 | .reg = SYS_COUNT_RX_CONTROL, |
91904600 VO |
171 | }, |
172 | [OCELOT_STAT_RX_LONGS] = { | |
173 | .name = "rx_longs", | |
d4c36765 | 174 | .reg = SYS_COUNT_RX_LONGS, |
91904600 VO |
175 | }, |
176 | [OCELOT_STAT_RX_CLASSIFIED_DROPS] = { | |
177 | .name = "rx_classified_drops", | |
d4c36765 | 178 | .reg = SYS_COUNT_RX_CLASSIFIED_DROPS, |
91904600 VO |
179 | }, |
180 | [OCELOT_STAT_RX_RED_PRIO_0] = { | |
181 | .name = "rx_red_prio_0", | |
d4c36765 | 182 | .reg = SYS_COUNT_RX_RED_PRIO_0, |
91904600 VO |
183 | }, |
184 | [OCELOT_STAT_RX_RED_PRIO_1] = { | |
185 | .name = "rx_red_prio_1", | |
d4c36765 | 186 | .reg = SYS_COUNT_RX_RED_PRIO_1, |
91904600 VO |
187 | }, |
188 | [OCELOT_STAT_RX_RED_PRIO_2] = { | |
189 | .name = "rx_red_prio_2", | |
d4c36765 | 190 | .reg = SYS_COUNT_RX_RED_PRIO_2, |
91904600 VO |
191 | }, |
192 | [OCELOT_STAT_RX_RED_PRIO_3] = { | |
193 | .name = "rx_red_prio_3", | |
d4c36765 | 194 | .reg = SYS_COUNT_RX_RED_PRIO_3, |
91904600 VO |
195 | }, |
196 | [OCELOT_STAT_RX_RED_PRIO_4] = { | |
197 | .name = "rx_red_prio_4", | |
d4c36765 | 198 | .reg = SYS_COUNT_RX_RED_PRIO_4, |
91904600 VO |
199 | }, |
200 | [OCELOT_STAT_RX_RED_PRIO_5] = { | |
201 | .name = "rx_red_prio_5", | |
d4c36765 | 202 | .reg = SYS_COUNT_RX_RED_PRIO_5, |
91904600 VO |
203 | }, |
204 | [OCELOT_STAT_RX_RED_PRIO_6] = { | |
205 | .name = "rx_red_prio_6", | |
d4c36765 | 206 | .reg = SYS_COUNT_RX_RED_PRIO_6, |
91904600 VO |
207 | }, |
208 | [OCELOT_STAT_RX_RED_PRIO_7] = { | |
209 | .name = "rx_red_prio_7", | |
d4c36765 | 210 | .reg = SYS_COUNT_RX_RED_PRIO_7, |
91904600 VO |
211 | }, |
212 | [OCELOT_STAT_RX_YELLOW_PRIO_0] = { | |
213 | .name = "rx_yellow_prio_0", | |
d4c36765 | 214 | .reg = SYS_COUNT_RX_YELLOW_PRIO_0, |
91904600 VO |
215 | }, |
216 | [OCELOT_STAT_RX_YELLOW_PRIO_1] = { | |
217 | .name = "rx_yellow_prio_1", | |
d4c36765 | 218 | .reg = SYS_COUNT_RX_YELLOW_PRIO_1, |
91904600 VO |
219 | }, |
220 | [OCELOT_STAT_RX_YELLOW_PRIO_2] = { | |
221 | .name = "rx_yellow_prio_2", | |
d4c36765 | 222 | .reg = SYS_COUNT_RX_YELLOW_PRIO_2, |
91904600 VO |
223 | }, |
224 | [OCELOT_STAT_RX_YELLOW_PRIO_3] = { | |
225 | .name = "rx_yellow_prio_3", | |
d4c36765 | 226 | .reg = SYS_COUNT_RX_YELLOW_PRIO_3, |
91904600 VO |
227 | }, |
228 | [OCELOT_STAT_RX_YELLOW_PRIO_4] = { | |
229 | .name = "rx_yellow_prio_4", | |
d4c36765 | 230 | .reg = SYS_COUNT_RX_YELLOW_PRIO_4, |
91904600 VO |
231 | }, |
232 | [OCELOT_STAT_RX_YELLOW_PRIO_5] = { | |
233 | .name = "rx_yellow_prio_5", | |
d4c36765 | 234 | .reg = SYS_COUNT_RX_YELLOW_PRIO_5, |
91904600 VO |
235 | }, |
236 | [OCELOT_STAT_RX_YELLOW_PRIO_6] = { | |
237 | .name = "rx_yellow_prio_6", | |
d4c36765 | 238 | .reg = SYS_COUNT_RX_YELLOW_PRIO_6, |
91904600 VO |
239 | }, |
240 | [OCELOT_STAT_RX_YELLOW_PRIO_7] = { | |
241 | .name = "rx_yellow_prio_7", | |
d4c36765 | 242 | .reg = SYS_COUNT_RX_YELLOW_PRIO_7, |
91904600 VO |
243 | }, |
244 | [OCELOT_STAT_RX_GREEN_PRIO_0] = { | |
245 | .name = "rx_green_prio_0", | |
d4c36765 | 246 | .reg = SYS_COUNT_RX_GREEN_PRIO_0, |
91904600 VO |
247 | }, |
248 | [OCELOT_STAT_RX_GREEN_PRIO_1] = { | |
249 | .name = "rx_green_prio_1", | |
d4c36765 | 250 | .reg = SYS_COUNT_RX_GREEN_PRIO_1, |
91904600 VO |
251 | }, |
252 | [OCELOT_STAT_RX_GREEN_PRIO_2] = { | |
253 | .name = "rx_green_prio_2", | |
d4c36765 | 254 | .reg = SYS_COUNT_RX_GREEN_PRIO_2, |
91904600 VO |
255 | }, |
256 | [OCELOT_STAT_RX_GREEN_PRIO_3] = { | |
257 | .name = "rx_green_prio_3", | |
d4c36765 | 258 | .reg = SYS_COUNT_RX_GREEN_PRIO_3, |
91904600 VO |
259 | }, |
260 | [OCELOT_STAT_RX_GREEN_PRIO_4] = { | |
261 | .name = "rx_green_prio_4", | |
d4c36765 | 262 | .reg = SYS_COUNT_RX_GREEN_PRIO_4, |
91904600 VO |
263 | }, |
264 | [OCELOT_STAT_RX_GREEN_PRIO_5] = { | |
265 | .name = "rx_green_prio_5", | |
d4c36765 | 266 | .reg = SYS_COUNT_RX_GREEN_PRIO_5, |
91904600 VO |
267 | }, |
268 | [OCELOT_STAT_RX_GREEN_PRIO_6] = { | |
269 | .name = "rx_green_prio_6", | |
d4c36765 | 270 | .reg = SYS_COUNT_RX_GREEN_PRIO_6, |
91904600 VO |
271 | }, |
272 | [OCELOT_STAT_RX_GREEN_PRIO_7] = { | |
273 | .name = "rx_green_prio_7", | |
d4c36765 | 274 | .reg = SYS_COUNT_RX_GREEN_PRIO_7, |
91904600 VO |
275 | }, |
276 | [OCELOT_STAT_TX_OCTETS] = { | |
277 | .name = "tx_octets", | |
d4c36765 | 278 | .reg = SYS_COUNT_TX_OCTETS, |
91904600 VO |
279 | }, |
280 | [OCELOT_STAT_TX_UNICAST] = { | |
281 | .name = "tx_unicast", | |
d4c36765 | 282 | .reg = SYS_COUNT_TX_UNICAST, |
91904600 VO |
283 | }, |
284 | [OCELOT_STAT_TX_MULTICAST] = { | |
285 | .name = "tx_multicast", | |
d4c36765 | 286 | .reg = SYS_COUNT_TX_MULTICAST, |
91904600 VO |
287 | }, |
288 | [OCELOT_STAT_TX_BROADCAST] = { | |
289 | .name = "tx_broadcast", | |
d4c36765 | 290 | .reg = SYS_COUNT_TX_BROADCAST, |
91904600 VO |
291 | }, |
292 | [OCELOT_STAT_TX_COLLISION] = { | |
293 | .name = "tx_collision", | |
d4c36765 | 294 | .reg = SYS_COUNT_TX_COLLISION, |
91904600 VO |
295 | }, |
296 | [OCELOT_STAT_TX_DROPS] = { | |
297 | .name = "tx_drops", | |
d4c36765 | 298 | .reg = SYS_COUNT_TX_DROPS, |
91904600 VO |
299 | }, |
300 | [OCELOT_STAT_TX_PAUSE] = { | |
301 | .name = "tx_pause", | |
d4c36765 | 302 | .reg = SYS_COUNT_TX_PAUSE, |
91904600 VO |
303 | }, |
304 | [OCELOT_STAT_TX_64] = { | |
305 | .name = "tx_frames_below_65_octets", | |
d4c36765 | 306 | .reg = SYS_COUNT_TX_64, |
91904600 VO |
307 | }, |
308 | [OCELOT_STAT_TX_65_127] = { | |
309 | .name = "tx_frames_65_to_127_octets", | |
d4c36765 | 310 | .reg = SYS_COUNT_TX_65_127, |
91904600 VO |
311 | }, |
312 | [OCELOT_STAT_TX_128_255] = { | |
313 | .name = "tx_frames_128_255_octets", | |
d4c36765 | 314 | .reg = SYS_COUNT_TX_128_255, |
91904600 VO |
315 | }, |
316 | [OCELOT_STAT_TX_256_511] = { | |
317 | .name = "tx_frames_256_511_octets", | |
d4c36765 | 318 | .reg = SYS_COUNT_TX_256_511, |
91904600 VO |
319 | }, |
320 | [OCELOT_STAT_TX_512_1023] = { | |
321 | .name = "tx_frames_512_1023_octets", | |
d4c36765 | 322 | .reg = SYS_COUNT_TX_512_1023, |
91904600 VO |
323 | }, |
324 | [OCELOT_STAT_TX_1024_1526] = { | |
325 | .name = "tx_frames_1024_1526_octets", | |
d4c36765 | 326 | .reg = SYS_COUNT_TX_1024_1526, |
91904600 VO |
327 | }, |
328 | [OCELOT_STAT_TX_1527_MAX] = { | |
329 | .name = "tx_frames_over_1526_octets", | |
d4c36765 | 330 | .reg = SYS_COUNT_TX_1527_MAX, |
91904600 VO |
331 | }, |
332 | [OCELOT_STAT_TX_YELLOW_PRIO_0] = { | |
333 | .name = "tx_yellow_prio_0", | |
d4c36765 | 334 | .reg = SYS_COUNT_TX_YELLOW_PRIO_0, |
91904600 VO |
335 | }, |
336 | [OCELOT_STAT_TX_YELLOW_PRIO_1] = { | |
337 | .name = "tx_yellow_prio_1", | |
d4c36765 | 338 | .reg = SYS_COUNT_TX_YELLOW_PRIO_1, |
91904600 VO |
339 | }, |
340 | [OCELOT_STAT_TX_YELLOW_PRIO_2] = { | |
341 | .name = "tx_yellow_prio_2", | |
d4c36765 | 342 | .reg = SYS_COUNT_TX_YELLOW_PRIO_2, |
91904600 VO |
343 | }, |
344 | [OCELOT_STAT_TX_YELLOW_PRIO_3] = { | |
345 | .name = "tx_yellow_prio_3", | |
d4c36765 | 346 | .reg = SYS_COUNT_TX_YELLOW_PRIO_3, |
91904600 VO |
347 | }, |
348 | [OCELOT_STAT_TX_YELLOW_PRIO_4] = { | |
349 | .name = "tx_yellow_prio_4", | |
d4c36765 | 350 | .reg = SYS_COUNT_TX_YELLOW_PRIO_4, |
91904600 VO |
351 | }, |
352 | [OCELOT_STAT_TX_YELLOW_PRIO_5] = { | |
353 | .name = "tx_yellow_prio_5", | |
d4c36765 | 354 | .reg = SYS_COUNT_TX_YELLOW_PRIO_5, |
91904600 VO |
355 | }, |
356 | [OCELOT_STAT_TX_YELLOW_PRIO_6] = { | |
357 | .name = "tx_yellow_prio_6", | |
d4c36765 | 358 | .reg = SYS_COUNT_TX_YELLOW_PRIO_6, |
91904600 VO |
359 | }, |
360 | [OCELOT_STAT_TX_YELLOW_PRIO_7] = { | |
361 | .name = "tx_yellow_prio_7", | |
d4c36765 | 362 | .reg = SYS_COUNT_TX_YELLOW_PRIO_7, |
91904600 VO |
363 | }, |
364 | [OCELOT_STAT_TX_GREEN_PRIO_0] = { | |
365 | .name = "tx_green_prio_0", | |
d4c36765 | 366 | .reg = SYS_COUNT_TX_GREEN_PRIO_0, |
91904600 VO |
367 | }, |
368 | [OCELOT_STAT_TX_GREEN_PRIO_1] = { | |
369 | .name = "tx_green_prio_1", | |
d4c36765 | 370 | .reg = SYS_COUNT_TX_GREEN_PRIO_1, |
91904600 VO |
371 | }, |
372 | [OCELOT_STAT_TX_GREEN_PRIO_2] = { | |
373 | .name = "tx_green_prio_2", | |
d4c36765 | 374 | .reg = SYS_COUNT_TX_GREEN_PRIO_2, |
91904600 VO |
375 | }, |
376 | [OCELOT_STAT_TX_GREEN_PRIO_3] = { | |
377 | .name = "tx_green_prio_3", | |
d4c36765 | 378 | .reg = SYS_COUNT_TX_GREEN_PRIO_3, |
91904600 VO |
379 | }, |
380 | [OCELOT_STAT_TX_GREEN_PRIO_4] = { | |
381 | .name = "tx_green_prio_4", | |
d4c36765 | 382 | .reg = SYS_COUNT_TX_GREEN_PRIO_4, |
91904600 VO |
383 | }, |
384 | [OCELOT_STAT_TX_GREEN_PRIO_5] = { | |
385 | .name = "tx_green_prio_5", | |
d4c36765 | 386 | .reg = SYS_COUNT_TX_GREEN_PRIO_5, |
91904600 VO |
387 | }, |
388 | [OCELOT_STAT_TX_GREEN_PRIO_6] = { | |
389 | .name = "tx_green_prio_6", | |
d4c36765 | 390 | .reg = SYS_COUNT_TX_GREEN_PRIO_6, |
91904600 VO |
391 | }, |
392 | [OCELOT_STAT_TX_GREEN_PRIO_7] = { | |
393 | .name = "tx_green_prio_7", | |
d4c36765 | 394 | .reg = SYS_COUNT_TX_GREEN_PRIO_7, |
91904600 VO |
395 | }, |
396 | [OCELOT_STAT_TX_AGED] = { | |
397 | .name = "tx_aged", | |
d4c36765 | 398 | .reg = SYS_COUNT_TX_AGING, |
91904600 VO |
399 | }, |
400 | [OCELOT_STAT_DROP_LOCAL] = { | |
401 | .name = "drop_local", | |
d4c36765 | 402 | .reg = SYS_COUNT_DROP_LOCAL, |
91904600 VO |
403 | }, |
404 | [OCELOT_STAT_DROP_TAIL] = { | |
405 | .name = "drop_tail", | |
d4c36765 | 406 | .reg = SYS_COUNT_DROP_TAIL, |
91904600 VO |
407 | }, |
408 | [OCELOT_STAT_DROP_YELLOW_PRIO_0] = { | |
409 | .name = "drop_yellow_prio_0", | |
d4c36765 | 410 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_0, |
91904600 VO |
411 | }, |
412 | [OCELOT_STAT_DROP_YELLOW_PRIO_1] = { | |
413 | .name = "drop_yellow_prio_1", | |
d4c36765 | 414 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_1, |
91904600 VO |
415 | }, |
416 | [OCELOT_STAT_DROP_YELLOW_PRIO_2] = { | |
417 | .name = "drop_yellow_prio_2", | |
d4c36765 | 418 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_2, |
91904600 VO |
419 | }, |
420 | [OCELOT_STAT_DROP_YELLOW_PRIO_3] = { | |
421 | .name = "drop_yellow_prio_3", | |
d4c36765 | 422 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_3, |
91904600 VO |
423 | }, |
424 | [OCELOT_STAT_DROP_YELLOW_PRIO_4] = { | |
425 | .name = "drop_yellow_prio_4", | |
d4c36765 | 426 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_4, |
91904600 VO |
427 | }, |
428 | [OCELOT_STAT_DROP_YELLOW_PRIO_5] = { | |
429 | .name = "drop_yellow_prio_5", | |
d4c36765 | 430 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_5, |
91904600 VO |
431 | }, |
432 | [OCELOT_STAT_DROP_YELLOW_PRIO_6] = { | |
433 | .name = "drop_yellow_prio_6", | |
d4c36765 | 434 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_6, |
91904600 VO |
435 | }, |
436 | [OCELOT_STAT_DROP_YELLOW_PRIO_7] = { | |
437 | .name = "drop_yellow_prio_7", | |
d4c36765 | 438 | .reg = SYS_COUNT_DROP_YELLOW_PRIO_7, |
91904600 VO |
439 | }, |
440 | [OCELOT_STAT_DROP_GREEN_PRIO_0] = { | |
441 | .name = "drop_green_prio_0", | |
d4c36765 | 442 | .reg = SYS_COUNT_DROP_GREEN_PRIO_0, |
91904600 VO |
443 | }, |
444 | [OCELOT_STAT_DROP_GREEN_PRIO_1] = { | |
445 | .name = "drop_green_prio_1", | |
d4c36765 | 446 | .reg = SYS_COUNT_DROP_GREEN_PRIO_1, |
91904600 VO |
447 | }, |
448 | [OCELOT_STAT_DROP_GREEN_PRIO_2] = { | |
449 | .name = "drop_green_prio_2", | |
d4c36765 | 450 | .reg = SYS_COUNT_DROP_GREEN_PRIO_2, |
91904600 VO |
451 | }, |
452 | [OCELOT_STAT_DROP_GREEN_PRIO_3] = { | |
453 | .name = "drop_green_prio_3", | |
d4c36765 | 454 | .reg = SYS_COUNT_DROP_GREEN_PRIO_3, |
91904600 VO |
455 | }, |
456 | [OCELOT_STAT_DROP_GREEN_PRIO_4] = { | |
457 | .name = "drop_green_prio_4", | |
d4c36765 | 458 | .reg = SYS_COUNT_DROP_GREEN_PRIO_4, |
91904600 VO |
459 | }, |
460 | [OCELOT_STAT_DROP_GREEN_PRIO_5] = { | |
461 | .name = "drop_green_prio_5", | |
d4c36765 | 462 | .reg = SYS_COUNT_DROP_GREEN_PRIO_5, |
91904600 VO |
463 | }, |
464 | [OCELOT_STAT_DROP_GREEN_PRIO_6] = { | |
465 | .name = "drop_green_prio_6", | |
d4c36765 | 466 | .reg = SYS_COUNT_DROP_GREEN_PRIO_6, |
91904600 VO |
467 | }, |
468 | [OCELOT_STAT_DROP_GREEN_PRIO_7] = { | |
469 | .name = "drop_green_prio_7", | |
d4c36765 | 470 | .reg = SYS_COUNT_DROP_GREEN_PRIO_7, |
91904600 | 471 | }, |
d9feb904 VO |
472 | }; |
473 | ||
474 | static void ocelot_pll5_init(struct ocelot *ocelot) | |
475 | { | |
476 | /* Configure PLL5. This will need a proper CCF driver | |
477 | * The values are coming from the VTSS API for Ocelot | |
478 | */ | |
479 | regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG4, | |
480 | HSIO_PLL5G_CFG4_IB_CTRL(0x7600) | | |
481 | HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8)); | |
482 | regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG0, | |
483 | HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) | | |
484 | HSIO_PLL5G_CFG0_CPU_CLK_DIV(2) | | |
485 | HSIO_PLL5G_CFG0_ENA_BIAS | | |
486 | HSIO_PLL5G_CFG0_ENA_VCO_BUF | | |
487 | HSIO_PLL5G_CFG0_ENA_CP1 | | |
488 | HSIO_PLL5G_CFG0_SELCPI(2) | | |
489 | HSIO_PLL5G_CFG0_LOOP_BW_RES(0xe) | | |
490 | HSIO_PLL5G_CFG0_SELBGV820(4) | | |
491 | HSIO_PLL5G_CFG0_DIV4 | | |
492 | HSIO_PLL5G_CFG0_ENA_CLKTREE | | |
493 | HSIO_PLL5G_CFG0_ENA_LANE); | |
494 | regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG2, | |
495 | HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET | | |
496 | HSIO_PLL5G_CFG2_EN_RESET_OVERRUN | | |
497 | HSIO_PLL5G_CFG2_GAIN_TEST(0x8) | | |
498 | HSIO_PLL5G_CFG2_ENA_AMPCTRL | | |
499 | HSIO_PLL5G_CFG2_PWD_AMPCTRL_N | | |
500 | HSIO_PLL5G_CFG2_AMPC_SEL(0x10)); | |
501 | } | |
502 | ||
503 | static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) | |
504 | { | |
505 | int ret; | |
506 | ||
507 | ocelot->map = ocelot_regmap; | |
508 | ocelot->stats_layout = ocelot_stats_layout; | |
d9feb904 VO |
509 | ocelot->num_mact_rows = 1024; |
510 | ocelot->ops = ops; | |
511 | ||
512 | ret = ocelot_regfields_init(ocelot, ocelot_regfields); | |
513 | if (ret) | |
514 | return ret; | |
515 | ||
516 | ocelot_pll5_init(ocelot); | |
517 | ||
518 | eth_random_addr(ocelot->base_mac); | |
519 | ocelot->base_mac[5] &= 0xf0; | |
520 | ||
521 | return 0; | |
522 | } | |
523 | ||
a556c76a AB |
524 | static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) |
525 | { | |
526 | struct ocelot *ocelot = arg; | |
924ee317 | 527 | int grp = 0, err; |
a556c76a | 528 | |
f833ca29 | 529 | while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) { |
4e3b0468 | 530 | struct sk_buff *skb; |
a556c76a | 531 | |
924ee317 VO |
532 | err = ocelot_xtr_poll_frame(ocelot, grp, &skb); |
533 | if (err) | |
a94306ce | 534 | goto out; |
4e3b0468 | 535 | |
924ee317 VO |
536 | skb->dev->stats.rx_bytes += skb->len; |
537 | skb->dev->stats.rx_packets++; | |
a556c76a | 538 | |
b2e118f6 AT |
539 | if (!skb_defer_rx_timestamp(skb)) |
540 | netif_rx(skb); | |
f833ca29 | 541 | } |
a556c76a | 542 | |
a94306ce | 543 | out: |
d7795f8f | 544 | if (err < 0) |
0a6f17c6 | 545 | ocelot_drain_cpu_queue(ocelot, 0); |
a556c76a AB |
546 | |
547 | return IRQ_HANDLED; | |
548 | } | |
549 | ||
4e3b0468 AT |
550 | static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg) |
551 | { | |
4e3b0468 AT |
552 | struct ocelot *ocelot = arg; |
553 | ||
e23a7b3e | 554 | ocelot_get_txtstamp(ocelot); |
4e3b0468 AT |
555 | |
556 | return IRQ_HANDLED; | |
557 | } | |
558 | ||
a556c76a AB |
559 | static const struct of_device_id mscc_ocelot_match[] = { |
560 | { .compatible = "mscc,vsc7514-switch" }, | |
561 | { } | |
562 | }; | |
563 | MODULE_DEVICE_TABLE(of, mscc_ocelot_match); | |
564 | ||
3a77b593 VO |
565 | static int ocelot_reset(struct ocelot *ocelot) |
566 | { | |
567 | int retries = 100; | |
568 | u32 val; | |
569 | ||
570 | regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); | |
571 | regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); | |
572 | ||
573 | do { | |
574 | msleep(1); | |
575 | regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], | |
576 | &val); | |
577 | } while (val && --retries); | |
578 | ||
579 | if (!retries) | |
580 | return -ETIMEDOUT; | |
581 | ||
582 | regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); | |
583 | regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); | |
584 | ||
585 | return 0; | |
586 | } | |
587 | ||
aa92d836 MK |
588 | /* Watermark encode |
589 | * Bit 8: Unit; 0:1, 1:16 | |
590 | * Bit 7-0: Value to be multiplied with unit | |
591 | */ | |
592 | static u16 ocelot_wm_enc(u16 value) | |
593 | { | |
01326493 VO |
594 | WARN_ON(value >= 16 * BIT(8)); |
595 | ||
aa92d836 MK |
596 | if (value >= BIT(8)) |
597 | return BIT(8) | (value / 16); | |
598 | ||
599 | return value; | |
600 | } | |
601 | ||
703b7621 VO |
602 | static u16 ocelot_wm_dec(u16 wm) |
603 | { | |
604 | if (wm & BIT(8)) | |
605 | return (wm & GENMASK(7, 0)) * 16; | |
606 | ||
607 | return wm; | |
608 | } | |
609 | ||
610 | static void ocelot_wm_stat(u32 val, u32 *inuse, u32 *maxuse) | |
611 | { | |
612 | *inuse = (val & GENMASK(23, 12)) >> 12; | |
613 | *maxuse = val & GENMASK(11, 0); | |
614 | } | |
615 | ||
dc3de2a2 | 616 | static const struct ocelot_ops ocelot_ops = { |
3a77b593 | 617 | .reset = ocelot_reset, |
aa92d836 | 618 | .wm_enc = ocelot_wm_enc, |
703b7621 VO |
619 | .wm_dec = ocelot_wm_dec, |
620 | .wm_stat = ocelot_wm_stat, | |
319e4dd1 VO |
621 | .port_to_netdev = ocelot_port_to_netdev, |
622 | .netdev_to_port = ocelot_netdev_to_port, | |
dc3de2a2 CM |
623 | }; |
624 | ||
20968054 | 625 | static struct vcap_props vsc7514_vcap_props[] = { |
e3aea296 VO |
626 | [VCAP_ES0] = { |
627 | .action_type_width = 0, | |
628 | .action_table = { | |
629 | [ES0_ACTION_TYPE_NORMAL] = { | |
630 | .width = 73, /* HIT_STICKY not included */ | |
631 | .count = 1, | |
632 | }, | |
633 | }, | |
634 | .target = S0, | |
635 | .keys = vsc7514_vcap_es0_keys, | |
636 | .actions = vsc7514_vcap_es0_actions, | |
637 | }, | |
a61e365d VO |
638 | [VCAP_IS1] = { |
639 | .action_type_width = 0, | |
640 | .action_table = { | |
641 | [IS1_ACTION_TYPE_NORMAL] = { | |
642 | .width = 78, /* HIT_STICKY not included */ | |
643 | .count = 4, | |
644 | }, | |
645 | }, | |
646 | .target = S1, | |
647 | .keys = vsc7514_vcap_is1_keys, | |
648 | .actions = vsc7514_vcap_is1_actions, | |
649 | }, | |
8551cdeb | 650 | [VCAP_IS2] = { |
8551cdeb VO |
651 | .action_type_width = 1, |
652 | .action_table = { | |
653 | [IS2_ACTION_TYPE_NORMAL] = { | |
654 | .width = 49, | |
655 | .count = 2 | |
656 | }, | |
657 | [IS2_ACTION_TYPE_SMAC_SIP] = { | |
658 | .width = 6, | |
659 | .count = 4 | |
660 | }, | |
661 | }, | |
c1c3993e VO |
662 | .target = S2, |
663 | .keys = vsc7514_vcap_is2_keys, | |
664 | .actions = vsc7514_vcap_is2_actions, | |
8551cdeb VO |
665 | }, |
666 | }; | |
667 | ||
2b49d128 YL |
668 | static struct ptp_clock_info ocelot_ptp_clock_info = { |
669 | .owner = THIS_MODULE, | |
670 | .name = "ocelot ptp", | |
671 | .max_adj = 0x7fffffff, | |
672 | .n_alarm = 0, | |
673 | .n_ext_ts = 0, | |
aabb2bb0 YL |
674 | .n_per_out = OCELOT_PTP_PINS_NUM, |
675 | .n_pins = OCELOT_PTP_PINS_NUM, | |
2b49d128 YL |
676 | .pps = 0, |
677 | .gettime64 = ocelot_ptp_gettime64, | |
678 | .settime64 = ocelot_ptp_settime64, | |
679 | .adjtime = ocelot_ptp_adjtime, | |
680 | .adjfine = ocelot_ptp_adjfine, | |
aabb2bb0 YL |
681 | .verify = ocelot_ptp_verify, |
682 | .enable = ocelot_ptp_enable, | |
2b49d128 YL |
683 | }; |
684 | ||
6c30384e VO |
685 | static void mscc_ocelot_teardown_devlink_ports(struct ocelot *ocelot) |
686 | { | |
687 | int port; | |
688 | ||
689 | for (port = 0; port < ocelot->num_phys_ports; port++) | |
690 | ocelot_port_devlink_teardown(ocelot, port); | |
691 | } | |
692 | ||
22cdb493 VO |
693 | static void mscc_ocelot_release_ports(struct ocelot *ocelot) |
694 | { | |
695 | int port; | |
696 | ||
697 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
22cdb493 VO |
698 | struct ocelot_port *ocelot_port; |
699 | ||
700 | ocelot_port = ocelot->ports[port]; | |
701 | if (!ocelot_port) | |
702 | continue; | |
703 | ||
e5fb512d | 704 | ocelot_deinit_port(ocelot, port); |
e0c16233 | 705 | ocelot_release_port(ocelot_port); |
22cdb493 VO |
706 | } |
707 | } | |
708 | ||
7c411799 VO |
709 | static int mscc_ocelot_init_ports(struct platform_device *pdev, |
710 | struct device_node *ports) | |
711 | { | |
712 | struct ocelot *ocelot = platform_get_drvdata(pdev); | |
e0c16233 | 713 | u32 devlink_ports_registered = 0; |
7c411799 | 714 | struct device_node *portnp; |
6c30384e VO |
715 | int port, err; |
716 | u32 reg; | |
7c411799 VO |
717 | |
718 | ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, | |
719 | sizeof(struct ocelot_port *), GFP_KERNEL); | |
720 | if (!ocelot->ports) | |
721 | return -ENOMEM; | |
722 | ||
6c30384e VO |
723 | ocelot->devlink_ports = devm_kcalloc(ocelot->dev, |
724 | ocelot->num_phys_ports, | |
725 | sizeof(*ocelot->devlink_ports), | |
726 | GFP_KERNEL); | |
727 | if (!ocelot->devlink_ports) | |
728 | return -ENOMEM; | |
729 | ||
7c411799 VO |
730 | for_each_available_child_of_node(ports, portnp) { |
731 | struct ocelot_port_private *priv; | |
732 | struct ocelot_port *ocelot_port; | |
6c30384e | 733 | struct devlink_port *dlp; |
7c411799 VO |
734 | struct regmap *target; |
735 | struct resource *res; | |
7c411799 | 736 | char res_name[8]; |
7c411799 | 737 | |
6c30384e | 738 | if (of_property_read_u32(portnp, "reg", ®)) |
7c411799 VO |
739 | continue; |
740 | ||
6c30384e | 741 | port = reg; |
e0c16233 DC |
742 | if (port < 0 || port >= ocelot->num_phys_ports) { |
743 | dev_err(ocelot->dev, | |
744 | "invalid port number: %d >= %d\n", port, | |
745 | ocelot->num_phys_ports); | |
746 | continue; | |
747 | } | |
6c30384e | 748 | |
7c411799 VO |
749 | snprintf(res_name, sizeof(res_name), "port%d", port); |
750 | ||
751 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
752 | res_name); | |
753 | target = ocelot_regmap_init(ocelot, res); | |
e0c16233 DC |
754 | if (IS_ERR(target)) { |
755 | err = PTR_ERR(target); | |
d1a7b9e4 | 756 | of_node_put(portnp); |
e0c16233 DC |
757 | goto out_teardown; |
758 | } | |
7c411799 | 759 | |
6c30384e VO |
760 | err = ocelot_port_devlink_init(ocelot, port, |
761 | DEVLINK_PORT_FLAVOUR_PHYSICAL); | |
762 | if (err) { | |
763 | of_node_put(portnp); | |
764 | goto out_teardown; | |
765 | } | |
766 | ||
e6e12df6 | 767 | err = ocelot_probe_port(ocelot, port, target, portnp); |
7c411799 | 768 | if (err) { |
5c8bb71d VO |
769 | ocelot_port_devlink_teardown(ocelot, port); |
770 | continue; | |
7c411799 VO |
771 | } |
772 | ||
5c8bb71d VO |
773 | devlink_ports_registered |= BIT(port); |
774 | ||
7c411799 VO |
775 | ocelot_port = ocelot->ports[port]; |
776 | priv = container_of(ocelot_port, struct ocelot_port_private, | |
777 | port); | |
6c30384e VO |
778 | dlp = &ocelot->devlink_ports[port]; |
779 | devlink_port_type_eth_set(dlp, priv->dev); | |
7c411799 VO |
780 | } |
781 | ||
6c30384e VO |
782 | /* Initialize unused devlink ports at the end */ |
783 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
e0c16233 | 784 | if (devlink_ports_registered & BIT(port)) |
6c30384e VO |
785 | continue; |
786 | ||
787 | err = ocelot_port_devlink_init(ocelot, port, | |
788 | DEVLINK_PORT_FLAVOUR_UNUSED); | |
e0c16233 | 789 | if (err) |
6c30384e | 790 | goto out_teardown; |
6c30384e | 791 | |
e0c16233 DC |
792 | devlink_ports_registered |= BIT(port); |
793 | } | |
6c30384e | 794 | |
7c411799 | 795 | return 0; |
6c30384e VO |
796 | |
797 | out_teardown: | |
798 | /* Unregister the network interfaces */ | |
799 | mscc_ocelot_release_ports(ocelot); | |
800 | /* Tear down devlink ports for the registered network interfaces */ | |
801 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
e0c16233 DC |
802 | if (devlink_ports_registered & BIT(port)) |
803 | ocelot_port_devlink_teardown(ocelot, port); | |
6c30384e | 804 | } |
6c30384e | 805 | return err; |
7c411799 VO |
806 | } |
807 | ||
a556c76a AB |
808 | static int mscc_ocelot_probe(struct platform_device *pdev) |
809 | { | |
a556c76a | 810 | struct device_node *np = pdev->dev.of_node; |
4e3b0468 | 811 | int err, irq_xtr, irq_ptp_rdy; |
7c411799 | 812 | struct device_node *ports; |
6c30384e | 813 | struct devlink *devlink; |
a556c76a | 814 | struct ocelot *ocelot; |
19aedfbe | 815 | struct regmap *hsio; |
4e3b0468 | 816 | unsigned int i; |
a556c76a AB |
817 | |
818 | struct { | |
819 | enum ocelot_target id; | |
820 | char *name; | |
45bce171 | 821 | u8 optional:1; |
259630e0 | 822 | } io_target[] = { |
a556c76a AB |
823 | { SYS, "sys" }, |
824 | { REW, "rew" }, | |
825 | { QSYS, "qsys" }, | |
826 | { ANA, "ana" }, | |
827 | { QS, "qs" }, | |
e3aea296 | 828 | { S0, "s0" }, |
a61e365d | 829 | { S1, "s1" }, |
b5962294 | 830 | { S2, "s2" }, |
45bce171 | 831 | { PTP, "ptp", 1 }, |
753a026c | 832 | { FDMA, "fdma", 1 }, |
a556c76a AB |
833 | }; |
834 | ||
835 | if (!np && !pdev->dev.platform_data) | |
836 | return -ENODEV; | |
837 | ||
919d13a7 LR |
838 | devlink = |
839 | devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot), &pdev->dev); | |
6c30384e | 840 | if (!devlink) |
a556c76a AB |
841 | return -ENOMEM; |
842 | ||
6c30384e VO |
843 | ocelot = devlink_priv(devlink); |
844 | ocelot->devlink = priv_to_devlink(ocelot); | |
a556c76a AB |
845 | platform_set_drvdata(pdev, ocelot); |
846 | ocelot->dev = &pdev->dev; | |
847 | ||
259630e0 | 848 | for (i = 0; i < ARRAY_SIZE(io_target); i++) { |
a556c76a | 849 | struct regmap *target; |
259630e0 | 850 | struct resource *res; |
a556c76a | 851 | |
259630e0 CM |
852 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
853 | io_target[i].name); | |
854 | ||
855 | target = ocelot_regmap_init(ocelot, res); | |
45bce171 | 856 | if (IS_ERR(target)) { |
259630e0 CM |
857 | if (io_target[i].optional) { |
858 | ocelot->targets[io_target[i].id] = NULL; | |
45bce171 AT |
859 | continue; |
860 | } | |
6c30384e VO |
861 | err = PTR_ERR(target); |
862 | goto out_free_devlink; | |
45bce171 | 863 | } |
a556c76a | 864 | |
259630e0 | 865 | ocelot->targets[io_target[i].id] = target; |
a556c76a AB |
866 | } |
867 | ||
753a026c CL |
868 | if (ocelot->targets[FDMA]) |
869 | ocelot_fdma_init(pdev, ocelot); | |
870 | ||
19aedfbe QS |
871 | hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio"); |
872 | if (IS_ERR(hsio)) { | |
873 | dev_err(&pdev->dev, "missing hsio syscon\n"); | |
6c30384e VO |
874 | err = PTR_ERR(hsio); |
875 | goto out_free_devlink; | |
19aedfbe QS |
876 | } |
877 | ||
878 | ocelot->targets[HSIO] = hsio; | |
879 | ||
dc3de2a2 | 880 | err = ocelot_chip_init(ocelot, &ocelot_ops); |
a556c76a | 881 | if (err) |
6c30384e | 882 | goto out_free_devlink; |
a556c76a | 883 | |
4e3b0468 | 884 | irq_xtr = platform_get_irq_byname(pdev, "xtr"); |
4160d9ec DC |
885 | if (irq_xtr < 0) { |
886 | err = irq_xtr; | |
6c30384e | 887 | goto out_free_devlink; |
4160d9ec | 888 | } |
a556c76a | 889 | |
4e3b0468 | 890 | err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL, |
a556c76a AB |
891 | ocelot_xtr_irq_handler, IRQF_ONESHOT, |
892 | "frame extraction", ocelot); | |
893 | if (err) | |
6c30384e | 894 | goto out_free_devlink; |
a556c76a | 895 | |
4e3b0468 AT |
896 | irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy"); |
897 | if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) { | |
898 | err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL, | |
899 | ocelot_ptp_rdy_irq_handler, | |
900 | IRQF_ONESHOT, "ptp ready", | |
901 | ocelot); | |
902 | if (err) | |
6c30384e | 903 | goto out_free_devlink; |
4e3b0468 AT |
904 | |
905 | /* Both the PTP interrupt and the PTP bank are available */ | |
906 | ocelot->ptp = 1; | |
907 | } | |
908 | ||
a556c76a AB |
909 | ports = of_get_child_by_name(np, "ethernet-ports"); |
910 | if (!ports) { | |
7c411799 | 911 | dev_err(ocelot->dev, "no ethernet-ports child node found\n"); |
6c30384e VO |
912 | err = -ENODEV; |
913 | goto out_free_devlink; | |
a556c76a AB |
914 | } |
915 | ||
916 | ocelot->num_phys_ports = of_get_child_count(ports); | |
edd2410b | 917 | ocelot->num_flooding_pgids = 1; |
a556c76a | 918 | |
8551cdeb | 919 | ocelot->vcap = vsc7514_vcap_props; |
77043c37 XY |
920 | |
921 | ocelot->vcap_pol.base = VSC7514_VCAP_POLICER_BASE; | |
922 | ocelot->vcap_pol.max = VSC7514_VCAP_POLICER_MAX; | |
923 | ||
2d44b097 | 924 | ocelot->npi = -1; |
e0632940 | 925 | |
d1cc0e93 VO |
926 | err = ocelot_init(ocelot); |
927 | if (err) | |
928 | goto out_put_ports; | |
929 | ||
6c30384e VO |
930 | err = mscc_ocelot_init_ports(pdev, ports); |
931 | if (err) | |
932 | goto out_ocelot_devlink_unregister; | |
933 | ||
753a026c CL |
934 | if (ocelot->fdma) |
935 | ocelot_fdma_start(ocelot); | |
936 | ||
f59fd9ca VO |
937 | err = ocelot_devlink_sb_register(ocelot); |
938 | if (err) | |
939 | goto out_ocelot_release_ports; | |
940 | ||
2b49d128 YL |
941 | if (ocelot->ptp) { |
942 | err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info); | |
943 | if (err) { | |
944 | dev_err(ocelot->dev, | |
945 | "Timestamp initialization failed\n"); | |
946 | ocelot->ptp = 0; | |
947 | } | |
948 | } | |
949 | ||
a556c76a | 950 | register_netdevice_notifier(&ocelot_netdevice_nb); |
56da64bc | 951 | register_switchdev_notifier(&ocelot_switchdev_nb); |
0e332c85 | 952 | register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); |
a556c76a | 953 | |
f87675b8 | 954 | of_node_put(ports); |
67d78e7f | 955 | devlink_register(devlink); |
f87675b8 | 956 | |
a556c76a AB |
957 | dev_info(&pdev->dev, "Ocelot switch probed\n"); |
958 | ||
f87675b8 CJ |
959 | return 0; |
960 | ||
f59fd9ca VO |
961 | out_ocelot_release_ports: |
962 | mscc_ocelot_release_ports(ocelot); | |
963 | mscc_ocelot_teardown_devlink_ports(ocelot); | |
6c30384e | 964 | out_ocelot_devlink_unregister: |
f87675b8 | 965 | ocelot_deinit(ocelot); |
d2c50b1c WY |
966 | out_put_ports: |
967 | of_node_put(ports); | |
6c30384e VO |
968 | out_free_devlink: |
969 | devlink_free(devlink); | |
a556c76a AB |
970 | return err; |
971 | } | |
972 | ||
973 | static int mscc_ocelot_remove(struct platform_device *pdev) | |
974 | { | |
975 | struct ocelot *ocelot = platform_get_drvdata(pdev); | |
976 | ||
753a026c CL |
977 | if (ocelot->fdma) |
978 | ocelot_fdma_deinit(ocelot); | |
67d78e7f | 979 | devlink_unregister(ocelot->devlink); |
2b49d128 | 980 | ocelot_deinit_timestamp(ocelot); |
f59fd9ca | 981 | ocelot_devlink_sb_unregister(ocelot); |
22cdb493 | 982 | mscc_ocelot_release_ports(ocelot); |
6c30384e | 983 | mscc_ocelot_teardown_devlink_ports(ocelot); |
a556c76a | 984 | ocelot_deinit(ocelot); |
0e332c85 | 985 | unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb); |
56da64bc | 986 | unregister_switchdev_notifier(&ocelot_switchdev_nb); |
a556c76a | 987 | unregister_netdevice_notifier(&ocelot_netdevice_nb); |
6c30384e | 988 | devlink_free(ocelot->devlink); |
a556c76a AB |
989 | |
990 | return 0; | |
991 | } | |
992 | ||
993 | static struct platform_driver mscc_ocelot_driver = { | |
994 | .probe = mscc_ocelot_probe, | |
995 | .remove = mscc_ocelot_remove, | |
996 | .driver = { | |
997 | .name = "ocelot-switch", | |
998 | .of_match_table = mscc_ocelot_match, | |
999 | }, | |
1000 | }; | |
1001 | ||
1002 | module_platform_driver(mscc_ocelot_driver); | |
1003 | ||
1004 | MODULE_DESCRIPTION("Microsemi Ocelot switch driver"); | |
1005 | MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>"); | |
1006 | MODULE_LICENSE("Dual MIT/GPL"); |