Commit | Line | Data |
---|---|---|
511e6bc0 | 1 | /* |
2 | * Copyright (c) 2014-2015 Hisilicon Limited. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | */ | |
9 | ||
511e6bc0 | 10 | #include "hns_dsaf_mac.h" |
2e2591b1 | 11 | #include "hns_dsaf_misc.h" |
511e6bc0 | 12 | #include "hns_dsaf_ppe.h" |
2e2591b1 | 13 | #include "hns_dsaf_reg.h" |
511e6bc0 | 14 | |
f00ef863 KY |
15 | enum _dsm_op_index { |
16 | HNS_OP_RESET_FUNC = 0x1, | |
17 | HNS_OP_SERDES_LP_FUNC = 0x2, | |
18 | HNS_OP_LED_SET_FUNC = 0x3, | |
19 | HNS_OP_GET_PORT_TYPE_FUNC = 0x4, | |
20 | HNS_OP_GET_SFP_STAT_FUNC = 0x5, | |
21 | }; | |
22 | ||
23 | enum _dsm_rst_type { | |
24 | HNS_DSAF_RESET_FUNC = 0x1, | |
25 | HNS_PPE_RESET_FUNC = 0x2, | |
26 | HNS_XGE_CORE_RESET_FUNC = 0x3, | |
27 | HNS_XGE_RESET_FUNC = 0x4, | |
28 | HNS_GE_RESET_FUNC = 0x5, | |
d605916b S |
29 | HNS_DSAF_CHN_RESET_FUNC = 0x6, |
30 | HNS_ROCE_RESET_FUNC = 0x7, | |
f00ef863 KY |
31 | }; |
32 | ||
33 | const u8 hns_dsaf_acpi_dsm_uuid[] = { | |
34 | 0x1A, 0xAA, 0x85, 0x1A, 0x93, 0xE2, 0x5E, 0x41, | |
35 | 0x8E, 0x28, 0x8D, 0x69, 0x0A, 0x0F, 0x82, 0x0A | |
36 | }; | |
37 | ||
831d828b YZZ |
38 | static void dsaf_write_sub(struct dsaf_device *dsaf_dev, u32 reg, u32 val) |
39 | { | |
40 | if (dsaf_dev->sub_ctrl) | |
41 | dsaf_write_syscon(dsaf_dev->sub_ctrl, reg, val); | |
42 | else | |
43 | dsaf_write_reg(dsaf_dev->sc_base, reg, val); | |
44 | } | |
45 | ||
46 | static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg) | |
47 | { | |
48 | u32 ret; | |
49 | ||
50 | if (dsaf_dev->sub_ctrl) | |
51 | ret = dsaf_read_syscon(dsaf_dev->sub_ctrl, reg); | |
52 | else | |
53 | ret = dsaf_read_reg(dsaf_dev->sc_base, reg); | |
54 | ||
55 | return ret; | |
56 | } | |
57 | ||
a24274aa KY |
58 | static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status, |
59 | u16 speed, int data) | |
511e6bc0 | 60 | { |
61 | int speed_reg = 0; | |
62 | u8 value; | |
63 | ||
64 | if (!mac_cb) { | |
65 | pr_err("sfp_led_opt mac_dev is null!\n"); | |
66 | return; | |
67 | } | |
31d4446d YZZ |
68 | if (!mac_cb->cpld_ctrl) { |
69 | dev_err(mac_cb->dev, "mac_id=%d, cpld syscon is null !\n", | |
511e6bc0 | 70 | mac_cb->mac_id); |
71 | return; | |
72 | } | |
73 | ||
74 | if (speed == MAC_SPEED_10000) | |
75 | speed_reg = 1; | |
76 | ||
77 | value = mac_cb->cpld_led_value; | |
78 | ||
79 | if (link_status) { | |
80 | dsaf_set_bit(value, DSAF_LED_LINK_B, link_status); | |
81 | dsaf_set_field(value, DSAF_LED_SPEED_M, | |
82 | DSAF_LED_SPEED_S, speed_reg); | |
83 | dsaf_set_bit(value, DSAF_LED_DATA_B, data); | |
84 | ||
85 | if (value != mac_cb->cpld_led_value) { | |
31d4446d YZZ |
86 | dsaf_write_syscon(mac_cb->cpld_ctrl, |
87 | mac_cb->cpld_ctrl_reg, value); | |
511e6bc0 | 88 | mac_cb->cpld_led_value = value; |
89 | } | |
90 | } else { | |
d8a8371e DH |
91 | value = (mac_cb->cpld_led_value) & (0x1 << DSAF_LED_ANCHOR_B); |
92 | dsaf_write_syscon(mac_cb->cpld_ctrl, | |
93 | mac_cb->cpld_ctrl_reg, value); | |
94 | mac_cb->cpld_led_value = value; | |
511e6bc0 | 95 | } |
96 | } | |
97 | ||
a24274aa | 98 | static void cpld_led_reset(struct hns_mac_cb *mac_cb) |
511e6bc0 | 99 | { |
31d4446d | 100 | if (!mac_cb || !mac_cb->cpld_ctrl) |
511e6bc0 | 101 | return; |
102 | ||
31d4446d YZZ |
103 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
104 | CPLD_LED_DEFAULT_VALUE); | |
511e6bc0 | 105 | mac_cb->cpld_led_value = CPLD_LED_DEFAULT_VALUE; |
106 | } | |
107 | ||
a24274aa KY |
108 | static int cpld_set_led_id(struct hns_mac_cb *mac_cb, |
109 | enum hnae_led_state status) | |
511e6bc0 | 110 | { |
111 | switch (status) { | |
112 | case HNAE_LED_ACTIVE: | |
31d4446d YZZ |
113 | mac_cb->cpld_led_value = |
114 | dsaf_read_syscon(mac_cb->cpld_ctrl, | |
115 | mac_cb->cpld_ctrl_reg); | |
511e6bc0 | 116 | dsaf_set_bit(mac_cb->cpld_led_value, DSAF_LED_ANCHOR_B, |
117 | CPLD_LED_ON_VALUE); | |
31d4446d YZZ |
118 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
119 | mac_cb->cpld_led_value); | |
d8a8371e | 120 | break; |
511e6bc0 | 121 | case HNAE_LED_INACTIVE: |
122 | dsaf_set_bit(mac_cb->cpld_led_value, DSAF_LED_ANCHOR_B, | |
123 | CPLD_LED_DEFAULT_VALUE); | |
31d4446d YZZ |
124 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
125 | mac_cb->cpld_led_value); | |
511e6bc0 | 126 | break; |
127 | default: | |
d8a8371e DH |
128 | dev_err(mac_cb->dev, "invalid led state: %d!", status); |
129 | return -EINVAL; | |
511e6bc0 | 130 | } |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | #define RESET_REQ_OR_DREQ 1 | |
136 | ||
f00ef863 KY |
137 | static void hns_dsaf_acpi_srst_by_port(struct dsaf_device *dsaf_dev, u8 op_type, |
138 | u32 port_type, u32 port, u32 val) | |
139 | { | |
140 | union acpi_object *obj; | |
141 | union acpi_object obj_args[3], argv4; | |
142 | ||
143 | obj_args[0].integer.type = ACPI_TYPE_INTEGER; | |
144 | obj_args[0].integer.value = port_type; | |
145 | obj_args[1].integer.type = ACPI_TYPE_INTEGER; | |
146 | obj_args[1].integer.value = port; | |
147 | obj_args[2].integer.type = ACPI_TYPE_INTEGER; | |
148 | obj_args[2].integer.value = val; | |
149 | ||
150 | argv4.type = ACPI_TYPE_PACKAGE; | |
151 | argv4.package.count = 3; | |
152 | argv4.package.elements = obj_args; | |
153 | ||
154 | obj = acpi_evaluate_dsm(ACPI_HANDLE(dsaf_dev->dev), | |
155 | hns_dsaf_acpi_dsm_uuid, 0, op_type, &argv4); | |
156 | if (!obj) { | |
157 | dev_warn(dsaf_dev->dev, "reset port_type%d port%d fail!", | |
158 | port_type, port); | |
159 | return; | |
160 | } | |
161 | ||
162 | ACPI_FREE(obj); | |
163 | } | |
164 | ||
a24274aa | 165 | static void hns_dsaf_rst(struct dsaf_device *dsaf_dev, bool dereset) |
511e6bc0 | 166 | { |
167 | u32 xbar_reg_addr; | |
168 | u32 nt_reg_addr; | |
169 | ||
a24274aa | 170 | if (!dereset) { |
511e6bc0 | 171 | xbar_reg_addr = DSAF_SUB_SC_XBAR_RESET_REQ_REG; |
172 | nt_reg_addr = DSAF_SUB_SC_NT_RESET_REQ_REG; | |
173 | } else { | |
174 | xbar_reg_addr = DSAF_SUB_SC_XBAR_RESET_DREQ_REG; | |
175 | nt_reg_addr = DSAF_SUB_SC_NT_RESET_DREQ_REG; | |
176 | } | |
177 | ||
831d828b YZZ |
178 | dsaf_write_sub(dsaf_dev, xbar_reg_addr, RESET_REQ_OR_DREQ); |
179 | dsaf_write_sub(dsaf_dev, nt_reg_addr, RESET_REQ_OR_DREQ); | |
511e6bc0 | 180 | } |
181 | ||
f00ef863 KY |
182 | static void hns_dsaf_rst_acpi(struct dsaf_device *dsaf_dev, bool dereset) |
183 | { | |
184 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
185 | HNS_DSAF_RESET_FUNC, | |
186 | 0, dereset); | |
187 | } | |
188 | ||
a24274aa KY |
189 | static void hns_dsaf_xge_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
190 | bool dereset) | |
511e6bc0 | 191 | { |
192 | u32 reg_val = 0; | |
193 | u32 reg_addr; | |
194 | ||
195 | if (port >= DSAF_XGE_NUM) | |
196 | return; | |
197 | ||
198 | reg_val |= RESET_REQ_OR_DREQ; | |
850bfa3b | 199 | reg_val |= 0x2082082 << dsaf_dev->mac_cb[port]->port_rst_off; |
511e6bc0 | 200 | |
a24274aa | 201 | if (!dereset) |
511e6bc0 | 202 | reg_addr = DSAF_SUB_SC_XGE_RESET_REQ_REG; |
203 | else | |
204 | reg_addr = DSAF_SUB_SC_XGE_RESET_DREQ_REG; | |
205 | ||
831d828b | 206 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 207 | } |
208 | ||
f00ef863 KY |
209 | static void hns_dsaf_xge_srst_by_port_acpi(struct dsaf_device *dsaf_dev, |
210 | u32 port, bool dereset) | |
211 | { | |
212 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
213 | HNS_XGE_RESET_FUNC, port, dereset); | |
214 | } | |
215 | ||
a24274aa KY |
216 | static void hns_dsaf_xge_core_srst_by_port(struct dsaf_device *dsaf_dev, |
217 | u32 port, bool dereset) | |
511e6bc0 | 218 | { |
219 | u32 reg_val = 0; | |
220 | u32 reg_addr; | |
221 | ||
222 | if (port >= DSAF_XGE_NUM) | |
223 | return; | |
224 | ||
850bfa3b YZZ |
225 | reg_val |= XGMAC_TRX_CORE_SRST_M |
226 | << dsaf_dev->mac_cb[port]->port_rst_off; | |
511e6bc0 | 227 | |
a24274aa | 228 | if (!dereset) |
511e6bc0 | 229 | reg_addr = DSAF_SUB_SC_XGE_RESET_REQ_REG; |
230 | else | |
231 | reg_addr = DSAF_SUB_SC_XGE_RESET_DREQ_REG; | |
232 | ||
831d828b | 233 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 234 | } |
235 | ||
e0180688 | 236 | /** |
237 | * hns_dsaf_srst_chns - reset dsaf channels | |
238 | * @dsaf_dev: dsaf device struct pointer | |
239 | * @msk: xbar channels mask value: | |
240 | * bit0-5 for xge0-5 | |
241 | * bit6-11 for ppe0-5 | |
242 | * bit12-17 for roce0-5 | |
243 | * bit18-19 for com/dfx | |
244 | * @enable: false - request reset , true - drop reset | |
245 | */ | |
d605916b | 246 | void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset) |
e0180688 | 247 | { |
248 | u32 reg_addr; | |
249 | ||
d605916b | 250 | if (!dereset) |
e0180688 | 251 | reg_addr = DSAF_SUB_SC_DSAF_RESET_REQ_REG; |
252 | else | |
253 | reg_addr = DSAF_SUB_SC_DSAF_RESET_DREQ_REG; | |
254 | ||
255 | dsaf_write_sub(dsaf_dev, reg_addr, msk); | |
256 | } | |
257 | ||
d605916b S |
258 | /** |
259 | * hns_dsaf_srst_chns - reset dsaf channels | |
260 | * @dsaf_dev: dsaf device struct pointer | |
261 | * @msk: xbar channels mask value: | |
262 | * bit0-5 for xge0-5 | |
263 | * bit6-11 for ppe0-5 | |
264 | * bit12-17 for roce0-5 | |
265 | * bit18-19 for com/dfx | |
266 | * @enable: false - request reset , true - drop reset | |
267 | */ | |
268 | void | |
269 | hns_dsaf_srst_chns_acpi(struct dsaf_device *dsaf_dev, u32 msk, bool dereset) | |
e0180688 | 270 | { |
d605916b S |
271 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, |
272 | HNS_DSAF_CHN_RESET_FUNC, | |
273 | msk, dereset); | |
274 | } | |
275 | ||
276 | void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool dereset) | |
277 | { | |
278 | if (!dereset) { | |
e0180688 | 279 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_ROCEE_RESET_REQ_REG, 1); |
280 | } else { | |
281 | dsaf_write_sub(dsaf_dev, | |
282 | DSAF_SUB_SC_ROCEE_CLK_DIS_REG, 1); | |
283 | dsaf_write_sub(dsaf_dev, | |
284 | DSAF_SUB_SC_ROCEE_RESET_DREQ_REG, 1); | |
285 | msleep(20); | |
286 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_ROCEE_CLK_EN_REG, 1); | |
287 | } | |
288 | } | |
289 | ||
d605916b S |
290 | void hns_dsaf_roce_srst_acpi(struct dsaf_device *dsaf_dev, bool dereset) |
291 | { | |
292 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
293 | HNS_ROCE_RESET_FUNC, 0, dereset); | |
294 | } | |
295 | ||
f00ef863 KY |
296 | static void |
297 | hns_dsaf_xge_core_srst_by_port_acpi(struct dsaf_device *dsaf_dev, | |
298 | u32 port, bool dereset) | |
299 | { | |
300 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
301 | HNS_XGE_CORE_RESET_FUNC, port, dereset); | |
302 | } | |
303 | ||
a24274aa KY |
304 | static void hns_dsaf_ge_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
305 | bool dereset) | |
511e6bc0 | 306 | { |
307 | u32 reg_val_1; | |
308 | u32 reg_val_2; | |
850bfa3b | 309 | u32 port_rst_off; |
511e6bc0 | 310 | |
311 | if (port >= DSAF_GE_NUM) | |
312 | return; | |
313 | ||
89a44093 | 314 | if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) { |
511e6bc0 | 315 | reg_val_1 = 0x1 << port; |
850bfa3b | 316 | port_rst_off = dsaf_dev->mac_cb[port]->port_rst_off; |
13ac695e | 317 | /* there is difference between V1 and V2 in register.*/ |
d9fdb4ed DH |
318 | reg_val_2 = AE_IS_VER1(dsaf_dev->dsaf_ver) ? |
319 | 0x1041041 : 0x2082082; | |
320 | reg_val_2 <<= port_rst_off; | |
511e6bc0 | 321 | |
a24274aa | 322 | if (!dereset) { |
831d828b | 323 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ1_REG, |
511e6bc0 | 324 | reg_val_1); |
325 | ||
831d828b | 326 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ0_REG, |
511e6bc0 | 327 | reg_val_2); |
328 | } else { | |
831d828b | 329 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ0_REG, |
511e6bc0 | 330 | reg_val_2); |
331 | ||
831d828b | 332 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ1_REG, |
511e6bc0 | 333 | reg_val_1); |
334 | } | |
335 | } else { | |
d9fdb4ed DH |
336 | reg_val_1 = 0x15540; |
337 | reg_val_2 = AE_IS_VER1(dsaf_dev->dsaf_ver) ? 0x100 : 0x40; | |
0b03fd85 | 338 | |
d9fdb4ed DH |
339 | reg_val_1 <<= dsaf_dev->reset_offset; |
340 | reg_val_2 <<= dsaf_dev->reset_offset; | |
511e6bc0 | 341 | |
a24274aa | 342 | if (!dereset) { |
831d828b | 343 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ1_REG, |
511e6bc0 | 344 | reg_val_1); |
345 | ||
831d828b | 346 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_PPE_RESET_REQ_REG, |
511e6bc0 | 347 | reg_val_2); |
348 | } else { | |
831d828b | 349 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ1_REG, |
511e6bc0 | 350 | reg_val_1); |
351 | ||
831d828b | 352 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_PPE_RESET_DREQ_REG, |
511e6bc0 | 353 | reg_val_2); |
354 | } | |
355 | } | |
356 | } | |
357 | ||
f00ef863 KY |
358 | static void hns_dsaf_ge_srst_by_port_acpi(struct dsaf_device *dsaf_dev, |
359 | u32 port, bool dereset) | |
360 | { | |
361 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
362 | HNS_GE_RESET_FUNC, port, dereset); | |
363 | } | |
364 | ||
a24274aa KY |
365 | static void hns_ppe_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
366 | bool dereset) | |
511e6bc0 | 367 | { |
368 | u32 reg_val = 0; | |
369 | u32 reg_addr; | |
370 | ||
850bfa3b | 371 | reg_val |= RESET_REQ_OR_DREQ << dsaf_dev->mac_cb[port]->port_rst_off; |
511e6bc0 | 372 | |
a24274aa | 373 | if (!dereset) |
511e6bc0 | 374 | reg_addr = DSAF_SUB_SC_PPE_RESET_REQ_REG; |
375 | else | |
376 | reg_addr = DSAF_SUB_SC_PPE_RESET_DREQ_REG; | |
377 | ||
831d828b | 378 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 379 | } |
380 | ||
f00ef863 KY |
381 | static void |
382 | hns_ppe_srst_by_port_acpi(struct dsaf_device *dsaf_dev, u32 port, bool dereset) | |
383 | { | |
384 | hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, | |
385 | HNS_PPE_RESET_FUNC, port, dereset); | |
386 | } | |
387 | ||
a24274aa | 388 | static void hns_ppe_com_srst(struct dsaf_device *dsaf_dev, bool dereset) |
511e6bc0 | 389 | { |
511e6bc0 | 390 | u32 reg_val; |
391 | u32 reg_addr; | |
392 | ||
f00ef863 KY |
393 | if (!(dev_of_node(dsaf_dev->dev))) |
394 | return; | |
395 | ||
89a44093 | 396 | if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) { |
511e6bc0 | 397 | reg_val = RESET_REQ_OR_DREQ; |
a24274aa | 398 | if (!dereset) |
511e6bc0 | 399 | reg_addr = DSAF_SUB_SC_RCB_PPE_COM_RESET_REQ_REG; |
400 | else | |
401 | reg_addr = DSAF_SUB_SC_RCB_PPE_COM_RESET_DREQ_REG; | |
402 | ||
403 | } else { | |
422c3107 | 404 | reg_val = 0x100 << dsaf_dev->reset_offset; |
511e6bc0 | 405 | |
a24274aa | 406 | if (!dereset) |
511e6bc0 | 407 | reg_addr = DSAF_SUB_SC_PPE_RESET_REQ_REG; |
408 | else | |
409 | reg_addr = DSAF_SUB_SC_PPE_RESET_DREQ_REG; | |
410 | } | |
411 | ||
831d828b | 412 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 413 | } |
414 | ||
415 | /** | |
416 | * hns_mac_get_sds_mode - get phy ifterface form serdes mode | |
417 | * @mac_cb: mac control block | |
418 | * retuen phy interface | |
419 | */ | |
a24274aa | 420 | static phy_interface_t hns_mac_get_phy_if(struct hns_mac_cb *mac_cb) |
511e6bc0 | 421 | { |
c1203fe7 SL |
422 | u32 mode; |
423 | u32 reg; | |
c1203fe7 | 424 | bool is_ver1 = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver); |
c1203fe7 | 425 | int mac_id = mac_cb->mac_id; |
0d768fc6 | 426 | phy_interface_t phy_if; |
511e6bc0 | 427 | |
0d768fc6 YZZ |
428 | if (is_ver1) { |
429 | if (HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev)) | |
430 | return PHY_INTERFACE_MODE_SGMII; | |
431 | ||
432 | if (mac_id >= 0 && mac_id <= 3) | |
433 | reg = HNS_MAC_HILINK4_REG; | |
511e6bc0 | 434 | else |
0d768fc6 YZZ |
435 | reg = HNS_MAC_HILINK3_REG; |
436 | } else{ | |
437 | if (!HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev) && mac_id <= 3) | |
438 | reg = HNS_MAC_HILINK4V2_REG; | |
c1203fe7 | 439 | else |
0d768fc6 | 440 | reg = HNS_MAC_HILINK3V2_REG; |
511e6bc0 | 441 | } |
0d768fc6 YZZ |
442 | |
443 | mode = dsaf_read_sub(mac_cb->dsaf_dev, reg); | |
444 | if (dsaf_get_bit(mode, mac_cb->port_mode_off)) | |
445 | phy_if = PHY_INTERFACE_MODE_XGMII; | |
446 | else | |
447 | phy_if = PHY_INTERFACE_MODE_SGMII; | |
448 | ||
511e6bc0 | 449 | return phy_if; |
450 | } | |
451 | ||
f00ef863 KY |
452 | static phy_interface_t hns_mac_get_phy_if_acpi(struct hns_mac_cb *mac_cb) |
453 | { | |
454 | phy_interface_t phy_if = PHY_INTERFACE_MODE_NA; | |
455 | union acpi_object *obj; | |
456 | union acpi_object obj_args, argv4; | |
457 | ||
458 | obj_args.integer.type = ACPI_TYPE_INTEGER; | |
459 | obj_args.integer.value = mac_cb->mac_id; | |
460 | ||
461 | argv4.type = ACPI_TYPE_PACKAGE, | |
462 | argv4.package.count = 1, | |
463 | argv4.package.elements = &obj_args, | |
464 | ||
465 | obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dev), | |
466 | hns_dsaf_acpi_dsm_uuid, 0, | |
467 | HNS_OP_GET_PORT_TYPE_FUNC, &argv4); | |
468 | ||
469 | if (!obj || obj->type != ACPI_TYPE_INTEGER) | |
470 | return phy_if; | |
471 | ||
472 | phy_if = obj->integer.value ? | |
473 | PHY_INTERFACE_MODE_XGMII : PHY_INTERFACE_MODE_SGMII; | |
474 | ||
475 | dev_dbg(mac_cb->dev, "mac_id=%d, phy_if=%d\n", mac_cb->mac_id, phy_if); | |
476 | ||
477 | ACPI_FREE(obj); | |
478 | ||
479 | return phy_if; | |
480 | } | |
481 | ||
31d4446d YZZ |
482 | int hns_mac_get_sfp_prsnt(struct hns_mac_cb *mac_cb, int *sfp_prsnt) |
483 | { | |
484 | if (!mac_cb->cpld_ctrl) | |
485 | return -ENODEV; | |
486 | ||
487 | *sfp_prsnt = !dsaf_read_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg | |
488 | + MAC_SFP_PORT_OFFSET); | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
511e6bc0 | 493 | /** |
494 | * hns_mac_config_sds_loopback - set loop back for serdes | |
495 | * @mac_cb: mac control block | |
496 | * retuen 0 == success | |
497 | */ | |
a24274aa | 498 | static int hns_mac_config_sds_loopback(struct hns_mac_cb *mac_cb, bool en) |
511e6bc0 | 499 | { |
511e6bc0 | 500 | const u8 lane_id[] = { |
501 | 0, /* mac 0 -> lane 0 */ | |
502 | 1, /* mac 1 -> lane 1 */ | |
503 | 2, /* mac 2 -> lane 2 */ | |
504 | 3, /* mac 3 -> lane 3 */ | |
505 | 2, /* mac 4 -> lane 2 */ | |
506 | 3, /* mac 5 -> lane 3 */ | |
507 | 0, /* mac 6 -> lane 0 */ | |
508 | 1 /* mac 7 -> lane 1 */ | |
509 | }; | |
510 | #define RX_CSR(lane, reg) ((0x4080 + (reg) * 0x0002 + (lane) * 0x0200) * 2) | |
511 | u64 reg_offset = RX_CSR(lane_id[mac_cb->mac_id], 0); | |
512 | ||
513 | int sfp_prsnt; | |
514 | int ret = hns_mac_get_sfp_prsnt(mac_cb, &sfp_prsnt); | |
515 | ||
652d39b0 | 516 | if (!mac_cb->phy_dev) { |
511e6bc0 | 517 | if (ret) |
518 | pr_info("please confirm sfp is present or not\n"); | |
519 | else | |
520 | if (!sfp_prsnt) | |
521 | pr_info("no sfp in this eth\n"); | |
522 | } | |
523 | ||
831d828b | 524 | if (mac_cb->serdes_ctrl) { |
89a6b1aa KY |
525 | u32 origin; |
526 | ||
527 | if (!AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver)) { | |
528 | #define HILINK_ACCESS_SEL_CFG 0x40008 | |
529 | /* hilink4 & hilink3 use the same xge training and | |
530 | * xge u adaptor. There is a hilink access sel cfg | |
531 | * register to select which one to be configed | |
532 | */ | |
533 | if ((!HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev)) && | |
534 | (mac_cb->mac_id <= 3)) | |
535 | dsaf_write_syscon(mac_cb->serdes_ctrl, | |
536 | HILINK_ACCESS_SEL_CFG, 0); | |
537 | else | |
538 | dsaf_write_syscon(mac_cb->serdes_ctrl, | |
539 | HILINK_ACCESS_SEL_CFG, 3); | |
540 | } | |
541 | ||
542 | origin = dsaf_read_syscon(mac_cb->serdes_ctrl, reg_offset); | |
831d828b | 543 | |
a24274aa | 544 | dsaf_set_field(origin, 1ull << 10, 10, en); |
831d828b YZZ |
545 | dsaf_write_syscon(mac_cb->serdes_ctrl, reg_offset, origin); |
546 | } else { | |
89a6b1aa KY |
547 | u8 *base_addr = (u8 *)mac_cb->serdes_vaddr + |
548 | (mac_cb->mac_id <= 3 ? 0x00280000 : 0x00200000); | |
a24274aa | 549 | dsaf_set_reg_field(base_addr, reg_offset, 1ull << 10, 10, en); |
831d828b | 550 | } |
511e6bc0 | 551 | |
552 | return 0; | |
553 | } | |
a24274aa | 554 | |
f00ef863 KY |
555 | static int |
556 | hns_mac_config_sds_loopback_acpi(struct hns_mac_cb *mac_cb, bool en) | |
557 | { | |
558 | union acpi_object *obj; | |
559 | union acpi_object obj_args[3], argv4; | |
560 | ||
561 | obj_args[0].integer.type = ACPI_TYPE_INTEGER; | |
562 | obj_args[0].integer.value = mac_cb->mac_id; | |
563 | obj_args[1].integer.type = ACPI_TYPE_INTEGER; | |
564 | obj_args[1].integer.value = !!en; | |
565 | ||
566 | argv4.type = ACPI_TYPE_PACKAGE; | |
567 | argv4.package.count = 2; | |
568 | argv4.package.elements = obj_args; | |
569 | ||
570 | obj = acpi_evaluate_dsm(ACPI_HANDLE(mac_cb->dsaf_dev->dev), | |
571 | hns_dsaf_acpi_dsm_uuid, 0, | |
572 | HNS_OP_SERDES_LP_FUNC, &argv4); | |
573 | if (!obj) { | |
574 | dev_warn(mac_cb->dsaf_dev->dev, "set port%d serdes lp fail!", | |
575 | mac_cb->mac_id); | |
576 | ||
577 | return -ENOTSUPP; | |
578 | } | |
579 | ||
580 | ACPI_FREE(obj); | |
581 | ||
582 | return 0; | |
583 | } | |
584 | ||
a24274aa KY |
585 | struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) |
586 | { | |
587 | struct dsaf_misc_op *misc_op; | |
588 | ||
589 | misc_op = devm_kzalloc(dsaf_dev->dev, sizeof(*misc_op), GFP_KERNEL); | |
590 | if (!misc_op) | |
591 | return NULL; | |
592 | ||
8413b3be KY |
593 | if (dev_of_node(dsaf_dev->dev)) { |
594 | misc_op->cpld_set_led = hns_cpld_set_led; | |
595 | misc_op->cpld_reset_led = cpld_led_reset; | |
596 | misc_op->cpld_set_led_id = cpld_set_led_id; | |
597 | ||
598 | misc_op->dsaf_reset = hns_dsaf_rst; | |
599 | misc_op->xge_srst = hns_dsaf_xge_srst_by_port; | |
600 | misc_op->xge_core_srst = hns_dsaf_xge_core_srst_by_port; | |
601 | misc_op->ge_srst = hns_dsaf_ge_srst_by_port; | |
602 | misc_op->ppe_srst = hns_ppe_srst_by_port; | |
603 | misc_op->ppe_comm_srst = hns_ppe_com_srst; | |
d605916b S |
604 | misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns; |
605 | misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst; | |
8413b3be KY |
606 | |
607 | misc_op->get_phy_if = hns_mac_get_phy_if; | |
608 | misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; | |
609 | ||
610 | misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback; | |
f00ef863 KY |
611 | } else if (is_acpi_node(dsaf_dev->dev->fwnode)) { |
612 | misc_op->cpld_set_led = hns_cpld_set_led; | |
613 | misc_op->cpld_reset_led = cpld_led_reset; | |
614 | misc_op->cpld_set_led_id = cpld_set_led_id; | |
615 | ||
616 | misc_op->dsaf_reset = hns_dsaf_rst_acpi; | |
617 | misc_op->xge_srst = hns_dsaf_xge_srst_by_port_acpi; | |
618 | misc_op->xge_core_srst = hns_dsaf_xge_core_srst_by_port_acpi; | |
619 | misc_op->ge_srst = hns_dsaf_ge_srst_by_port_acpi; | |
620 | misc_op->ppe_srst = hns_ppe_srst_by_port_acpi; | |
621 | misc_op->ppe_comm_srst = hns_ppe_com_srst; | |
d605916b S |
622 | misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns_acpi; |
623 | misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst_acpi; | |
f00ef863 KY |
624 | |
625 | misc_op->get_phy_if = hns_mac_get_phy_if_acpi; | |
626 | misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; | |
627 | ||
628 | misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback_acpi; | |
629 | } else { | |
630 | devm_kfree(dsaf_dev->dev, (void *)misc_op); | |
631 | misc_op = NULL; | |
8413b3be | 632 | } |
a24274aa KY |
633 | |
634 | return (void *)misc_op; | |
635 | } | |
d605916b S |
636 | |
637 | static int hns_dsaf_dev_match(struct device *dev, void *fwnode) | |
638 | { | |
639 | return dev->fwnode == fwnode; | |
640 | } | |
641 | ||
642 | struct | |
643 | platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode) | |
644 | { | |
645 | struct device *dev; | |
646 | ||
647 | dev = bus_find_device(&platform_bus_type, NULL, | |
648 | fwnode, hns_dsaf_dev_match); | |
649 | return dev ? to_platform_device(dev) : NULL; | |
650 | } |