]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
9b70e007 SG |
2 | /* |
3 | * Copyright (c) 2011 The Chromium OS Authors. | |
9b70e007 | 4 | * |
14727120 | 5 | * Patched for AX88772B by Antmicro Ltd <www.antmicro.com> |
9b70e007 SG |
6 | */ |
7 | ||
d678a59d | 8 | #include <common.h> |
fbc4b8af | 9 | #include <dm.h> |
f7ae49fc | 10 | #include <log.h> |
90526e9f | 11 | #include <net.h> |
9b70e007 | 12 | #include <usb.h> |
fbc4b8af | 13 | #include <malloc.h> |
cf92e05c | 14 | #include <memalign.h> |
c05ed00a | 15 | #include <linux/delay.h> |
9b70e007 SG |
16 | #include <linux/mii.h> |
17 | #include "usb_ether.h" | |
9b70e007 SG |
18 | |
19 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | |
20 | ||
21 | #define AX_CMD_SET_SW_MII 0x06 | |
22 | #define AX_CMD_READ_MII_REG 0x07 | |
23 | #define AX_CMD_WRITE_MII_REG 0x08 | |
24 | #define AX_CMD_SET_HW_MII 0x0a | |
02c8d8cc | 25 | #define AX_CMD_READ_EEPROM 0x0b |
9b70e007 SG |
26 | #define AX_CMD_READ_RX_CTL 0x0f |
27 | #define AX_CMD_WRITE_RX_CTL 0x10 | |
28 | #define AX_CMD_WRITE_IPG0 0x12 | |
29 | #define AX_CMD_READ_NODE_ID 0x13 | |
58f8fab8 | 30 | #define AX_CMD_WRITE_NODE_ID 0x14 |
9b70e007 SG |
31 | #define AX_CMD_READ_PHY_ID 0x19 |
32 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | |
33 | #define AX_CMD_WRITE_GPIOS 0x1f | |
34 | #define AX_CMD_SW_RESET 0x20 | |
35 | #define AX_CMD_SW_PHY_SELECT 0x22 | |
36 | ||
37 | #define AX_SWRESET_CLEAR 0x00 | |
38 | #define AX_SWRESET_PRTE 0x04 | |
39 | #define AX_SWRESET_PRL 0x08 | |
40 | #define AX_SWRESET_IPRL 0x20 | |
41 | #define AX_SWRESET_IPPD 0x40 | |
42 | ||
43 | #define AX88772_IPG0_DEFAULT 0x15 | |
44 | #define AX88772_IPG1_DEFAULT 0x0c | |
45 | #define AX88772_IPG2_DEFAULT 0x12 | |
46 | ||
47 | /* AX88772 & AX88178 Medium Mode Register */ | |
48 | #define AX_MEDIUM_PF 0x0080 | |
49 | #define AX_MEDIUM_JFE 0x0040 | |
50 | #define AX_MEDIUM_TFC 0x0020 | |
51 | #define AX_MEDIUM_RFC 0x0010 | |
52 | #define AX_MEDIUM_ENCK 0x0008 | |
53 | #define AX_MEDIUM_AC 0x0004 | |
54 | #define AX_MEDIUM_FD 0x0002 | |
55 | #define AX_MEDIUM_GM 0x0001 | |
56 | #define AX_MEDIUM_SM 0x1000 | |
57 | #define AX_MEDIUM_SBP 0x0800 | |
58 | #define AX_MEDIUM_PS 0x0200 | |
59 | #define AX_MEDIUM_RE 0x0100 | |
60 | ||
61 | #define AX88178_MEDIUM_DEFAULT \ | |
62 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | |
63 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | |
64 | AX_MEDIUM_RE) | |
65 | ||
66 | #define AX88772_MEDIUM_DEFAULT \ | |
67 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | |
68 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | |
69 | AX_MEDIUM_AC | AX_MEDIUM_RE) | |
70 | ||
71 | /* AX88772 & AX88178 RX_CTL values */ | |
cea6c8ce AB |
72 | #define AX_RX_CTL_SO 0x0080 |
73 | #define AX_RX_CTL_AB 0x0008 | |
9b70e007 SG |
74 | |
75 | #define AX_DEFAULT_RX_CTL \ | |
76 | (AX_RX_CTL_SO | AX_RX_CTL_AB) | |
77 | ||
78 | /* GPIO 2 toggles */ | |
79 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | |
80 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | |
81 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | |
82 | ||
83 | /* local defines */ | |
84 | #define ASIX_BASE_NAME "asx" | |
85 | #define USB_CTRL_SET_TIMEOUT 5000 | |
86 | #define USB_CTRL_GET_TIMEOUT 5000 | |
87 | #define USB_BULK_SEND_TIMEOUT 5000 | |
88 | #define USB_BULK_RECV_TIMEOUT 5000 | |
89 | ||
90 | #define AX_RX_URB_SIZE 2048 | |
91 | #define PHY_CONNECT_TIMEOUT 5000 | |
92 | ||
58f8fab8 LS |
93 | /* asix_flags defines */ |
94 | #define FLAG_NONE 0 | |
95 | #define FLAG_TYPE_AX88172 (1U << 0) | |
96 | #define FLAG_TYPE_AX88772 (1U << 1) | |
1dff9d0f LS |
97 | #define FLAG_TYPE_AX88772B (1U << 2) |
98 | #define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */ | |
58f8fab8 | 99 | |
9b70e007 | 100 | |
58f8fab8 LS |
101 | /* driver private */ |
102 | struct asix_private { | |
103 | int flags; | |
fbc4b8af | 104 | struct ueth_data ueth; |
58f8fab8 LS |
105 | }; |
106 | ||
9b70e007 SG |
107 | /* |
108 | * Asix infrastructure commands | |
109 | */ | |
110 | static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, | |
111 | u16 size, void *data) | |
112 | { | |
113 | int len; | |
114 | ||
115 | debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x " | |
116 | "size=%d\n", cmd, value, index, size); | |
117 | ||
118 | len = usb_control_msg( | |
119 | dev->pusb_dev, | |
120 | usb_sndctrlpipe(dev->pusb_dev, 0), | |
121 | cmd, | |
122 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
123 | value, | |
124 | index, | |
125 | data, | |
126 | size, | |
127 | USB_CTRL_SET_TIMEOUT); | |
128 | ||
129 | return len == size ? 0 : -1; | |
130 | } | |
131 | ||
132 | static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, | |
133 | u16 size, void *data) | |
134 | { | |
135 | int len; | |
136 | ||
137 | debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | |
138 | cmd, value, index, size); | |
139 | ||
140 | len = usb_control_msg( | |
141 | dev->pusb_dev, | |
142 | usb_rcvctrlpipe(dev->pusb_dev, 0), | |
143 | cmd, | |
144 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
145 | value, | |
146 | index, | |
147 | data, | |
148 | size, | |
149 | USB_CTRL_GET_TIMEOUT); | |
150 | return len == size ? 0 : -1; | |
151 | } | |
152 | ||
153 | static inline int asix_set_sw_mii(struct ueth_data *dev) | |
154 | { | |
155 | int ret; | |
156 | ||
157 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | |
158 | if (ret < 0) | |
159 | debug("Failed to enable software MII access\n"); | |
160 | return ret; | |
161 | } | |
162 | ||
163 | static inline int asix_set_hw_mii(struct ueth_data *dev) | |
164 | { | |
165 | int ret; | |
166 | ||
167 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | |
168 | if (ret < 0) | |
169 | debug("Failed to enable hardware MII access\n"); | |
170 | return ret; | |
171 | } | |
172 | ||
173 | static int asix_mdio_read(struct ueth_data *dev, int phy_id, int loc) | |
174 | { | |
c59ab092 | 175 | ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1); |
9b70e007 SG |
176 | |
177 | asix_set_sw_mii(dev); | |
c59ab092 | 178 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res); |
9b70e007 SG |
179 | asix_set_hw_mii(dev); |
180 | ||
181 | debug("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | |
c59ab092 | 182 | phy_id, loc, le16_to_cpu(*res)); |
9b70e007 | 183 | |
c59ab092 | 184 | return le16_to_cpu(*res); |
9b70e007 SG |
185 | } |
186 | ||
187 | static void | |
188 | asix_mdio_write(struct ueth_data *dev, int phy_id, int loc, int val) | |
189 | { | |
c59ab092 MV |
190 | ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1); |
191 | *res = cpu_to_le16(val); | |
9b70e007 SG |
192 | |
193 | debug("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | |
194 | phy_id, loc, val); | |
195 | asix_set_sw_mii(dev); | |
c59ab092 | 196 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, res); |
9b70e007 SG |
197 | asix_set_hw_mii(dev); |
198 | } | |
199 | ||
200 | /* | |
201 | * Asix "high level" commands | |
202 | */ | |
203 | static int asix_sw_reset(struct ueth_data *dev, u8 flags) | |
204 | { | |
205 | int ret; | |
206 | ||
207 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | |
208 | if (ret < 0) | |
209 | debug("Failed to send software reset: %02x\n", ret); | |
210 | else | |
211 | udelay(150 * 1000); | |
212 | ||
213 | return ret; | |
214 | } | |
215 | ||
216 | static inline int asix_get_phy_addr(struct ueth_data *dev) | |
217 | { | |
c59ab092 MV |
218 | ALLOC_CACHE_ALIGN_BUFFER(u8, buf, 2); |
219 | ||
9b70e007 SG |
220 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
221 | ||
222 | debug("asix_get_phy_addr()\n"); | |
223 | ||
224 | if (ret < 0) { | |
225 | debug("Error reading PHYID register: %02x\n", ret); | |
226 | goto out; | |
227 | } | |
0ed1eb6f | 228 | debug("asix_get_phy_addr() returning 0x%02x%02x\n", buf[0], buf[1]); |
9b70e007 SG |
229 | ret = buf[1]; |
230 | ||
231 | out: | |
232 | return ret; | |
233 | } | |
234 | ||
235 | static int asix_write_medium_mode(struct ueth_data *dev, u16 mode) | |
236 | { | |
237 | int ret; | |
238 | ||
239 | debug("asix_write_medium_mode() - mode = 0x%04x\n", mode); | |
240 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, | |
241 | 0, 0, NULL); | |
242 | if (ret < 0) { | |
243 | debug("Failed to write Medium Mode mode to 0x%04x: %02x\n", | |
244 | mode, ret); | |
245 | } | |
246 | return ret; | |
247 | } | |
248 | ||
249 | static u16 asix_read_rx_ctl(struct ueth_data *dev) | |
250 | { | |
c59ab092 MV |
251 | ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1); |
252 | ||
253 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, v); | |
9b70e007 SG |
254 | |
255 | if (ret < 0) | |
256 | debug("Error reading RX_CTL register: %02x\n", ret); | |
257 | else | |
c59ab092 | 258 | ret = le16_to_cpu(*v); |
9b70e007 SG |
259 | return ret; |
260 | } | |
261 | ||
262 | static int asix_write_rx_ctl(struct ueth_data *dev, u16 mode) | |
263 | { | |
264 | int ret; | |
265 | ||
266 | debug("asix_write_rx_ctl() - mode = 0x%04x\n", mode); | |
267 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | |
268 | if (ret < 0) { | |
269 | debug("Failed to write RX_CTL mode to 0x%04x: %02x\n", | |
270 | mode, ret); | |
271 | } | |
272 | return ret; | |
273 | } | |
274 | ||
275 | static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep) | |
276 | { | |
277 | int ret; | |
278 | ||
279 | debug("asix_write_gpio() - value = 0x%04x\n", value); | |
280 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | |
281 | if (ret < 0) { | |
282 | debug("Failed to write GPIO value 0x%04x: %02x\n", | |
283 | value, ret); | |
284 | } | |
285 | if (sleep) | |
286 | udelay(sleep * 1000); | |
287 | ||
288 | return ret; | |
289 | } | |
290 | ||
fbc4b8af | 291 | static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr) |
58f8fab8 | 292 | { |
58f8fab8 LS |
293 | int ret; |
294 | ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); | |
295 | ||
fbc4b8af | 296 | memcpy(buf, enetaddr, ETH_ALEN); |
58f8fab8 LS |
297 | |
298 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf); | |
299 | if (ret < 0) | |
300 | debug("Failed to set MAC address: %02x\n", ret); | |
301 | ||
302 | return ret; | |
303 | } | |
304 | ||
9b70e007 SG |
305 | /* |
306 | * mii commands | |
307 | */ | |
308 | ||
309 | /* | |
310 | * mii_nway_restart - restart NWay (autonegotiation) for this interface | |
311 | * | |
312 | * Returns 0 on success, negative on error. | |
313 | */ | |
314 | static int mii_nway_restart(struct ueth_data *dev) | |
315 | { | |
316 | int bmcr; | |
317 | int r = -1; | |
318 | ||
319 | /* if autoneg is off, it's an error */ | |
320 | bmcr = asix_mdio_read(dev, dev->phy_id, MII_BMCR); | |
321 | ||
322 | if (bmcr & BMCR_ANENABLE) { | |
323 | bmcr |= BMCR_ANRESTART; | |
324 | asix_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr); | |
325 | r = 0; | |
326 | } | |
327 | ||
328 | return r; | |
329 | } | |
330 | ||
fbc4b8af SG |
331 | static int asix_read_mac_common(struct ueth_data *dev, |
332 | struct asix_private *priv, uint8_t *enetaddr) | |
02c8d8cc | 333 | { |
02c8d8cc | 334 | ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); |
fbc4b8af | 335 | int i; |
02c8d8cc LS |
336 | |
337 | if (priv->flags & FLAG_EEPROM_MAC) { | |
338 | for (i = 0; i < (ETH_ALEN >> 1); i++) { | |
339 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, | |
340 | 0x04 + i, 0, 2, buf) < 0) { | |
341 | debug("Failed to read SROM address 04h.\n"); | |
342 | return -1; | |
343 | } | |
fbc4b8af | 344 | memcpy(enetaddr + i * 2, buf, 2); |
02c8d8cc LS |
345 | } |
346 | } else { | |
347 | if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf) | |
348 | < 0) { | |
349 | debug("Failed to read MAC address.\n"); | |
350 | return -1; | |
351 | } | |
fbc4b8af | 352 | memcpy(enetaddr, buf, ETH_ALEN); |
02c8d8cc LS |
353 | } |
354 | ||
355 | return 0; | |
356 | } | |
357 | ||
5fae53d0 | 358 | static int asix_basic_reset(struct ueth_data *dev) |
9b70e007 SG |
359 | { |
360 | int embd_phy; | |
9b70e007 | 361 | u16 rx_ctl; |
9b70e007 SG |
362 | |
363 | if (asix_write_gpio(dev, | |
364 | AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0) | |
5fae53d0 | 365 | return -1; |
9b70e007 SG |
366 | |
367 | /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ | |
368 | embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | |
369 | if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, | |
370 | embd_phy, 0, 0, NULL) < 0) { | |
371 | debug("Select PHY #1 failed\n"); | |
5fae53d0 | 372 | return -1; |
9b70e007 SG |
373 | } |
374 | ||
375 | if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0) | |
5fae53d0 | 376 | return -1; |
9b70e007 SG |
377 | |
378 | if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0) | |
5fae53d0 | 379 | return -1; |
9b70e007 SG |
380 | |
381 | if (embd_phy) { | |
382 | if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0) | |
5fae53d0 | 383 | return -1; |
9b70e007 SG |
384 | } else { |
385 | if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0) | |
5fae53d0 | 386 | return -1; |
9b70e007 SG |
387 | } |
388 | ||
389 | rx_ctl = asix_read_rx_ctl(dev); | |
390 | debug("RX_CTL is 0x%04x after software reset\n", rx_ctl); | |
391 | if (asix_write_rx_ctl(dev, 0x0000) < 0) | |
5fae53d0 | 392 | return -1; |
9b70e007 SG |
393 | |
394 | rx_ctl = asix_read_rx_ctl(dev); | |
395 | debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | |
396 | ||
9b70e007 SG |
397 | dev->phy_id = asix_get_phy_addr(dev); |
398 | if (dev->phy_id < 0) | |
399 | debug("Failed to read phy id\n"); | |
400 | ||
9b70e007 SG |
401 | asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); |
402 | asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE, | |
403 | ADVERTISE_ALL | ADVERTISE_CSMA); | |
404 | mii_nway_restart(dev); | |
405 | ||
406 | if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0) | |
4edcf0a3 | 407 | return -1; |
9b70e007 SG |
408 | |
409 | if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | |
410 | AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | |
411 | AX88772_IPG2_DEFAULT, 0, NULL) < 0) { | |
412 | debug("Write IPG,IPG1,IPG2 failed\n"); | |
4edcf0a3 | 413 | return -1; |
9b70e007 SG |
414 | } |
415 | ||
4edcf0a3 JW |
416 | return 0; |
417 | } | |
418 | ||
14727120 | 419 | static int asix_init_common(struct ueth_data *dev, uint8_t *enetaddr) |
4edcf0a3 | 420 | { |
4edcf0a3 JW |
421 | int timeout = 0; |
422 | #define TIMEOUT_RESOLUTION 50 /* ms */ | |
423 | int link_detected; | |
424 | ||
425 | debug("** %s()\n", __func__); | |
426 | ||
cea6c8ce | 427 | if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0) |
14727120 MZ |
428 | goto out_err; |
429 | ||
430 | if (asix_write_hwaddr_common(dev, enetaddr) < 0) | |
9b70e007 SG |
431 | goto out_err; |
432 | ||
433 | do { | |
434 | link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) & | |
435 | BMSR_LSTATUS; | |
436 | if (!link_detected) { | |
437 | if (timeout == 0) | |
438 | printf("Waiting for Ethernet connection... "); | |
439 | udelay(TIMEOUT_RESOLUTION * 1000); | |
440 | timeout += TIMEOUT_RESOLUTION; | |
441 | } | |
442 | } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT); | |
443 | if (link_detected) { | |
444 | if (timeout != 0) | |
445 | printf("done.\n"); | |
446 | } else { | |
447 | printf("unable to connect.\n"); | |
448 | goto out_err; | |
449 | } | |
450 | ||
14727120 MZ |
451 | /* |
452 | * Wait some more to avoid timeout on first transfer | |
453 | * (e.g. EHCI timed out on TD - token=0x8008d80) | |
454 | */ | |
455 | mdelay(25); | |
456 | ||
9b70e007 SG |
457 | return 0; |
458 | out_err: | |
459 | return -1; | |
460 | } | |
461 | ||
fbc4b8af | 462 | static int asix_send_common(struct ueth_data *dev, void *packet, int length) |
9b70e007 | 463 | { |
9b70e007 SG |
464 | int err; |
465 | u32 packet_len; | |
466 | int actual_len; | |
c59ab092 MV |
467 | ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg, |
468 | PKTSIZE + sizeof(packet_len)); | |
9b70e007 SG |
469 | |
470 | debug("** %s(), len %d\n", __func__, length); | |
471 | ||
472 | packet_len = (((length) ^ 0x0000ffff) << 16) + (length); | |
473 | cpu_to_le32s(&packet_len); | |
474 | ||
475 | memcpy(msg, &packet_len, sizeof(packet_len)); | |
476 | memcpy(msg + sizeof(packet_len), (void *)packet, length); | |
9b70e007 SG |
477 | |
478 | err = usb_bulk_msg(dev->pusb_dev, | |
479 | usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), | |
480 | (void *)msg, | |
481 | length + sizeof(packet_len), | |
482 | &actual_len, | |
483 | USB_BULK_SEND_TIMEOUT); | |
4c5998b7 | 484 | debug("Tx: len = %zu, actual = %u, err = %d\n", |
9b70e007 SG |
485 | length + sizeof(packet_len), actual_len, err); |
486 | ||
487 | return err; | |
488 | } | |
489 | ||
fbc4b8af SG |
490 | static int asix_eth_start(struct udevice *dev) |
491 | { | |
c69cda25 | 492 | struct eth_pdata *pdata = dev_get_plat(dev); |
fbc4b8af SG |
493 | struct asix_private *priv = dev_get_priv(dev); |
494 | ||
14727120 | 495 | return asix_init_common(&priv->ueth, pdata->enetaddr); |
fbc4b8af SG |
496 | } |
497 | ||
498 | void asix_eth_stop(struct udevice *dev) | |
499 | { | |
500 | debug("** %s()\n", __func__); | |
501 | } | |
502 | ||
503 | int asix_eth_send(struct udevice *dev, void *packet, int length) | |
504 | { | |
505 | struct asix_private *priv = dev_get_priv(dev); | |
506 | ||
507 | return asix_send_common(&priv->ueth, packet, length); | |
508 | } | |
509 | ||
510 | int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp) | |
511 | { | |
512 | struct asix_private *priv = dev_get_priv(dev); | |
513 | struct ueth_data *ueth = &priv->ueth; | |
514 | uint8_t *ptr; | |
515 | int ret, len; | |
516 | u32 packet_len; | |
517 | ||
518 | len = usb_ether_get_rx_bytes(ueth, &ptr); | |
519 | debug("%s: first try, len=%d\n", __func__, len); | |
520 | if (!len) { | |
521 | if (!(flags & ETH_RECV_CHECK_DEVICE)) | |
522 | return -EAGAIN; | |
523 | ret = usb_ether_receive(ueth, AX_RX_URB_SIZE); | |
524 | if (ret == -EAGAIN) | |
525 | return ret; | |
526 | ||
527 | len = usb_ether_get_rx_bytes(ueth, &ptr); | |
528 | debug("%s: second try, len=%d\n", __func__, len); | |
529 | } | |
530 | ||
531 | /* | |
532 | * 1st 4 bytes contain the length of the actual data as two | |
533 | * complementary 16-bit words. Extract the length of the data. | |
534 | */ | |
535 | if (len < sizeof(packet_len)) { | |
536 | debug("Rx: incomplete packet length\n"); | |
537 | goto err; | |
538 | } | |
539 | memcpy(&packet_len, ptr, sizeof(packet_len)); | |
540 | le32_to_cpus(&packet_len); | |
541 | if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) { | |
542 | debug("Rx: malformed packet length: %#x (%#x:%#x)\n", | |
543 | packet_len, (~packet_len >> 16) & 0x7ff, | |
544 | packet_len & 0x7ff); | |
545 | goto err; | |
546 | } | |
547 | packet_len = packet_len & 0x7ff; | |
548 | if (packet_len > len - sizeof(packet_len)) { | |
549 | debug("Rx: too large packet: %d\n", packet_len); | |
550 | goto err; | |
551 | } | |
552 | ||
553 | *packetp = ptr + sizeof(packet_len); | |
554 | return packet_len; | |
555 | ||
556 | err: | |
557 | usb_ether_advance_rxbuf(ueth, -1); | |
558 | return -EINVAL; | |
559 | } | |
560 | ||
561 | static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len) | |
562 | { | |
563 | struct asix_private *priv = dev_get_priv(dev); | |
564 | ||
565 | if (packet_len & 1) | |
566 | packet_len++; | |
567 | usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len); | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | int asix_write_hwaddr(struct udevice *dev) | |
573 | { | |
c69cda25 | 574 | struct eth_pdata *pdata = dev_get_plat(dev); |
fbc4b8af SG |
575 | struct asix_private *priv = dev_get_priv(dev); |
576 | ||
577 | if (priv->flags & FLAG_TYPE_AX88172) | |
578 | return -ENOSYS; | |
579 | ||
580 | return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr); | |
581 | } | |
582 | ||
583 | static int asix_eth_probe(struct udevice *dev) | |
584 | { | |
c69cda25 | 585 | struct eth_pdata *pdata = dev_get_plat(dev); |
fbc4b8af SG |
586 | struct asix_private *priv = dev_get_priv(dev); |
587 | struct ueth_data *ss = &priv->ueth; | |
588 | int ret; | |
589 | ||
590 | priv->flags = dev->driver_data; | |
591 | ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE); | |
592 | if (ret) | |
593 | return ret; | |
594 | ||
595 | ret = asix_basic_reset(ss); | |
596 | if (ret) | |
597 | goto err; | |
598 | ||
599 | /* Get the MAC address */ | |
600 | ret = asix_read_mac_common(ss, priv, pdata->enetaddr); | |
601 | if (ret) | |
602 | goto err; | |
603 | debug("MAC %pM\n", pdata->enetaddr); | |
604 | ||
605 | return 0; | |
606 | ||
607 | err: | |
608 | return usb_ether_deregister(ss); | |
609 | } | |
610 | ||
611 | static const struct eth_ops asix_eth_ops = { | |
612 | .start = asix_eth_start, | |
613 | .send = asix_eth_send, | |
614 | .recv = asix_eth_recv, | |
615 | .free_pkt = asix_free_pkt, | |
616 | .stop = asix_eth_stop, | |
617 | .write_hwaddr = asix_write_hwaddr, | |
618 | }; | |
619 | ||
620 | U_BOOT_DRIVER(asix_eth) = { | |
621 | .name = "asix_eth", | |
622 | .id = UCLASS_ETH, | |
623 | .probe = asix_eth_probe, | |
624 | .ops = &asix_eth_ops, | |
41575d8e | 625 | .priv_auto = sizeof(struct asix_private), |
caa4daa2 | 626 | .plat_auto = sizeof(struct eth_pdata), |
fbc4b8af SG |
627 | }; |
628 | ||
629 | static const struct usb_device_id asix_eth_id_table[] = { | |
630 | /* Apple USB Ethernet Adapter */ | |
631 | { USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 }, | |
632 | /* D-Link DUB-E100 H/W Ver B1 */ | |
633 | { USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 }, | |
634 | /* D-Link DUB-E100 H/W Ver C1 */ | |
635 | { USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 }, | |
636 | /* Cables-to-Go USB Ethernet Adapter */ | |
637 | { USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 }, | |
638 | /* Trendnet TU2-ET100 V3.0R */ | |
639 | { USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 }, | |
640 | /* SMC */ | |
641 | { USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 }, | |
642 | /* MSI - ASIX 88772a */ | |
643 | { USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 }, | |
644 | /* Linksys 200M v2.1 */ | |
645 | { USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 }, | |
646 | /* 0Q0 cable ethernet */ | |
647 | { USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 }, | |
648 | /* DLink DUB-E100 H/W Ver B1 Alternate */ | |
649 | { USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 }, | |
650 | /* ASIX 88772B */ | |
651 | { USB_DEVICE(0x0b95, 0x772b), | |
652 | .driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC }, | |
653 | { USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B }, | |
654 | { } /* Terminating entry */ | |
655 | }; | |
656 | ||
657 | U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table); |