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 | |
831d828b YZZ |
15 | static void dsaf_write_sub(struct dsaf_device *dsaf_dev, u32 reg, u32 val) |
16 | { | |
17 | if (dsaf_dev->sub_ctrl) | |
18 | dsaf_write_syscon(dsaf_dev->sub_ctrl, reg, val); | |
19 | else | |
20 | dsaf_write_reg(dsaf_dev->sc_base, reg, val); | |
21 | } | |
22 | ||
23 | static u32 dsaf_read_sub(struct dsaf_device *dsaf_dev, u32 reg) | |
24 | { | |
25 | u32 ret; | |
26 | ||
27 | if (dsaf_dev->sub_ctrl) | |
28 | ret = dsaf_read_syscon(dsaf_dev->sub_ctrl, reg); | |
29 | else | |
30 | ret = dsaf_read_reg(dsaf_dev->sc_base, reg); | |
31 | ||
32 | return ret; | |
33 | } | |
34 | ||
a24274aa KY |
35 | static void hns_cpld_set_led(struct hns_mac_cb *mac_cb, int link_status, |
36 | u16 speed, int data) | |
511e6bc0 | 37 | { |
38 | int speed_reg = 0; | |
39 | u8 value; | |
40 | ||
41 | if (!mac_cb) { | |
42 | pr_err("sfp_led_opt mac_dev is null!\n"); | |
43 | return; | |
44 | } | |
31d4446d YZZ |
45 | if (!mac_cb->cpld_ctrl) { |
46 | dev_err(mac_cb->dev, "mac_id=%d, cpld syscon is null !\n", | |
511e6bc0 | 47 | mac_cb->mac_id); |
48 | return; | |
49 | } | |
50 | ||
51 | if (speed == MAC_SPEED_10000) | |
52 | speed_reg = 1; | |
53 | ||
54 | value = mac_cb->cpld_led_value; | |
55 | ||
56 | if (link_status) { | |
57 | dsaf_set_bit(value, DSAF_LED_LINK_B, link_status); | |
58 | dsaf_set_field(value, DSAF_LED_SPEED_M, | |
59 | DSAF_LED_SPEED_S, speed_reg); | |
60 | dsaf_set_bit(value, DSAF_LED_DATA_B, data); | |
61 | ||
62 | if (value != mac_cb->cpld_led_value) { | |
31d4446d YZZ |
63 | dsaf_write_syscon(mac_cb->cpld_ctrl, |
64 | mac_cb->cpld_ctrl_reg, value); | |
511e6bc0 | 65 | mac_cb->cpld_led_value = value; |
66 | } | |
67 | } else { | |
31d4446d YZZ |
68 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
69 | CPLD_LED_DEFAULT_VALUE); | |
511e6bc0 | 70 | mac_cb->cpld_led_value = CPLD_LED_DEFAULT_VALUE; |
71 | } | |
72 | } | |
73 | ||
a24274aa | 74 | static void cpld_led_reset(struct hns_mac_cb *mac_cb) |
511e6bc0 | 75 | { |
31d4446d | 76 | if (!mac_cb || !mac_cb->cpld_ctrl) |
511e6bc0 | 77 | return; |
78 | ||
31d4446d YZZ |
79 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
80 | CPLD_LED_DEFAULT_VALUE); | |
511e6bc0 | 81 | mac_cb->cpld_led_value = CPLD_LED_DEFAULT_VALUE; |
82 | } | |
83 | ||
a24274aa KY |
84 | static int cpld_set_led_id(struct hns_mac_cb *mac_cb, |
85 | enum hnae_led_state status) | |
511e6bc0 | 86 | { |
87 | switch (status) { | |
88 | case HNAE_LED_ACTIVE: | |
31d4446d YZZ |
89 | mac_cb->cpld_led_value = |
90 | dsaf_read_syscon(mac_cb->cpld_ctrl, | |
91 | mac_cb->cpld_ctrl_reg); | |
511e6bc0 | 92 | dsaf_set_bit(mac_cb->cpld_led_value, DSAF_LED_ANCHOR_B, |
93 | CPLD_LED_ON_VALUE); | |
31d4446d YZZ |
94 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
95 | mac_cb->cpld_led_value); | |
edc9b427 | 96 | return 2; |
511e6bc0 | 97 | case HNAE_LED_INACTIVE: |
98 | dsaf_set_bit(mac_cb->cpld_led_value, DSAF_LED_ANCHOR_B, | |
99 | CPLD_LED_DEFAULT_VALUE); | |
31d4446d YZZ |
100 | dsaf_write_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg, |
101 | mac_cb->cpld_led_value); | |
511e6bc0 | 102 | break; |
103 | default: | |
104 | break; | |
105 | } | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
110 | #define RESET_REQ_OR_DREQ 1 | |
111 | ||
a24274aa | 112 | static void hns_dsaf_rst(struct dsaf_device *dsaf_dev, bool dereset) |
511e6bc0 | 113 | { |
114 | u32 xbar_reg_addr; | |
115 | u32 nt_reg_addr; | |
116 | ||
a24274aa | 117 | if (!dereset) { |
511e6bc0 | 118 | xbar_reg_addr = DSAF_SUB_SC_XBAR_RESET_REQ_REG; |
119 | nt_reg_addr = DSAF_SUB_SC_NT_RESET_REQ_REG; | |
120 | } else { | |
121 | xbar_reg_addr = DSAF_SUB_SC_XBAR_RESET_DREQ_REG; | |
122 | nt_reg_addr = DSAF_SUB_SC_NT_RESET_DREQ_REG; | |
123 | } | |
124 | ||
831d828b YZZ |
125 | dsaf_write_sub(dsaf_dev, xbar_reg_addr, RESET_REQ_OR_DREQ); |
126 | dsaf_write_sub(dsaf_dev, nt_reg_addr, RESET_REQ_OR_DREQ); | |
511e6bc0 | 127 | } |
128 | ||
a24274aa KY |
129 | static void hns_dsaf_xge_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
130 | bool dereset) | |
511e6bc0 | 131 | { |
132 | u32 reg_val = 0; | |
133 | u32 reg_addr; | |
134 | ||
135 | if (port >= DSAF_XGE_NUM) | |
136 | return; | |
137 | ||
138 | reg_val |= RESET_REQ_OR_DREQ; | |
850bfa3b | 139 | reg_val |= 0x2082082 << dsaf_dev->mac_cb[port]->port_rst_off; |
511e6bc0 | 140 | |
a24274aa | 141 | if (!dereset) |
511e6bc0 | 142 | reg_addr = DSAF_SUB_SC_XGE_RESET_REQ_REG; |
143 | else | |
144 | reg_addr = DSAF_SUB_SC_XGE_RESET_DREQ_REG; | |
145 | ||
831d828b | 146 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 147 | } |
148 | ||
a24274aa KY |
149 | static void hns_dsaf_xge_core_srst_by_port(struct dsaf_device *dsaf_dev, |
150 | u32 port, bool dereset) | |
511e6bc0 | 151 | { |
152 | u32 reg_val = 0; | |
153 | u32 reg_addr; | |
154 | ||
155 | if (port >= DSAF_XGE_NUM) | |
156 | return; | |
157 | ||
850bfa3b YZZ |
158 | reg_val |= XGMAC_TRX_CORE_SRST_M |
159 | << dsaf_dev->mac_cb[port]->port_rst_off; | |
511e6bc0 | 160 | |
a24274aa | 161 | if (!dereset) |
511e6bc0 | 162 | reg_addr = DSAF_SUB_SC_XGE_RESET_REQ_REG; |
163 | else | |
164 | reg_addr = DSAF_SUB_SC_XGE_RESET_DREQ_REG; | |
165 | ||
831d828b | 166 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 167 | } |
168 | ||
a24274aa KY |
169 | static void hns_dsaf_ge_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
170 | bool dereset) | |
511e6bc0 | 171 | { |
172 | u32 reg_val_1; | |
173 | u32 reg_val_2; | |
850bfa3b | 174 | u32 port_rst_off; |
511e6bc0 | 175 | |
176 | if (port >= DSAF_GE_NUM) | |
177 | return; | |
178 | ||
89a44093 | 179 | if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) { |
511e6bc0 | 180 | reg_val_1 = 0x1 << port; |
850bfa3b | 181 | port_rst_off = dsaf_dev->mac_cb[port]->port_rst_off; |
13ac695e S |
182 | /* there is difference between V1 and V2 in register.*/ |
183 | if (AE_IS_VER1(dsaf_dev->dsaf_ver)) | |
850bfa3b | 184 | reg_val_2 = 0x1041041 << port_rst_off; |
13ac695e | 185 | else |
850bfa3b | 186 | reg_val_2 = 0x2082082 << port_rst_off; |
511e6bc0 | 187 | |
a24274aa | 188 | if (!dereset) { |
831d828b | 189 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ1_REG, |
511e6bc0 | 190 | reg_val_1); |
191 | ||
831d828b | 192 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ0_REG, |
511e6bc0 | 193 | reg_val_2); |
194 | } else { | |
831d828b | 195 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ0_REG, |
511e6bc0 | 196 | reg_val_2); |
197 | ||
831d828b | 198 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ1_REG, |
511e6bc0 | 199 | reg_val_1); |
200 | } | |
201 | } else { | |
422c3107 YZZ |
202 | reg_val_1 = 0x15540 << dsaf_dev->reset_offset; |
203 | reg_val_2 = 0x100 << dsaf_dev->reset_offset; | |
511e6bc0 | 204 | |
a24274aa | 205 | if (!dereset) { |
831d828b | 206 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_REQ1_REG, |
511e6bc0 | 207 | reg_val_1); |
208 | ||
831d828b | 209 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_PPE_RESET_REQ_REG, |
511e6bc0 | 210 | reg_val_2); |
211 | } else { | |
831d828b | 212 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_GE_RESET_DREQ1_REG, |
511e6bc0 | 213 | reg_val_1); |
214 | ||
831d828b | 215 | dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_PPE_RESET_DREQ_REG, |
511e6bc0 | 216 | reg_val_2); |
217 | } | |
218 | } | |
219 | } | |
220 | ||
a24274aa KY |
221 | static void hns_ppe_srst_by_port(struct dsaf_device *dsaf_dev, u32 port, |
222 | bool dereset) | |
511e6bc0 | 223 | { |
224 | u32 reg_val = 0; | |
225 | u32 reg_addr; | |
226 | ||
850bfa3b | 227 | reg_val |= RESET_REQ_OR_DREQ << dsaf_dev->mac_cb[port]->port_rst_off; |
511e6bc0 | 228 | |
a24274aa | 229 | if (!dereset) |
511e6bc0 | 230 | reg_addr = DSAF_SUB_SC_PPE_RESET_REQ_REG; |
231 | else | |
232 | reg_addr = DSAF_SUB_SC_PPE_RESET_DREQ_REG; | |
233 | ||
831d828b | 234 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 235 | } |
236 | ||
a24274aa | 237 | static void hns_ppe_com_srst(struct dsaf_device *dsaf_dev, bool dereset) |
511e6bc0 | 238 | { |
511e6bc0 | 239 | u32 reg_val; |
240 | u32 reg_addr; | |
241 | ||
89a44093 | 242 | if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) { |
511e6bc0 | 243 | reg_val = RESET_REQ_OR_DREQ; |
a24274aa | 244 | if (!dereset) |
511e6bc0 | 245 | reg_addr = DSAF_SUB_SC_RCB_PPE_COM_RESET_REQ_REG; |
246 | else | |
247 | reg_addr = DSAF_SUB_SC_RCB_PPE_COM_RESET_DREQ_REG; | |
248 | ||
249 | } else { | |
422c3107 | 250 | reg_val = 0x100 << dsaf_dev->reset_offset; |
511e6bc0 | 251 | |
a24274aa | 252 | if (!dereset) |
511e6bc0 | 253 | reg_addr = DSAF_SUB_SC_PPE_RESET_REQ_REG; |
254 | else | |
255 | reg_addr = DSAF_SUB_SC_PPE_RESET_DREQ_REG; | |
256 | } | |
257 | ||
831d828b | 258 | dsaf_write_sub(dsaf_dev, reg_addr, reg_val); |
511e6bc0 | 259 | } |
260 | ||
261 | /** | |
262 | * hns_mac_get_sds_mode - get phy ifterface form serdes mode | |
263 | * @mac_cb: mac control block | |
264 | * retuen phy interface | |
265 | */ | |
a24274aa | 266 | static phy_interface_t hns_mac_get_phy_if(struct hns_mac_cb *mac_cb) |
511e6bc0 | 267 | { |
c1203fe7 SL |
268 | u32 mode; |
269 | u32 reg; | |
c1203fe7 | 270 | bool is_ver1 = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver); |
c1203fe7 | 271 | int mac_id = mac_cb->mac_id; |
0d768fc6 | 272 | phy_interface_t phy_if; |
511e6bc0 | 273 | |
0d768fc6 YZZ |
274 | if (is_ver1) { |
275 | if (HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev)) | |
276 | return PHY_INTERFACE_MODE_SGMII; | |
277 | ||
278 | if (mac_id >= 0 && mac_id <= 3) | |
279 | reg = HNS_MAC_HILINK4_REG; | |
511e6bc0 | 280 | else |
0d768fc6 YZZ |
281 | reg = HNS_MAC_HILINK3_REG; |
282 | } else{ | |
283 | if (!HNS_DSAF_IS_DEBUG(mac_cb->dsaf_dev) && mac_id <= 3) | |
284 | reg = HNS_MAC_HILINK4V2_REG; | |
c1203fe7 | 285 | else |
0d768fc6 | 286 | reg = HNS_MAC_HILINK3V2_REG; |
511e6bc0 | 287 | } |
0d768fc6 YZZ |
288 | |
289 | mode = dsaf_read_sub(mac_cb->dsaf_dev, reg); | |
290 | if (dsaf_get_bit(mode, mac_cb->port_mode_off)) | |
291 | phy_if = PHY_INTERFACE_MODE_XGMII; | |
292 | else | |
293 | phy_if = PHY_INTERFACE_MODE_SGMII; | |
294 | ||
511e6bc0 | 295 | return phy_if; |
296 | } | |
297 | ||
31d4446d YZZ |
298 | int hns_mac_get_sfp_prsnt(struct hns_mac_cb *mac_cb, int *sfp_prsnt) |
299 | { | |
300 | if (!mac_cb->cpld_ctrl) | |
301 | return -ENODEV; | |
302 | ||
303 | *sfp_prsnt = !dsaf_read_syscon(mac_cb->cpld_ctrl, mac_cb->cpld_ctrl_reg | |
304 | + MAC_SFP_PORT_OFFSET); | |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
511e6bc0 | 309 | /** |
310 | * hns_mac_config_sds_loopback - set loop back for serdes | |
311 | * @mac_cb: mac control block | |
312 | * retuen 0 == success | |
313 | */ | |
a24274aa | 314 | static int hns_mac_config_sds_loopback(struct hns_mac_cb *mac_cb, bool en) |
511e6bc0 | 315 | { |
316 | /* port 0-3 hilink4 base is serdes_vaddr + 0x00280000 | |
317 | * port 4-7 hilink3 base is serdes_vaddr + 0x00200000 | |
318 | */ | |
319 | u8 *base_addr = (u8 *)mac_cb->serdes_vaddr + | |
320 | (mac_cb->mac_id <= 3 ? 0x00280000 : 0x00200000); | |
321 | const u8 lane_id[] = { | |
322 | 0, /* mac 0 -> lane 0 */ | |
323 | 1, /* mac 1 -> lane 1 */ | |
324 | 2, /* mac 2 -> lane 2 */ | |
325 | 3, /* mac 3 -> lane 3 */ | |
326 | 2, /* mac 4 -> lane 2 */ | |
327 | 3, /* mac 5 -> lane 3 */ | |
328 | 0, /* mac 6 -> lane 0 */ | |
329 | 1 /* mac 7 -> lane 1 */ | |
330 | }; | |
331 | #define RX_CSR(lane, reg) ((0x4080 + (reg) * 0x0002 + (lane) * 0x0200) * 2) | |
332 | u64 reg_offset = RX_CSR(lane_id[mac_cb->mac_id], 0); | |
333 | ||
334 | int sfp_prsnt; | |
335 | int ret = hns_mac_get_sfp_prsnt(mac_cb, &sfp_prsnt); | |
336 | ||
652d39b0 | 337 | if (!mac_cb->phy_dev) { |
511e6bc0 | 338 | if (ret) |
339 | pr_info("please confirm sfp is present or not\n"); | |
340 | else | |
341 | if (!sfp_prsnt) | |
342 | pr_info("no sfp in this eth\n"); | |
343 | } | |
344 | ||
831d828b YZZ |
345 | if (mac_cb->serdes_ctrl) { |
346 | u32 origin = dsaf_read_syscon(mac_cb->serdes_ctrl, reg_offset); | |
347 | ||
a24274aa | 348 | dsaf_set_field(origin, 1ull << 10, 10, en); |
831d828b YZZ |
349 | dsaf_write_syscon(mac_cb->serdes_ctrl, reg_offset, origin); |
350 | } else { | |
a24274aa | 351 | dsaf_set_reg_field(base_addr, reg_offset, 1ull << 10, 10, en); |
831d828b | 352 | } |
511e6bc0 | 353 | |
354 | return 0; | |
355 | } | |
a24274aa KY |
356 | |
357 | struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) | |
358 | { | |
359 | struct dsaf_misc_op *misc_op; | |
360 | ||
361 | misc_op = devm_kzalloc(dsaf_dev->dev, sizeof(*misc_op), GFP_KERNEL); | |
362 | if (!misc_op) | |
363 | return NULL; | |
364 | ||
8413b3be KY |
365 | if (dev_of_node(dsaf_dev->dev)) { |
366 | misc_op->cpld_set_led = hns_cpld_set_led; | |
367 | misc_op->cpld_reset_led = cpld_led_reset; | |
368 | misc_op->cpld_set_led_id = cpld_set_led_id; | |
369 | ||
370 | misc_op->dsaf_reset = hns_dsaf_rst; | |
371 | misc_op->xge_srst = hns_dsaf_xge_srst_by_port; | |
372 | misc_op->xge_core_srst = hns_dsaf_xge_core_srst_by_port; | |
373 | misc_op->ge_srst = hns_dsaf_ge_srst_by_port; | |
374 | misc_op->ppe_srst = hns_ppe_srst_by_port; | |
375 | misc_op->ppe_comm_srst = hns_ppe_com_srst; | |
376 | ||
377 | misc_op->get_phy_if = hns_mac_get_phy_if; | |
378 | misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; | |
379 | ||
380 | misc_op->cfg_serdes_loopback = hns_mac_config_sds_loopback; | |
381 | } | |
a24274aa KY |
382 | |
383 | return (void *)misc_op; | |
384 | } |