]>
Commit | Line | Data |
---|---|---|
56051948 VO |
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* Copyright 2017 Microsemi Corporation | |
3 | * Copyright 2018-2019 NXP Semiconductors | |
4 | */ | |
bdeced75 | 5 | #include <linux/fsl/enetc_mdio.h> |
07d985ee | 6 | #include <soc/mscc/ocelot_vcap.h> |
56051948 VO |
7 | #include <soc/mscc/ocelot_sys.h> |
8 | #include <soc/mscc/ocelot.h> | |
9 | #include <linux/iopoll.h> | |
10 | #include <linux/pci.h> | |
11 | #include "felix.h" | |
12 | ||
07d985ee VO |
13 | #define VSC9959_VCAP_IS2_CNT 1024 |
14 | #define VSC9959_VCAP_IS2_ENTRY_WIDTH 376 | |
15 | #define VSC9959_VCAP_PORT_CNT 6 | |
16 | ||
bdeced75 VO |
17 | /* TODO: should find a better place for these */ |
18 | #define USXGMII_BMCR_RESET BIT(15) | |
19 | #define USXGMII_BMCR_AN_EN BIT(12) | |
20 | #define USXGMII_BMCR_RST_AN BIT(9) | |
21 | #define USXGMII_BMSR_LNKS(status) (((status) & GENMASK(2, 2)) >> 2) | |
22 | #define USXGMII_BMSR_AN_CMPL(status) (((status) & GENMASK(5, 5)) >> 5) | |
23 | #define USXGMII_ADVERTISE_LNKS(x) (((x) << 15) & BIT(15)) | |
24 | #define USXGMII_ADVERTISE_FDX BIT(12) | |
25 | #define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9)) | |
26 | #define USXGMII_LPA_LNKS(lpa) ((lpa) >> 15) | |
27 | #define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12) | |
28 | #define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9) | |
29 | ||
30 | enum usxgmii_speed { | |
31 | USXGMII_SPEED_10 = 0, | |
32 | USXGMII_SPEED_100 = 1, | |
33 | USXGMII_SPEED_1000 = 2, | |
34 | USXGMII_SPEED_2500 = 4, | |
35 | }; | |
36 | ||
56051948 VO |
37 | static const u32 vsc9959_ana_regmap[] = { |
38 | REG(ANA_ADVLEARN, 0x0089a0), | |
39 | REG(ANA_VLANMASK, 0x0089a4), | |
40 | REG_RESERVED(ANA_PORT_B_DOMAIN), | |
41 | REG(ANA_ANAGEFIL, 0x0089ac), | |
42 | REG(ANA_ANEVENTS, 0x0089b0), | |
43 | REG(ANA_STORMLIMIT_BURST, 0x0089b4), | |
44 | REG(ANA_STORMLIMIT_CFG, 0x0089b8), | |
45 | REG(ANA_ISOLATED_PORTS, 0x0089c8), | |
46 | REG(ANA_COMMUNITY_PORTS, 0x0089cc), | |
47 | REG(ANA_AUTOAGE, 0x0089d0), | |
48 | REG(ANA_MACTOPTIONS, 0x0089d4), | |
49 | REG(ANA_LEARNDISC, 0x0089d8), | |
50 | REG(ANA_AGENCTRL, 0x0089dc), | |
51 | REG(ANA_MIRRORPORTS, 0x0089e0), | |
52 | REG(ANA_EMIRRORPORTS, 0x0089e4), | |
53 | REG(ANA_FLOODING, 0x0089e8), | |
54 | REG(ANA_FLOODING_IPMC, 0x008a08), | |
55 | REG(ANA_SFLOW_CFG, 0x008a0c), | |
56 | REG(ANA_PORT_MODE, 0x008a28), | |
57 | REG(ANA_CUT_THRU_CFG, 0x008a48), | |
58 | REG(ANA_PGID_PGID, 0x008400), | |
59 | REG(ANA_TABLES_ANMOVED, 0x007f1c), | |
60 | REG(ANA_TABLES_MACHDATA, 0x007f20), | |
61 | REG(ANA_TABLES_MACLDATA, 0x007f24), | |
62 | REG(ANA_TABLES_STREAMDATA, 0x007f28), | |
63 | REG(ANA_TABLES_MACACCESS, 0x007f2c), | |
64 | REG(ANA_TABLES_MACTINDX, 0x007f30), | |
65 | REG(ANA_TABLES_VLANACCESS, 0x007f34), | |
66 | REG(ANA_TABLES_VLANTIDX, 0x007f38), | |
67 | REG(ANA_TABLES_ISDXACCESS, 0x007f3c), | |
68 | REG(ANA_TABLES_ISDXTIDX, 0x007f40), | |
69 | REG(ANA_TABLES_ENTRYLIM, 0x007f00), | |
70 | REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44), | |
71 | REG(ANA_TABLES_PTP_ID_LOW, 0x007f48), | |
72 | REG(ANA_TABLES_STREAMACCESS, 0x007f4c), | |
73 | REG(ANA_TABLES_STREAMTIDX, 0x007f50), | |
74 | REG(ANA_TABLES_SEQ_HISTORY, 0x007f54), | |
75 | REG(ANA_TABLES_SEQ_MASK, 0x007f58), | |
76 | REG(ANA_TABLES_SFID_MASK, 0x007f5c), | |
77 | REG(ANA_TABLES_SFIDACCESS, 0x007f60), | |
78 | REG(ANA_TABLES_SFIDTIDX, 0x007f64), | |
79 | REG(ANA_MSTI_STATE, 0x008600), | |
80 | REG(ANA_OAM_UPM_LM_CNT, 0x008000), | |
81 | REG(ANA_SG_ACCESS_CTRL, 0x008a64), | |
82 | REG(ANA_SG_CONFIG_REG_1, 0x007fb0), | |
83 | REG(ANA_SG_CONFIG_REG_2, 0x007fb4), | |
84 | REG(ANA_SG_CONFIG_REG_3, 0x007fb8), | |
85 | REG(ANA_SG_CONFIG_REG_4, 0x007fbc), | |
86 | REG(ANA_SG_CONFIG_REG_5, 0x007fc0), | |
87 | REG(ANA_SG_GCL_GS_CONFIG, 0x007f80), | |
88 | REG(ANA_SG_GCL_TI_CONFIG, 0x007f90), | |
89 | REG(ANA_SG_STATUS_REG_1, 0x008980), | |
90 | REG(ANA_SG_STATUS_REG_2, 0x008984), | |
91 | REG(ANA_SG_STATUS_REG_3, 0x008988), | |
92 | REG(ANA_PORT_VLAN_CFG, 0x007800), | |
93 | REG(ANA_PORT_DROP_CFG, 0x007804), | |
94 | REG(ANA_PORT_QOS_CFG, 0x007808), | |
95 | REG(ANA_PORT_VCAP_CFG, 0x00780c), | |
96 | REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810), | |
97 | REG(ANA_PORT_VCAP_S2_CFG, 0x00781c), | |
98 | REG(ANA_PORT_PCP_DEI_MAP, 0x007820), | |
99 | REG(ANA_PORT_CPU_FWD_CFG, 0x007860), | |
100 | REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864), | |
101 | REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868), | |
102 | REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c), | |
103 | REG(ANA_PORT_PORT_CFG, 0x007870), | |
104 | REG(ANA_PORT_POL_CFG, 0x007874), | |
105 | REG(ANA_PORT_PTP_CFG, 0x007878), | |
106 | REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c), | |
107 | REG(ANA_PORT_PTP_DLY2_CFG, 0x007880), | |
108 | REG(ANA_PORT_SFID_CFG, 0x007884), | |
109 | REG(ANA_PFC_PFC_CFG, 0x008800), | |
110 | REG_RESERVED(ANA_PFC_PFC_TIMER), | |
111 | REG_RESERVED(ANA_IPT_OAM_MEP_CFG), | |
112 | REG_RESERVED(ANA_IPT_IPT), | |
113 | REG_RESERVED(ANA_PPT_PPT), | |
114 | REG_RESERVED(ANA_FID_MAP_FID_MAP), | |
115 | REG(ANA_AGGR_CFG, 0x008a68), | |
116 | REG(ANA_CPUQ_CFG, 0x008a6c), | |
117 | REG_RESERVED(ANA_CPUQ_CFG2), | |
118 | REG(ANA_CPUQ_8021_CFG, 0x008a74), | |
119 | REG(ANA_DSCP_CFG, 0x008ab4), | |
120 | REG(ANA_DSCP_REWR_CFG, 0x008bb4), | |
121 | REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4), | |
122 | REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14), | |
123 | REG_RESERVED(ANA_VRAP_CFG), | |
124 | REG_RESERVED(ANA_VRAP_HDR_DATA), | |
125 | REG_RESERVED(ANA_VRAP_HDR_MASK), | |
126 | REG(ANA_DISCARD_CFG, 0x008c40), | |
127 | REG(ANA_FID_CFG, 0x008c44), | |
128 | REG(ANA_POL_PIR_CFG, 0x004000), | |
129 | REG(ANA_POL_CIR_CFG, 0x004004), | |
130 | REG(ANA_POL_MODE_CFG, 0x004008), | |
131 | REG(ANA_POL_PIR_STATE, 0x00400c), | |
132 | REG(ANA_POL_CIR_STATE, 0x004010), | |
133 | REG_RESERVED(ANA_POL_STATE), | |
134 | REG(ANA_POL_FLOWC, 0x008c48), | |
135 | REG(ANA_POL_HYST, 0x008cb4), | |
136 | REG_RESERVED(ANA_POL_MISC_CFG), | |
137 | }; | |
138 | ||
139 | static const u32 vsc9959_qs_regmap[] = { | |
140 | REG(QS_XTR_GRP_CFG, 0x000000), | |
141 | REG(QS_XTR_RD, 0x000008), | |
142 | REG(QS_XTR_FRM_PRUNING, 0x000010), | |
143 | REG(QS_XTR_FLUSH, 0x000018), | |
144 | REG(QS_XTR_DATA_PRESENT, 0x00001c), | |
145 | REG(QS_XTR_CFG, 0x000020), | |
146 | REG(QS_INJ_GRP_CFG, 0x000024), | |
147 | REG(QS_INJ_WR, 0x00002c), | |
148 | REG(QS_INJ_CTRL, 0x000034), | |
149 | REG(QS_INJ_STATUS, 0x00003c), | |
150 | REG(QS_INJ_ERR, 0x000040), | |
151 | REG_RESERVED(QS_INH_DBG), | |
152 | }; | |
153 | ||
154 | static const u32 vsc9959_s2_regmap[] = { | |
155 | REG(S2_CORE_UPDATE_CTRL, 0x000000), | |
156 | REG(S2_CORE_MV_CFG, 0x000004), | |
157 | REG(S2_CACHE_ENTRY_DAT, 0x000008), | |
158 | REG(S2_CACHE_MASK_DAT, 0x000108), | |
159 | REG(S2_CACHE_ACTION_DAT, 0x000208), | |
160 | REG(S2_CACHE_CNT_DAT, 0x000308), | |
161 | REG(S2_CACHE_TG_DAT, 0x000388), | |
162 | }; | |
163 | ||
164 | static const u32 vsc9959_qsys_regmap[] = { | |
165 | REG(QSYS_PORT_MODE, 0x00f460), | |
166 | REG(QSYS_SWITCH_PORT_MODE, 0x00f480), | |
167 | REG(QSYS_STAT_CNT_CFG, 0x00f49c), | |
168 | REG(QSYS_EEE_CFG, 0x00f4a0), | |
169 | REG(QSYS_EEE_THRES, 0x00f4b8), | |
170 | REG(QSYS_IGR_NO_SHARING, 0x00f4bc), | |
171 | REG(QSYS_EGR_NO_SHARING, 0x00f4c0), | |
172 | REG(QSYS_SW_STATUS, 0x00f4c4), | |
173 | REG(QSYS_EXT_CPU_CFG, 0x00f4e0), | |
174 | REG_RESERVED(QSYS_PAD_CFG), | |
175 | REG(QSYS_CPU_GROUP_MAP, 0x00f4e8), | |
176 | REG_RESERVED(QSYS_QMAP), | |
177 | REG_RESERVED(QSYS_ISDX_SGRP), | |
178 | REG_RESERVED(QSYS_TIMED_FRAME_ENTRY), | |
179 | REG(QSYS_TFRM_MISC, 0x00f50c), | |
180 | REG(QSYS_TFRM_PORT_DLY, 0x00f510), | |
181 | REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514), | |
182 | REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518), | |
183 | REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c), | |
184 | REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520), | |
185 | REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524), | |
186 | REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528), | |
187 | REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c), | |
188 | REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530), | |
189 | REG(QSYS_RED_PROFILE, 0x00f534), | |
190 | REG(QSYS_RES_QOS_MODE, 0x00f574), | |
191 | REG(QSYS_RES_CFG, 0x00c000), | |
192 | REG(QSYS_RES_STAT, 0x00c004), | |
193 | REG(QSYS_EGR_DROP_MODE, 0x00f578), | |
194 | REG(QSYS_EQ_CTRL, 0x00f57c), | |
195 | REG_RESERVED(QSYS_EVENTS_CORE), | |
196 | REG(QSYS_QMAXSDU_CFG_0, 0x00f584), | |
197 | REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0), | |
198 | REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc), | |
199 | REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8), | |
200 | REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4), | |
201 | REG(QSYS_QMAXSDU_CFG_5, 0x00f610), | |
202 | REG(QSYS_QMAXSDU_CFG_6, 0x00f62c), | |
203 | REG(QSYS_QMAXSDU_CFG_7, 0x00f648), | |
204 | REG(QSYS_PREEMPTION_CFG, 0x00f664), | |
205 | REG_RESERVED(QSYS_CIR_CFG), | |
206 | REG(QSYS_EIR_CFG, 0x000004), | |
207 | REG(QSYS_SE_CFG, 0x000008), | |
208 | REG(QSYS_SE_DWRR_CFG, 0x00000c), | |
209 | REG_RESERVED(QSYS_SE_CONNECT), | |
210 | REG(QSYS_SE_DLB_SENSE, 0x000040), | |
211 | REG(QSYS_CIR_STATE, 0x000044), | |
212 | REG(QSYS_EIR_STATE, 0x000048), | |
213 | REG_RESERVED(QSYS_SE_STATE), | |
214 | REG(QSYS_HSCH_MISC_CFG, 0x00f67c), | |
215 | REG(QSYS_TAG_CONFIG, 0x00f680), | |
216 | REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698), | |
217 | REG(QSYS_PORT_MAX_SDU, 0x00f69c), | |
218 | REG(QSYS_PARAM_CFG_REG_1, 0x00f440), | |
219 | REG(QSYS_PARAM_CFG_REG_2, 0x00f444), | |
220 | REG(QSYS_PARAM_CFG_REG_3, 0x00f448), | |
221 | REG(QSYS_PARAM_CFG_REG_4, 0x00f44c), | |
222 | REG(QSYS_PARAM_CFG_REG_5, 0x00f450), | |
223 | REG(QSYS_GCL_CFG_REG_1, 0x00f454), | |
224 | REG(QSYS_GCL_CFG_REG_2, 0x00f458), | |
225 | REG(QSYS_PARAM_STATUS_REG_1, 0x00f400), | |
226 | REG(QSYS_PARAM_STATUS_REG_2, 0x00f404), | |
227 | REG(QSYS_PARAM_STATUS_REG_3, 0x00f408), | |
228 | REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c), | |
229 | REG(QSYS_PARAM_STATUS_REG_5, 0x00f410), | |
230 | REG(QSYS_PARAM_STATUS_REG_6, 0x00f414), | |
231 | REG(QSYS_PARAM_STATUS_REG_7, 0x00f418), | |
232 | REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c), | |
233 | REG(QSYS_PARAM_STATUS_REG_9, 0x00f420), | |
234 | REG(QSYS_GCL_STATUS_REG_1, 0x00f424), | |
235 | REG(QSYS_GCL_STATUS_REG_2, 0x00f428), | |
236 | }; | |
237 | ||
238 | static const u32 vsc9959_rew_regmap[] = { | |
239 | REG(REW_PORT_VLAN_CFG, 0x000000), | |
240 | REG(REW_TAG_CFG, 0x000004), | |
241 | REG(REW_PORT_CFG, 0x000008), | |
242 | REG(REW_DSCP_CFG, 0x00000c), | |
243 | REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010), | |
244 | REG(REW_PTP_CFG, 0x000050), | |
245 | REG(REW_PTP_DLY1_CFG, 0x000054), | |
246 | REG(REW_RED_TAG_CFG, 0x000058), | |
247 | REG(REW_DSCP_REMAP_DP1_CFG, 0x000410), | |
248 | REG(REW_DSCP_REMAP_CFG, 0x000510), | |
249 | REG_RESERVED(REW_STAT_CFG), | |
250 | REG_RESERVED(REW_REW_STICKY), | |
251 | REG_RESERVED(REW_PPT), | |
252 | }; | |
253 | ||
254 | static const u32 vsc9959_sys_regmap[] = { | |
255 | REG(SYS_COUNT_RX_OCTETS, 0x000000), | |
256 | REG(SYS_COUNT_RX_MULTICAST, 0x000008), | |
257 | REG(SYS_COUNT_RX_SHORTS, 0x000010), | |
258 | REG(SYS_COUNT_RX_FRAGMENTS, 0x000014), | |
259 | REG(SYS_COUNT_RX_JABBERS, 0x000018), | |
260 | REG(SYS_COUNT_RX_64, 0x000024), | |
261 | REG(SYS_COUNT_RX_65_127, 0x000028), | |
262 | REG(SYS_COUNT_RX_128_255, 0x00002c), | |
263 | REG(SYS_COUNT_RX_256_1023, 0x000030), | |
264 | REG(SYS_COUNT_RX_1024_1526, 0x000034), | |
265 | REG(SYS_COUNT_RX_1527_MAX, 0x000038), | |
266 | REG(SYS_COUNT_RX_LONGS, 0x000044), | |
267 | REG(SYS_COUNT_TX_OCTETS, 0x000200), | |
268 | REG(SYS_COUNT_TX_COLLISION, 0x000210), | |
269 | REG(SYS_COUNT_TX_DROPS, 0x000214), | |
270 | REG(SYS_COUNT_TX_64, 0x00021c), | |
271 | REG(SYS_COUNT_TX_65_127, 0x000220), | |
272 | REG(SYS_COUNT_TX_128_511, 0x000224), | |
273 | REG(SYS_COUNT_TX_512_1023, 0x000228), | |
274 | REG(SYS_COUNT_TX_1024_1526, 0x00022c), | |
275 | REG(SYS_COUNT_TX_1527_MAX, 0x000230), | |
276 | REG(SYS_COUNT_TX_AGING, 0x000278), | |
277 | REG(SYS_RESET_CFG, 0x000e00), | |
278 | REG(SYS_SR_ETYPE_CFG, 0x000e04), | |
279 | REG(SYS_VLAN_ETYPE_CFG, 0x000e08), | |
280 | REG(SYS_PORT_MODE, 0x000e0c), | |
281 | REG(SYS_FRONT_PORT_MODE, 0x000e2c), | |
282 | REG(SYS_FRM_AGING, 0x000e44), | |
283 | REG(SYS_STAT_CFG, 0x000e48), | |
284 | REG(SYS_SW_STATUS, 0x000e4c), | |
285 | REG_RESERVED(SYS_MISC_CFG), | |
286 | REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c), | |
287 | REG(SYS_REW_MAC_LOW_CFG, 0x000e84), | |
288 | REG(SYS_TIMESTAMP_OFFSET, 0x000e9c), | |
289 | REG(SYS_PAUSE_CFG, 0x000ea0), | |
290 | REG(SYS_PAUSE_TOT_CFG, 0x000ebc), | |
291 | REG(SYS_ATOP, 0x000ec0), | |
292 | REG(SYS_ATOP_TOT_CFG, 0x000edc), | |
293 | REG(SYS_MAC_FC_CFG, 0x000ee0), | |
294 | REG(SYS_MMGT, 0x000ef8), | |
295 | REG_RESERVED(SYS_MMGT_FAST), | |
296 | REG_RESERVED(SYS_EVENTS_DIF), | |
297 | REG_RESERVED(SYS_EVENTS_CORE), | |
298 | REG_RESERVED(SYS_CNT), | |
299 | REG(SYS_PTP_STATUS, 0x000f14), | |
300 | REG(SYS_PTP_TXSTAMP, 0x000f18), | |
301 | REG(SYS_PTP_NXT, 0x000f1c), | |
302 | REG(SYS_PTP_CFG, 0x000f20), | |
303 | REG(SYS_RAM_INIT, 0x000f24), | |
304 | REG_RESERVED(SYS_CM_ADDR), | |
305 | REG_RESERVED(SYS_CM_DATA_WR), | |
306 | REG_RESERVED(SYS_CM_DATA_RD), | |
307 | REG_RESERVED(SYS_CM_OP), | |
308 | REG_RESERVED(SYS_CM_DATA), | |
309 | }; | |
310 | ||
5df66c48 YL |
311 | static const u32 vsc9959_ptp_regmap[] = { |
312 | REG(PTP_PIN_CFG, 0x000000), | |
313 | REG(PTP_PIN_TOD_SEC_MSB, 0x000004), | |
314 | REG(PTP_PIN_TOD_SEC_LSB, 0x000008), | |
315 | REG(PTP_PIN_TOD_NSEC, 0x00000c), | |
316 | REG(PTP_CFG_MISC, 0x0000a0), | |
317 | REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), | |
318 | REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), | |
319 | }; | |
320 | ||
56051948 VO |
321 | static const u32 vsc9959_gcb_regmap[] = { |
322 | REG(GCB_SOFT_RST, 0x000004), | |
323 | }; | |
324 | ||
325 | static const u32 *vsc9959_regmap[] = { | |
326 | [ANA] = vsc9959_ana_regmap, | |
327 | [QS] = vsc9959_qs_regmap, | |
328 | [QSYS] = vsc9959_qsys_regmap, | |
329 | [REW] = vsc9959_rew_regmap, | |
330 | [SYS] = vsc9959_sys_regmap, | |
331 | [S2] = vsc9959_s2_regmap, | |
5df66c48 | 332 | [PTP] = vsc9959_ptp_regmap, |
56051948 VO |
333 | [GCB] = vsc9959_gcb_regmap, |
334 | }; | |
335 | ||
336 | /* Addresses are relative to the PCI device's base address and | |
337 | * will be fixed up at ioremap time. | |
338 | */ | |
339 | static struct resource vsc9959_target_io_res[] = { | |
340 | [ANA] = { | |
341 | .start = 0x0280000, | |
342 | .end = 0x028ffff, | |
343 | .name = "ana", | |
344 | }, | |
345 | [QS] = { | |
346 | .start = 0x0080000, | |
347 | .end = 0x00800ff, | |
348 | .name = "qs", | |
349 | }, | |
350 | [QSYS] = { | |
351 | .start = 0x0200000, | |
352 | .end = 0x021ffff, | |
353 | .name = "qsys", | |
354 | }, | |
355 | [REW] = { | |
356 | .start = 0x0030000, | |
357 | .end = 0x003ffff, | |
358 | .name = "rew", | |
359 | }, | |
360 | [SYS] = { | |
361 | .start = 0x0010000, | |
362 | .end = 0x001ffff, | |
363 | .name = "sys", | |
364 | }, | |
365 | [S2] = { | |
366 | .start = 0x0060000, | |
367 | .end = 0x00603ff, | |
368 | .name = "s2", | |
369 | }, | |
5df66c48 YL |
370 | [PTP] = { |
371 | .start = 0x0090000, | |
372 | .end = 0x00900cb, | |
373 | .name = "ptp", | |
374 | }, | |
56051948 VO |
375 | [GCB] = { |
376 | .start = 0x0070000, | |
377 | .end = 0x00701ff, | |
378 | .name = "devcpu_gcb", | |
379 | }, | |
380 | }; | |
381 | ||
382 | static struct resource vsc9959_port_io_res[] = { | |
383 | { | |
384 | .start = 0x0100000, | |
385 | .end = 0x010ffff, | |
386 | .name = "port0", | |
387 | }, | |
388 | { | |
389 | .start = 0x0110000, | |
390 | .end = 0x011ffff, | |
391 | .name = "port1", | |
392 | }, | |
393 | { | |
394 | .start = 0x0120000, | |
395 | .end = 0x012ffff, | |
396 | .name = "port2", | |
397 | }, | |
398 | { | |
399 | .start = 0x0130000, | |
400 | .end = 0x013ffff, | |
401 | .name = "port3", | |
402 | }, | |
403 | { | |
404 | .start = 0x0140000, | |
405 | .end = 0x014ffff, | |
406 | .name = "port4", | |
407 | }, | |
408 | { | |
409 | .start = 0x0150000, | |
410 | .end = 0x015ffff, | |
411 | .name = "port5", | |
412 | }, | |
413 | }; | |
414 | ||
bdeced75 VO |
415 | /* Port MAC 0 Internal MDIO bus through which the SerDes acting as an |
416 | * SGMII/QSGMII MAC PCS can be found. | |
417 | */ | |
418 | static struct resource vsc9959_imdio_res = { | |
419 | .start = 0x8030, | |
420 | .end = 0x8040, | |
421 | .name = "imdio", | |
422 | }; | |
423 | ||
56051948 VO |
424 | static const struct reg_field vsc9959_regfields[] = { |
425 | [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), | |
426 | [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), | |
427 | [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30), | |
428 | [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26), | |
429 | [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24), | |
430 | [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23), | |
431 | [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22), | |
432 | [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21), | |
433 | [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20), | |
434 | [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19), | |
435 | [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18), | |
436 | [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17), | |
437 | [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15), | |
438 | [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14), | |
439 | [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13), | |
440 | [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12), | |
441 | [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11), | |
442 | [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10), | |
443 | [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9), | |
444 | [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8), | |
445 | [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7), | |
446 | [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), | |
447 | [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), | |
448 | [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4), | |
449 | [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3), | |
450 | [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2), | |
451 | [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1), | |
452 | [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0), | |
453 | [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16), | |
454 | [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12), | |
455 | [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10), | |
456 | [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0), | |
457 | [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0), | |
458 | }; | |
459 | ||
460 | static const struct ocelot_stat_layout vsc9959_stats_layout[] = { | |
461 | { .offset = 0x00, .name = "rx_octets", }, | |
462 | { .offset = 0x01, .name = "rx_unicast", }, | |
463 | { .offset = 0x02, .name = "rx_multicast", }, | |
464 | { .offset = 0x03, .name = "rx_broadcast", }, | |
465 | { .offset = 0x04, .name = "rx_shorts", }, | |
466 | { .offset = 0x05, .name = "rx_fragments", }, | |
467 | { .offset = 0x06, .name = "rx_jabbers", }, | |
468 | { .offset = 0x07, .name = "rx_crc_align_errs", }, | |
469 | { .offset = 0x08, .name = "rx_sym_errs", }, | |
470 | { .offset = 0x09, .name = "rx_frames_below_65_octets", }, | |
471 | { .offset = 0x0A, .name = "rx_frames_65_to_127_octets", }, | |
472 | { .offset = 0x0B, .name = "rx_frames_128_to_255_octets", }, | |
473 | { .offset = 0x0C, .name = "rx_frames_256_to_511_octets", }, | |
474 | { .offset = 0x0D, .name = "rx_frames_512_to_1023_octets", }, | |
475 | { .offset = 0x0E, .name = "rx_frames_1024_to_1526_octets", }, | |
476 | { .offset = 0x0F, .name = "rx_frames_over_1526_octets", }, | |
477 | { .offset = 0x10, .name = "rx_pause", }, | |
478 | { .offset = 0x11, .name = "rx_control", }, | |
479 | { .offset = 0x12, .name = "rx_longs", }, | |
480 | { .offset = 0x13, .name = "rx_classified_drops", }, | |
481 | { .offset = 0x14, .name = "rx_red_prio_0", }, | |
482 | { .offset = 0x15, .name = "rx_red_prio_1", }, | |
483 | { .offset = 0x16, .name = "rx_red_prio_2", }, | |
484 | { .offset = 0x17, .name = "rx_red_prio_3", }, | |
485 | { .offset = 0x18, .name = "rx_red_prio_4", }, | |
486 | { .offset = 0x19, .name = "rx_red_prio_5", }, | |
487 | { .offset = 0x1A, .name = "rx_red_prio_6", }, | |
488 | { .offset = 0x1B, .name = "rx_red_prio_7", }, | |
489 | { .offset = 0x1C, .name = "rx_yellow_prio_0", }, | |
490 | { .offset = 0x1D, .name = "rx_yellow_prio_1", }, | |
491 | { .offset = 0x1E, .name = "rx_yellow_prio_2", }, | |
492 | { .offset = 0x1F, .name = "rx_yellow_prio_3", }, | |
493 | { .offset = 0x20, .name = "rx_yellow_prio_4", }, | |
494 | { .offset = 0x21, .name = "rx_yellow_prio_5", }, | |
495 | { .offset = 0x22, .name = "rx_yellow_prio_6", }, | |
496 | { .offset = 0x23, .name = "rx_yellow_prio_7", }, | |
497 | { .offset = 0x24, .name = "rx_green_prio_0", }, | |
498 | { .offset = 0x25, .name = "rx_green_prio_1", }, | |
499 | { .offset = 0x26, .name = "rx_green_prio_2", }, | |
500 | { .offset = 0x27, .name = "rx_green_prio_3", }, | |
501 | { .offset = 0x28, .name = "rx_green_prio_4", }, | |
502 | { .offset = 0x29, .name = "rx_green_prio_5", }, | |
503 | { .offset = 0x2A, .name = "rx_green_prio_6", }, | |
504 | { .offset = 0x2B, .name = "rx_green_prio_7", }, | |
505 | { .offset = 0x80, .name = "tx_octets", }, | |
506 | { .offset = 0x81, .name = "tx_unicast", }, | |
507 | { .offset = 0x82, .name = "tx_multicast", }, | |
508 | { .offset = 0x83, .name = "tx_broadcast", }, | |
509 | { .offset = 0x84, .name = "tx_collision", }, | |
510 | { .offset = 0x85, .name = "tx_drops", }, | |
511 | { .offset = 0x86, .name = "tx_pause", }, | |
512 | { .offset = 0x87, .name = "tx_frames_below_65_octets", }, | |
513 | { .offset = 0x88, .name = "tx_frames_65_to_127_octets", }, | |
514 | { .offset = 0x89, .name = "tx_frames_128_255_octets", }, | |
515 | { .offset = 0x8B, .name = "tx_frames_256_511_octets", }, | |
516 | { .offset = 0x8C, .name = "tx_frames_1024_1526_octets", }, | |
517 | { .offset = 0x8D, .name = "tx_frames_over_1526_octets", }, | |
518 | { .offset = 0x8E, .name = "tx_yellow_prio_0", }, | |
519 | { .offset = 0x8F, .name = "tx_yellow_prio_1", }, | |
520 | { .offset = 0x90, .name = "tx_yellow_prio_2", }, | |
521 | { .offset = 0x91, .name = "tx_yellow_prio_3", }, | |
522 | { .offset = 0x92, .name = "tx_yellow_prio_4", }, | |
523 | { .offset = 0x93, .name = "tx_yellow_prio_5", }, | |
524 | { .offset = 0x94, .name = "tx_yellow_prio_6", }, | |
525 | { .offset = 0x95, .name = "tx_yellow_prio_7", }, | |
526 | { .offset = 0x96, .name = "tx_green_prio_0", }, | |
527 | { .offset = 0x97, .name = "tx_green_prio_1", }, | |
528 | { .offset = 0x98, .name = "tx_green_prio_2", }, | |
529 | { .offset = 0x99, .name = "tx_green_prio_3", }, | |
530 | { .offset = 0x9A, .name = "tx_green_prio_4", }, | |
531 | { .offset = 0x9B, .name = "tx_green_prio_5", }, | |
532 | { .offset = 0x9C, .name = "tx_green_prio_6", }, | |
533 | { .offset = 0x9D, .name = "tx_green_prio_7", }, | |
534 | { .offset = 0x9E, .name = "tx_aged", }, | |
535 | { .offset = 0x100, .name = "drop_local", }, | |
536 | { .offset = 0x101, .name = "drop_tail", }, | |
537 | { .offset = 0x102, .name = "drop_yellow_prio_0", }, | |
538 | { .offset = 0x103, .name = "drop_yellow_prio_1", }, | |
539 | { .offset = 0x104, .name = "drop_yellow_prio_2", }, | |
540 | { .offset = 0x105, .name = "drop_yellow_prio_3", }, | |
541 | { .offset = 0x106, .name = "drop_yellow_prio_4", }, | |
542 | { .offset = 0x107, .name = "drop_yellow_prio_5", }, | |
543 | { .offset = 0x108, .name = "drop_yellow_prio_6", }, | |
544 | { .offset = 0x109, .name = "drop_yellow_prio_7", }, | |
545 | { .offset = 0x10A, .name = "drop_green_prio_0", }, | |
546 | { .offset = 0x10B, .name = "drop_green_prio_1", }, | |
547 | { .offset = 0x10C, .name = "drop_green_prio_2", }, | |
548 | { .offset = 0x10D, .name = "drop_green_prio_3", }, | |
549 | { .offset = 0x10E, .name = "drop_green_prio_4", }, | |
550 | { .offset = 0x10F, .name = "drop_green_prio_5", }, | |
551 | { .offset = 0x110, .name = "drop_green_prio_6", }, | |
552 | { .offset = 0x111, .name = "drop_green_prio_7", }, | |
553 | }; | |
554 | ||
07d985ee VO |
555 | struct vcap_field vsc9959_vcap_is2_keys[] = { |
556 | /* Common: 41 bits */ | |
557 | [VCAP_IS2_TYPE] = { 0, 4}, | |
558 | [VCAP_IS2_HK_FIRST] = { 4, 1}, | |
559 | [VCAP_IS2_HK_PAG] = { 5, 8}, | |
560 | [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 7}, | |
561 | [VCAP_IS2_HK_RSV2] = { 20, 1}, | |
562 | [VCAP_IS2_HK_HOST_MATCH] = { 21, 1}, | |
563 | [VCAP_IS2_HK_L2_MC] = { 22, 1}, | |
564 | [VCAP_IS2_HK_L2_BC] = { 23, 1}, | |
565 | [VCAP_IS2_HK_VLAN_TAGGED] = { 24, 1}, | |
566 | [VCAP_IS2_HK_VID] = { 25, 12}, | |
567 | [VCAP_IS2_HK_DEI] = { 37, 1}, | |
568 | [VCAP_IS2_HK_PCP] = { 38, 3}, | |
569 | /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */ | |
570 | [VCAP_IS2_HK_L2_DMAC] = { 41, 48}, | |
571 | [VCAP_IS2_HK_L2_SMAC] = { 89, 48}, | |
572 | /* MAC_ETYPE (TYPE=000) */ | |
573 | [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = {137, 16}, | |
574 | [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = {153, 16}, | |
575 | [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = {169, 8}, | |
576 | [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = {177, 3}, | |
577 | /* MAC_LLC (TYPE=001) */ | |
578 | [VCAP_IS2_HK_MAC_LLC_L2_LLC] = {137, 40}, | |
579 | /* MAC_SNAP (TYPE=010) */ | |
580 | [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = {137, 40}, | |
581 | /* MAC_ARP (TYPE=011) */ | |
582 | [VCAP_IS2_HK_MAC_ARP_SMAC] = { 41, 48}, | |
583 | [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 89, 1}, | |
584 | [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 90, 1}, | |
585 | [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 91, 1}, | |
586 | [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 92, 1}, | |
587 | [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 93, 1}, | |
588 | [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 94, 1}, | |
589 | [VCAP_IS2_HK_MAC_ARP_OPCODE] = { 95, 2}, | |
590 | [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 97, 32}, | |
591 | [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = {129, 32}, | |
592 | [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = {161, 1}, | |
593 | /* IP4_TCP_UDP / IP4_OTHER common */ | |
594 | [VCAP_IS2_HK_IP4] = { 41, 1}, | |
595 | [VCAP_IS2_HK_L3_FRAGMENT] = { 42, 1}, | |
596 | [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 43, 1}, | |
597 | [VCAP_IS2_HK_L3_OPTIONS] = { 44, 1}, | |
598 | [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 45, 1}, | |
599 | [VCAP_IS2_HK_L3_TOS] = { 46, 8}, | |
600 | [VCAP_IS2_HK_L3_IP4_DIP] = { 54, 32}, | |
601 | [VCAP_IS2_HK_L3_IP4_SIP] = { 86, 32}, | |
602 | [VCAP_IS2_HK_DIP_EQ_SIP] = {118, 1}, | |
603 | /* IP4_TCP_UDP (TYPE=100) */ | |
604 | [VCAP_IS2_HK_TCP] = {119, 1}, | |
605 | [VCAP_IS2_HK_L4_SPORT] = {120, 16}, | |
606 | [VCAP_IS2_HK_L4_DPORT] = {136, 16}, | |
607 | [VCAP_IS2_HK_L4_RNG] = {152, 8}, | |
608 | [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = {160, 1}, | |
609 | [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = {161, 1}, | |
610 | [VCAP_IS2_HK_L4_URG] = {162, 1}, | |
611 | [VCAP_IS2_HK_L4_ACK] = {163, 1}, | |
612 | [VCAP_IS2_HK_L4_PSH] = {164, 1}, | |
613 | [VCAP_IS2_HK_L4_RST] = {165, 1}, | |
614 | [VCAP_IS2_HK_L4_SYN] = {166, 1}, | |
615 | [VCAP_IS2_HK_L4_FIN] = {167, 1}, | |
616 | [VCAP_IS2_HK_L4_1588_DOM] = {168, 8}, | |
617 | [VCAP_IS2_HK_L4_1588_VER] = {176, 4}, | |
618 | /* IP4_OTHER (TYPE=101) */ | |
619 | [VCAP_IS2_HK_IP4_L3_PROTO] = {119, 8}, | |
620 | [VCAP_IS2_HK_L3_PAYLOAD] = {127, 56}, | |
621 | /* IP6_STD (TYPE=110) */ | |
622 | [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 41, 1}, | |
623 | [VCAP_IS2_HK_L3_IP6_SIP] = { 42, 128}, | |
624 | [VCAP_IS2_HK_IP6_L3_PROTO] = {170, 8}, | |
625 | /* OAM (TYPE=111) */ | |
626 | [VCAP_IS2_HK_OAM_MEL_FLAGS] = {137, 7}, | |
627 | [VCAP_IS2_HK_OAM_VER] = {144, 5}, | |
628 | [VCAP_IS2_HK_OAM_OPCODE] = {149, 8}, | |
629 | [VCAP_IS2_HK_OAM_FLAGS] = {157, 8}, | |
630 | [VCAP_IS2_HK_OAM_MEPID] = {165, 16}, | |
631 | [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = {181, 1}, | |
632 | [VCAP_IS2_HK_OAM_IS_Y1731] = {182, 1}, | |
633 | }; | |
634 | ||
635 | struct vcap_field vsc9959_vcap_is2_actions[] = { | |
636 | [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1}, | |
637 | [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1}, | |
638 | [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3}, | |
639 | [VCAP_IS2_ACT_MASK_MODE] = { 5, 2}, | |
640 | [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1}, | |
641 | [VCAP_IS2_ACT_LRN_DIS] = { 8, 1}, | |
642 | [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1}, | |
643 | [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9}, | |
644 | [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1}, | |
645 | [VCAP_IS2_ACT_PORT_MASK] = { 20, 11}, | |
646 | [VCAP_IS2_ACT_REW_OP] = { 31, 9}, | |
647 | [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1}, | |
648 | [VCAP_IS2_ACT_RSV] = { 41, 2}, | |
649 | [VCAP_IS2_ACT_ACL_ID] = { 43, 6}, | |
650 | [VCAP_IS2_ACT_HIT_CNT] = { 49, 32}, | |
651 | }; | |
652 | ||
653 | static const struct vcap_props vsc9959_vcap_props[] = { | |
654 | [VCAP_IS2] = { | |
655 | .tg_width = 2, | |
656 | .sw_count = 4, | |
657 | .entry_count = VSC9959_VCAP_IS2_CNT, | |
658 | .entry_width = VSC9959_VCAP_IS2_ENTRY_WIDTH, | |
659 | .action_count = VSC9959_VCAP_IS2_CNT + | |
660 | VSC9959_VCAP_PORT_CNT + 2, | |
661 | .action_width = 89, | |
662 | .action_type_width = 1, | |
663 | .action_table = { | |
664 | [IS2_ACTION_TYPE_NORMAL] = { | |
665 | .width = 44, | |
666 | .count = 2 | |
667 | }, | |
668 | [IS2_ACTION_TYPE_SMAC_SIP] = { | |
669 | .width = 6, | |
670 | .count = 4 | |
671 | }, | |
672 | }, | |
673 | .counter_words = 4, | |
674 | .counter_width = 32, | |
675 | }, | |
676 | }; | |
677 | ||
56051948 VO |
678 | #define VSC9959_INIT_TIMEOUT 50000 |
679 | #define VSC9959_GCB_RST_SLEEP 100 | |
680 | #define VSC9959_SYS_RAMINIT_SLEEP 80 | |
681 | ||
682 | static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) | |
683 | { | |
684 | int val; | |
685 | ||
686 | regmap_field_read(ocelot->regfields[GCB_SOFT_RST_SWC_RST], &val); | |
687 | ||
688 | return val; | |
689 | } | |
690 | ||
691 | static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) | |
692 | { | |
693 | return ocelot_read(ocelot, SYS_RAM_INIT); | |
694 | } | |
695 | ||
696 | static int vsc9959_reset(struct ocelot *ocelot) | |
697 | { | |
698 | int val, err; | |
699 | ||
700 | /* soft-reset the switch core */ | |
701 | regmap_field_write(ocelot->regfields[GCB_SOFT_RST_SWC_RST], 1); | |
702 | ||
703 | err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, | |
704 | VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); | |
705 | if (err) { | |
706 | dev_err(ocelot->dev, "timeout: switch core reset\n"); | |
707 | return err; | |
708 | } | |
709 | ||
710 | /* initialize switch mem ~40us */ | |
711 | ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT); | |
712 | err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val, | |
713 | VSC9959_SYS_RAMINIT_SLEEP, | |
714 | VSC9959_INIT_TIMEOUT); | |
715 | if (err) { | |
716 | dev_err(ocelot->dev, "timeout: switch sram init\n"); | |
717 | return err; | |
718 | } | |
719 | ||
720 | /* enable switch core */ | |
721 | regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); | |
722 | ||
723 | return 0; | |
724 | } | |
725 | ||
bdeced75 VO |
726 | static void vsc9959_pcs_an_restart_sgmii(struct phy_device *pcs) |
727 | { | |
728 | phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART); | |
729 | } | |
730 | ||
731 | static void vsc9959_pcs_an_restart_usxgmii(struct phy_device *pcs) | |
732 | { | |
733 | phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR, | |
734 | USXGMII_BMCR_RESET | | |
735 | USXGMII_BMCR_AN_EN | | |
736 | USXGMII_BMCR_RST_AN); | |
737 | } | |
738 | ||
739 | static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port) | |
740 | { | |
741 | struct felix *felix = ocelot_to_felix(ocelot); | |
742 | struct phy_device *pcs = felix->pcs[port]; | |
743 | ||
744 | if (!pcs) | |
745 | return; | |
746 | ||
747 | switch (pcs->interface) { | |
748 | case PHY_INTERFACE_MODE_SGMII: | |
749 | case PHY_INTERFACE_MODE_QSGMII: | |
750 | vsc9959_pcs_an_restart_sgmii(pcs); | |
751 | break; | |
752 | case PHY_INTERFACE_MODE_USXGMII: | |
753 | vsc9959_pcs_an_restart_usxgmii(pcs); | |
754 | break; | |
755 | default: | |
756 | dev_err(ocelot->dev, "Invalid PCS interface type %s\n", | |
757 | phy_modes(pcs->interface)); | |
758 | break; | |
759 | } | |
760 | } | |
761 | ||
762 | /* We enable SGMII AN only when the PHY has managed = "in-band-status" in the | |
763 | * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed | |
764 | * into the PCS, which is retrieved out-of-band over MDIO. This also has the | |
765 | * benefit of working with SGMII fixed-links, like downstream switches, where | |
766 | * both link partners attempt to operate as AN slaves and therefore AN never | |
767 | * completes. But it also has the disadvantage that some PHY chips don't pass | |
768 | * traffic if SGMII AN is enabled but not completed (acknowledged by us), so | |
769 | * setting MLO_AN_INBAND is actually required for those. | |
770 | */ | |
771 | static void vsc9959_pcs_init_sgmii(struct phy_device *pcs, | |
772 | unsigned int link_an_mode, | |
773 | const struct phylink_link_state *state) | |
774 | { | |
775 | if (link_an_mode == MLO_AN_INBAND) { | |
8c6123e1 AM |
776 | int bmsr, bmcr; |
777 | ||
778 | /* Some PHYs like VSC8234 don't like it when AN restarts on | |
779 | * their system side and they restart line side AN too, going | |
780 | * into an endless link up/down loop. Don't restart PCS AN if | |
781 | * link is up already. | |
782 | * We do check that AN is enabled just in case this is the 1st | |
783 | * call, PCS detects a carrier but AN is disabled from power on | |
784 | * or by boot loader. | |
785 | */ | |
786 | bmcr = phy_read(pcs, MII_BMCR); | |
787 | if (bmcr < 0) | |
788 | return; | |
789 | ||
790 | bmsr = phy_read(pcs, MII_BMSR); | |
791 | if (bmsr < 0) | |
792 | return; | |
793 | ||
794 | if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_LSTATUS)) | |
795 | return; | |
796 | ||
bdeced75 VO |
797 | /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001 |
798 | * for the MAC PCS in order to acknowledge the AN. | |
799 | */ | |
800 | phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | | |
801 | ADVERTISE_LPACK); | |
802 | ||
803 | phy_write(pcs, ENETC_PCS_IF_MODE, | |
804 | ENETC_PCS_IF_MODE_SGMII_EN | | |
805 | ENETC_PCS_IF_MODE_USE_SGMII_AN); | |
806 | ||
807 | /* Adjust link timer for SGMII */ | |
808 | phy_write(pcs, ENETC_PCS_LINK_TIMER1, | |
809 | ENETC_PCS_LINK_TIMER1_VAL); | |
810 | phy_write(pcs, ENETC_PCS_LINK_TIMER2, | |
811 | ENETC_PCS_LINK_TIMER2_VAL); | |
812 | ||
813 | phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE); | |
814 | } else { | |
815 | int speed; | |
816 | ||
817 | if (state->duplex == DUPLEX_HALF) { | |
818 | phydev_err(pcs, "Half duplex not supported\n"); | |
819 | return; | |
820 | } | |
821 | switch (state->speed) { | |
822 | case SPEED_1000: | |
823 | speed = ENETC_PCS_SPEED_1000; | |
824 | break; | |
825 | case SPEED_100: | |
826 | speed = ENETC_PCS_SPEED_100; | |
827 | break; | |
828 | case SPEED_10: | |
829 | speed = ENETC_PCS_SPEED_10; | |
830 | break; | |
831 | case SPEED_UNKNOWN: | |
832 | /* Silently don't do anything */ | |
833 | return; | |
834 | default: | |
835 | phydev_err(pcs, "Invalid PCS speed %d\n", state->speed); | |
836 | return; | |
837 | } | |
838 | ||
839 | phy_write(pcs, ENETC_PCS_IF_MODE, | |
840 | ENETC_PCS_IF_MODE_SGMII_EN | | |
841 | ENETC_PCS_IF_MODE_SGMII_SPEED(speed)); | |
842 | ||
843 | /* Yes, not a mistake: speed is given by IF_MODE. */ | |
844 | phy_write(pcs, MII_BMCR, BMCR_RESET | | |
845 | BMCR_SPEED1000 | | |
846 | BMCR_FULLDPLX); | |
847 | } | |
848 | } | |
849 | ||
850 | /* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane | |
851 | * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have | |
852 | * auto-negotiation of any link parameters. Electrically it is compatible with | |
853 | * a single lane of XAUI. | |
854 | * The hardware reference manual wants to call this mode SGMII, but it isn't | |
855 | * really, since the fundamental features of SGMII: | |
856 | * - Downgrading the link speed by duplicating symbols | |
857 | * - Auto-negotiation | |
858 | * are not there. | |
859 | * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers | |
860 | * because the clock frequency is actually given by a PLL configured in the | |
861 | * Reset Configuration Word (RCW). | |
862 | * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o | |
863 | * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a | |
864 | * lower link speed on line side, the system-side interface remains fixed at | |
865 | * 2500 Mbps and we do rate adaptation through pause frames. | |
866 | */ | |
867 | static void vsc9959_pcs_init_2500basex(struct phy_device *pcs, | |
868 | unsigned int link_an_mode, | |
869 | const struct phylink_link_state *state) | |
870 | { | |
871 | if (link_an_mode == MLO_AN_INBAND) { | |
872 | phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n"); | |
873 | return; | |
874 | } | |
875 | ||
876 | phy_write(pcs, ENETC_PCS_IF_MODE, | |
877 | ENETC_PCS_IF_MODE_SGMII_EN | | |
878 | ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500)); | |
879 | ||
880 | phy_write(pcs, MII_BMCR, BMCR_SPEED1000 | | |
881 | BMCR_FULLDPLX | | |
882 | BMCR_RESET); | |
883 | } | |
884 | ||
885 | static void vsc9959_pcs_init_usxgmii(struct phy_device *pcs, | |
886 | unsigned int link_an_mode, | |
887 | const struct phylink_link_state *state) | |
888 | { | |
889 | if (link_an_mode != MLO_AN_INBAND) { | |
890 | phydev_err(pcs, "USXGMII only supports in-band AN for now\n"); | |
891 | return; | |
892 | } | |
893 | ||
894 | /* Configure device ability for the USXGMII Replicator */ | |
895 | phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE, | |
896 | USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) | | |
897 | USXGMII_ADVERTISE_LNKS(1) | | |
898 | ADVERTISE_SGMII | | |
899 | ADVERTISE_LPACK | | |
900 | USXGMII_ADVERTISE_FDX); | |
901 | } | |
902 | ||
903 | static void vsc9959_pcs_init(struct ocelot *ocelot, int port, | |
904 | unsigned int link_an_mode, | |
905 | const struct phylink_link_state *state) | |
906 | { | |
907 | struct felix *felix = ocelot_to_felix(ocelot); | |
908 | struct phy_device *pcs = felix->pcs[port]; | |
909 | ||
910 | if (!pcs) | |
911 | return; | |
912 | ||
913 | /* The PCS does not implement the BMSR register fully, so capability | |
914 | * detection via genphy_read_abilities does not work. Since we can get | |
915 | * the PHY config word from the LPA register though, there is still | |
916 | * value in using the generic phy_resolve_aneg_linkmode function. So | |
917 | * populate the supported and advertising link modes manually here. | |
918 | */ | |
919 | linkmode_set_bit_array(phy_basic_ports_array, | |
920 | ARRAY_SIZE(phy_basic_ports_array), | |
921 | pcs->supported); | |
922 | linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported); | |
923 | linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported); | |
924 | linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported); | |
925 | if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX || | |
926 | pcs->interface == PHY_INTERFACE_MODE_USXGMII) | |
927 | linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, | |
928 | pcs->supported); | |
929 | if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX) | |
930 | linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, | |
931 | pcs->supported); | |
932 | phy_advertise_supported(pcs); | |
933 | ||
934 | switch (pcs->interface) { | |
935 | case PHY_INTERFACE_MODE_SGMII: | |
936 | case PHY_INTERFACE_MODE_QSGMII: | |
937 | vsc9959_pcs_init_sgmii(pcs, link_an_mode, state); | |
938 | break; | |
939 | case PHY_INTERFACE_MODE_2500BASEX: | |
940 | vsc9959_pcs_init_2500basex(pcs, link_an_mode, state); | |
941 | break; | |
942 | case PHY_INTERFACE_MODE_USXGMII: | |
943 | vsc9959_pcs_init_usxgmii(pcs, link_an_mode, state); | |
944 | break; | |
945 | default: | |
946 | dev_err(ocelot->dev, "Unsupported link mode %s\n", | |
947 | phy_modes(pcs->interface)); | |
948 | } | |
949 | } | |
950 | ||
951 | static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs, | |
952 | struct phylink_link_state *state) | |
953 | { | |
954 | state->an_complete = pcs->autoneg_complete; | |
955 | state->an_enabled = pcs->autoneg; | |
956 | state->link = pcs->link; | |
957 | state->duplex = pcs->duplex; | |
958 | state->speed = pcs->speed; | |
959 | /* SGMII AN does not negotiate flow control, but that's ok, | |
960 | * since phylink already knows that, and does: | |
961 | * link_state.pause |= pl->phy_state.pause; | |
962 | */ | |
963 | state->pause = MLO_PAUSE_NONE; | |
964 | ||
965 | phydev_dbg(pcs, | |
966 | "mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n", | |
967 | phy_modes(pcs->interface), | |
968 | phy_speed_to_str(pcs->speed), | |
969 | phy_duplex_to_str(pcs->duplex), | |
970 | __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->advertising, | |
971 | __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->lp_advertising, | |
972 | pcs->link, pcs->autoneg, pcs->autoneg_complete); | |
973 | } | |
974 | ||
975 | static void vsc9959_pcs_link_state_sgmii(struct phy_device *pcs, | |
976 | struct phylink_link_state *state) | |
977 | { | |
978 | int err; | |
979 | ||
980 | err = genphy_update_link(pcs); | |
981 | if (err < 0) | |
982 | return; | |
983 | ||
984 | if (pcs->autoneg_complete) { | |
985 | u16 lpa = phy_read(pcs, MII_LPA); | |
986 | ||
987 | mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa); | |
988 | ||
989 | phy_resolve_aneg_linkmode(pcs); | |
990 | } | |
991 | } | |
992 | ||
993 | static void vsc9959_pcs_link_state_2500basex(struct phy_device *pcs, | |
994 | struct phylink_link_state *state) | |
995 | { | |
996 | int err; | |
997 | ||
998 | err = genphy_update_link(pcs); | |
999 | if (err < 0) | |
1000 | return; | |
1001 | ||
1002 | pcs->speed = SPEED_2500; | |
1003 | pcs->asym_pause = true; | |
1004 | pcs->pause = true; | |
1005 | } | |
1006 | ||
1007 | static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs, | |
1008 | struct phylink_link_state *state) | |
1009 | { | |
1010 | int status, lpa; | |
1011 | ||
1012 | status = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_BMSR); | |
1013 | if (status < 0) | |
1014 | return; | |
1015 | ||
1016 | pcs->autoneg = true; | |
1017 | pcs->autoneg_complete = USXGMII_BMSR_AN_CMPL(status); | |
1018 | pcs->link = USXGMII_BMSR_LNKS(status); | |
1019 | ||
1020 | if (!pcs->link || !pcs->autoneg_complete) | |
1021 | return; | |
1022 | ||
1023 | lpa = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_LPA); | |
1024 | if (lpa < 0) | |
1025 | return; | |
1026 | ||
1027 | switch (USXGMII_LPA_SPEED(lpa)) { | |
1028 | case USXGMII_SPEED_10: | |
1029 | pcs->speed = SPEED_10; | |
1030 | break; | |
1031 | case USXGMII_SPEED_100: | |
1032 | pcs->speed = SPEED_100; | |
1033 | break; | |
1034 | case USXGMII_SPEED_1000: | |
1035 | pcs->speed = SPEED_1000; | |
1036 | break; | |
1037 | case USXGMII_SPEED_2500: | |
1038 | pcs->speed = SPEED_2500; | |
1039 | break; | |
1040 | default: | |
1041 | break; | |
1042 | } | |
1043 | ||
bdeced75 VO |
1044 | if (USXGMII_LPA_DUPLEX(lpa)) |
1045 | pcs->duplex = DUPLEX_FULL; | |
1046 | else | |
1047 | pcs->duplex = DUPLEX_HALF; | |
1048 | } | |
1049 | ||
1050 | static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port, | |
1051 | struct phylink_link_state *state) | |
1052 | { | |
1053 | struct felix *felix = ocelot_to_felix(ocelot); | |
1054 | struct phy_device *pcs = felix->pcs[port]; | |
1055 | ||
1056 | if (!pcs) | |
1057 | return; | |
1058 | ||
1059 | pcs->speed = SPEED_UNKNOWN; | |
1060 | pcs->duplex = DUPLEX_UNKNOWN; | |
1061 | pcs->pause = 0; | |
1062 | pcs->asym_pause = 0; | |
1063 | ||
1064 | switch (pcs->interface) { | |
1065 | case PHY_INTERFACE_MODE_SGMII: | |
1066 | case PHY_INTERFACE_MODE_QSGMII: | |
1067 | vsc9959_pcs_link_state_sgmii(pcs, state); | |
1068 | break; | |
1069 | case PHY_INTERFACE_MODE_2500BASEX: | |
1070 | vsc9959_pcs_link_state_2500basex(pcs, state); | |
1071 | break; | |
1072 | case PHY_INTERFACE_MODE_USXGMII: | |
1073 | vsc9959_pcs_link_state_usxgmii(pcs, state); | |
1074 | break; | |
1075 | default: | |
1076 | return; | |
1077 | } | |
1078 | ||
1079 | vsc9959_pcs_link_state_resolve(pcs, state); | |
1080 | } | |
1081 | ||
1082 | static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port, | |
1083 | phy_interface_t phy_mode) | |
1084 | { | |
1085 | switch (phy_mode) { | |
28a134f5 | 1086 | case PHY_INTERFACE_MODE_INTERNAL: |
bdeced75 VO |
1087 | if (port != 4 && port != 5) |
1088 | return -ENOTSUPP; | |
1089 | return 0; | |
1090 | case PHY_INTERFACE_MODE_SGMII: | |
1091 | case PHY_INTERFACE_MODE_QSGMII: | |
1092 | case PHY_INTERFACE_MODE_USXGMII: | |
1093 | case PHY_INTERFACE_MODE_2500BASEX: | |
1094 | /* Not supported on internal to-CPU ports */ | |
1095 | if (port == 4 || port == 5) | |
1096 | return -ENOTSUPP; | |
1097 | return 0; | |
1098 | default: | |
1099 | return -ENOTSUPP; | |
1100 | } | |
1101 | } | |
1102 | ||
56051948 VO |
1103 | static const struct ocelot_ops vsc9959_ops = { |
1104 | .reset = vsc9959_reset, | |
1105 | }; | |
1106 | ||
bdeced75 VO |
1107 | static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) |
1108 | { | |
1109 | struct felix *felix = ocelot_to_felix(ocelot); | |
1110 | struct enetc_mdio_priv *mdio_priv; | |
1111 | struct device *dev = ocelot->dev; | |
1112 | resource_size_t imdio_base; | |
1113 | void __iomem *imdio_regs; | |
1114 | struct resource *res; | |
1115 | struct enetc_hw *hw; | |
1116 | struct mii_bus *bus; | |
1117 | int port; | |
1118 | int rc; | |
1119 | ||
1120 | felix->pcs = devm_kcalloc(dev, felix->info->num_ports, | |
1121 | sizeof(struct phy_device *), | |
1122 | GFP_KERNEL); | |
1123 | if (!felix->pcs) { | |
1124 | dev_err(dev, "failed to allocate array for PCS PHYs\n"); | |
1125 | return -ENOMEM; | |
1126 | } | |
1127 | ||
1128 | imdio_base = pci_resource_start(felix->pdev, | |
1129 | felix->info->imdio_pci_bar); | |
1130 | ||
1131 | res = felix->info->imdio_res; | |
1132 | res->flags = IORESOURCE_MEM; | |
1133 | res->start += imdio_base; | |
1134 | res->end += imdio_base; | |
1135 | ||
1136 | imdio_regs = devm_ioremap_resource(dev, res); | |
1137 | if (IS_ERR(imdio_regs)) { | |
1138 | dev_err(dev, "failed to map internal MDIO registers\n"); | |
1139 | return PTR_ERR(imdio_regs); | |
1140 | } | |
1141 | ||
1142 | hw = enetc_hw_alloc(dev, imdio_regs); | |
1143 | if (IS_ERR(hw)) { | |
1144 | dev_err(dev, "failed to allocate ENETC HW structure\n"); | |
1145 | return PTR_ERR(hw); | |
1146 | } | |
1147 | ||
1148 | bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); | |
1149 | if (!bus) | |
1150 | return -ENOMEM; | |
1151 | ||
1152 | bus->name = "VSC9959 internal MDIO bus"; | |
1153 | bus->read = enetc_mdio_read; | |
1154 | bus->write = enetc_mdio_write; | |
1155 | bus->parent = dev; | |
1156 | mdio_priv = bus->priv; | |
1157 | mdio_priv->hw = hw; | |
1158 | /* This gets added to imdio_regs, which already maps addresses | |
1159 | * starting with the proper offset. | |
1160 | */ | |
1161 | mdio_priv->mdio_base = 0; | |
1162 | snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); | |
1163 | ||
1164 | /* Needed in order to initialize the bus mutex lock */ | |
1165 | rc = mdiobus_register(bus); | |
1166 | if (rc < 0) { | |
1167 | dev_err(dev, "failed to register MDIO bus\n"); | |
1168 | return rc; | |
1169 | } | |
1170 | ||
1171 | felix->imdio = bus; | |
1172 | ||
1173 | for (port = 0; port < felix->info->num_ports; port++) { | |
1174 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
1175 | struct phy_device *pcs; | |
1176 | bool is_c45 = false; | |
1177 | ||
1178 | if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_USXGMII) | |
1179 | is_c45 = true; | |
1180 | ||
1181 | pcs = get_phy_device(felix->imdio, port, is_c45); | |
1182 | if (IS_ERR(pcs)) | |
1183 | continue; | |
1184 | ||
1185 | pcs->interface = ocelot_port->phy_mode; | |
1186 | felix->pcs[port] = pcs; | |
1187 | ||
1188 | dev_info(dev, "Found PCS at internal MDIO address %d\n", port); | |
1189 | } | |
1190 | ||
1191 | return 0; | |
1192 | } | |
1193 | ||
1194 | static void vsc9959_mdio_bus_free(struct ocelot *ocelot) | |
1195 | { | |
1196 | struct felix *felix = ocelot_to_felix(ocelot); | |
1197 | int port; | |
1198 | ||
1199 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
1200 | struct phy_device *pcs = felix->pcs[port]; | |
1201 | ||
1202 | if (!pcs) | |
1203 | continue; | |
1204 | ||
1205 | put_device(&pcs->mdio.dev); | |
1206 | } | |
1207 | mdiobus_unregister(felix->imdio); | |
1208 | } | |
1209 | ||
56051948 VO |
1210 | struct felix_info felix_info_vsc9959 = { |
1211 | .target_io_res = vsc9959_target_io_res, | |
1212 | .port_io_res = vsc9959_port_io_res, | |
bdeced75 | 1213 | .imdio_res = &vsc9959_imdio_res, |
56051948 VO |
1214 | .regfields = vsc9959_regfields, |
1215 | .map = vsc9959_regmap, | |
1216 | .ops = &vsc9959_ops, | |
1217 | .stats_layout = vsc9959_stats_layout, | |
1218 | .num_stats = ARRAY_SIZE(vsc9959_stats_layout), | |
07d985ee VO |
1219 | .vcap_is2_keys = vsc9959_vcap_is2_keys, |
1220 | .vcap_is2_actions = vsc9959_vcap_is2_actions, | |
1221 | .vcap = vsc9959_vcap_props, | |
56051948 | 1222 | .shared_queue_sz = 128 * 1024, |
21ce7f3e | 1223 | .num_mact_rows = 2048, |
56051948 | 1224 | .num_ports = 6, |
bdeced75 VO |
1225 | .switch_pci_bar = 4, |
1226 | .imdio_pci_bar = 0, | |
1227 | .mdio_bus_alloc = vsc9959_mdio_bus_alloc, | |
1228 | .mdio_bus_free = vsc9959_mdio_bus_free, | |
1229 | .pcs_init = vsc9959_pcs_init, | |
1230 | .pcs_an_restart = vsc9959_pcs_an_restart, | |
1231 | .pcs_link_state = vsc9959_pcs_link_state, | |
1232 | .prevalidate_phy_mode = vsc9959_prevalidate_phy_mode, | |
56051948 | 1233 | }; |