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