blob: 5f56f6f2dde433d02bff3180c239546dbccd93c4 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass246d6932011-02-16 11:14:34 -08002/*
3 * Copyright (c) 2011 The Chromium OS Authors.
Simon Glass246d6932011-02-16 11:14:34 -08004 *
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +02005 * Patched for AX88772B by Antmicro Ltd <www.antmicro.com>
Simon Glass246d6932011-02-16 11:14:34 -08006 */
7
8#include <common.h>
Simon Glassf58369f2015-07-06 16:47:54 -06009#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Simon Glass274e0b02020-05-10 11:39:56 -060011#include <net.h>
Simon Glass246d6932011-02-16 11:14:34 -080012#include <usb.h>
Simon Glassf58369f2015-07-06 16:47:54 -060013#include <malloc.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060014#include <memalign.h>
Simon Glass246d6932011-02-16 11:14:34 -080015#include <linux/mii.h>
16#include "usb_ether.h"
Simon Glass246d6932011-02-16 11:14:34 -080017
18/* ASIX AX8817X based USB 2.0 Ethernet Devices */
19
20#define AX_CMD_SET_SW_MII 0x06
21#define AX_CMD_READ_MII_REG 0x07
22#define AX_CMD_WRITE_MII_REG 0x08
23#define AX_CMD_SET_HW_MII 0x0a
Lucas Stach95c359b2012-08-22 11:05:00 +000024#define AX_CMD_READ_EEPROM 0x0b
Simon Glass246d6932011-02-16 11:14:34 -080025#define AX_CMD_READ_RX_CTL 0x0f
26#define AX_CMD_WRITE_RX_CTL 0x10
27#define AX_CMD_WRITE_IPG0 0x12
28#define AX_CMD_READ_NODE_ID 0x13
Lucas Stachfc9a7582012-08-22 11:04:59 +000029#define AX_CMD_WRITE_NODE_ID 0x14
Simon Glass246d6932011-02-16 11:14:34 -080030#define AX_CMD_READ_PHY_ID 0x19
31#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
32#define AX_CMD_WRITE_GPIOS 0x1f
33#define AX_CMD_SW_RESET 0x20
34#define AX_CMD_SW_PHY_SELECT 0x22
35
36#define AX_SWRESET_CLEAR 0x00
37#define AX_SWRESET_PRTE 0x04
38#define AX_SWRESET_PRL 0x08
39#define AX_SWRESET_IPRL 0x20
40#define AX_SWRESET_IPPD 0x40
41
42#define AX88772_IPG0_DEFAULT 0x15
43#define AX88772_IPG1_DEFAULT 0x0c
44#define AX88772_IPG2_DEFAULT 0x12
45
46/* AX88772 & AX88178 Medium Mode Register */
47#define AX_MEDIUM_PF 0x0080
48#define AX_MEDIUM_JFE 0x0040
49#define AX_MEDIUM_TFC 0x0020
50#define AX_MEDIUM_RFC 0x0010
51#define AX_MEDIUM_ENCK 0x0008
52#define AX_MEDIUM_AC 0x0004
53#define AX_MEDIUM_FD 0x0002
54#define AX_MEDIUM_GM 0x0001
55#define AX_MEDIUM_SM 0x1000
56#define AX_MEDIUM_SBP 0x0800
57#define AX_MEDIUM_PS 0x0200
58#define AX_MEDIUM_RE 0x0100
59
60#define AX88178_MEDIUM_DEFAULT \
61 (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
62 AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
63 AX_MEDIUM_RE)
64
65#define AX88772_MEDIUM_DEFAULT \
66 (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
67 AX_MEDIUM_TFC | AX_MEDIUM_PS | \
68 AX_MEDIUM_AC | AX_MEDIUM_RE)
69
70/* AX88772 & AX88178 RX_CTL values */
Alban Bedel3cf1a962016-09-10 03:54:09 +020071#define AX_RX_CTL_SO 0x0080
72#define AX_RX_CTL_AB 0x0008
Simon Glass246d6932011-02-16 11:14:34 -080073
74#define AX_DEFAULT_RX_CTL \
75 (AX_RX_CTL_SO | AX_RX_CTL_AB)
76
77/* GPIO 2 toggles */
78#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
79#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
80#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
81
82/* local defines */
83#define ASIX_BASE_NAME "asx"
84#define USB_CTRL_SET_TIMEOUT 5000
85#define USB_CTRL_GET_TIMEOUT 5000
86#define USB_BULK_SEND_TIMEOUT 5000
87#define USB_BULK_RECV_TIMEOUT 5000
88
89#define AX_RX_URB_SIZE 2048
90#define PHY_CONNECT_TIMEOUT 5000
91
Lucas Stachfc9a7582012-08-22 11:04:59 +000092/* asix_flags defines */
93#define FLAG_NONE 0
94#define FLAG_TYPE_AX88172 (1U << 0)
95#define FLAG_TYPE_AX88772 (1U << 1)
Lucas Stach06e46932012-08-22 11:05:01 +000096#define FLAG_TYPE_AX88772B (1U << 2)
97#define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */
Lucas Stachfc9a7582012-08-22 11:04:59 +000098
Simon Glass246d6932011-02-16 11:14:34 -080099
Lucas Stachfc9a7582012-08-22 11:04:59 +0000100/* driver private */
101struct asix_private {
102 int flags;
Simon Glassf58369f2015-07-06 16:47:54 -0600103#ifdef CONFIG_DM_ETH
104 struct ueth_data ueth;
105#endif
Lucas Stachfc9a7582012-08-22 11:04:59 +0000106};
107
Simon Glassf58369f2015-07-06 16:47:54 -0600108#ifndef CONFIG_DM_ETH
109/* local vars */
110static int curr_eth_dev; /* index for name of next device detected */
111#endif
112
Simon Glass246d6932011-02-16 11:14:34 -0800113/*
114 * Asix infrastructure commands
115 */
116static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
117 u16 size, void *data)
118{
119 int len;
120
121 debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x "
122 "size=%d\n", cmd, value, index, size);
123
124 len = usb_control_msg(
125 dev->pusb_dev,
126 usb_sndctrlpipe(dev->pusb_dev, 0),
127 cmd,
128 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
129 value,
130 index,
131 data,
132 size,
133 USB_CTRL_SET_TIMEOUT);
134
135 return len == size ? 0 : -1;
136}
137
138static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index,
139 u16 size, void *data)
140{
141 int len;
142
143 debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
144 cmd, value, index, size);
145
146 len = usb_control_msg(
147 dev->pusb_dev,
148 usb_rcvctrlpipe(dev->pusb_dev, 0),
149 cmd,
150 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
151 value,
152 index,
153 data,
154 size,
155 USB_CTRL_GET_TIMEOUT);
156 return len == size ? 0 : -1;
157}
158
159static inline int asix_set_sw_mii(struct ueth_data *dev)
160{
161 int ret;
162
163 ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
164 if (ret < 0)
165 debug("Failed to enable software MII access\n");
166 return ret;
167}
168
169static inline int asix_set_hw_mii(struct ueth_data *dev)
170{
171 int ret;
172
173 ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
174 if (ret < 0)
175 debug("Failed to enable hardware MII access\n");
176 return ret;
177}
178
179static int asix_mdio_read(struct ueth_data *dev, int phy_id, int loc)
180{
Marek Vasut115436e2012-06-24 14:17:56 +0000181 ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
Simon Glass246d6932011-02-16 11:14:34 -0800182
183 asix_set_sw_mii(dev);
Marek Vasut115436e2012-06-24 14:17:56 +0000184 asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res);
Simon Glass246d6932011-02-16 11:14:34 -0800185 asix_set_hw_mii(dev);
186
187 debug("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
Marek Vasut115436e2012-06-24 14:17:56 +0000188 phy_id, loc, le16_to_cpu(*res));
Simon Glass246d6932011-02-16 11:14:34 -0800189
Marek Vasut115436e2012-06-24 14:17:56 +0000190 return le16_to_cpu(*res);
Simon Glass246d6932011-02-16 11:14:34 -0800191}
192
193static void
194asix_mdio_write(struct ueth_data *dev, int phy_id, int loc, int val)
195{
Marek Vasut115436e2012-06-24 14:17:56 +0000196 ALLOC_CACHE_ALIGN_BUFFER(__le16, res, 1);
197 *res = cpu_to_le16(val);
Simon Glass246d6932011-02-16 11:14:34 -0800198
199 debug("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
200 phy_id, loc, val);
201 asix_set_sw_mii(dev);
Marek Vasut115436e2012-06-24 14:17:56 +0000202 asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, res);
Simon Glass246d6932011-02-16 11:14:34 -0800203 asix_set_hw_mii(dev);
204}
205
206/*
207 * Asix "high level" commands
208 */
209static int asix_sw_reset(struct ueth_data *dev, u8 flags)
210{
211 int ret;
212
213 ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
214 if (ret < 0)
215 debug("Failed to send software reset: %02x\n", ret);
216 else
217 udelay(150 * 1000);
218
219 return ret;
220}
221
222static inline int asix_get_phy_addr(struct ueth_data *dev)
223{
Marek Vasut115436e2012-06-24 14:17:56 +0000224 ALLOC_CACHE_ALIGN_BUFFER(u8, buf, 2);
225
Simon Glass246d6932011-02-16 11:14:34 -0800226 int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
227
228 debug("asix_get_phy_addr()\n");
229
230 if (ret < 0) {
231 debug("Error reading PHYID register: %02x\n", ret);
232 goto out;
233 }
Marek Vasuta61b9662011-09-23 21:13:35 +0200234 debug("asix_get_phy_addr() returning 0x%02x%02x\n", buf[0], buf[1]);
Simon Glass246d6932011-02-16 11:14:34 -0800235 ret = buf[1];
236
237out:
238 return ret;
239}
240
241static int asix_write_medium_mode(struct ueth_data *dev, u16 mode)
242{
243 int ret;
244
245 debug("asix_write_medium_mode() - mode = 0x%04x\n", mode);
246 ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode,
247 0, 0, NULL);
248 if (ret < 0) {
249 debug("Failed to write Medium Mode mode to 0x%04x: %02x\n",
250 mode, ret);
251 }
252 return ret;
253}
254
255static u16 asix_read_rx_ctl(struct ueth_data *dev)
256{
Marek Vasut115436e2012-06-24 14:17:56 +0000257 ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1);
258
259 int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, v);
Simon Glass246d6932011-02-16 11:14:34 -0800260
261 if (ret < 0)
262 debug("Error reading RX_CTL register: %02x\n", ret);
263 else
Marek Vasut115436e2012-06-24 14:17:56 +0000264 ret = le16_to_cpu(*v);
Simon Glass246d6932011-02-16 11:14:34 -0800265 return ret;
266}
267
268static int asix_write_rx_ctl(struct ueth_data *dev, u16 mode)
269{
270 int ret;
271
272 debug("asix_write_rx_ctl() - mode = 0x%04x\n", mode);
273 ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
274 if (ret < 0) {
275 debug("Failed to write RX_CTL mode to 0x%04x: %02x\n",
276 mode, ret);
277 }
278 return ret;
279}
280
281static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
282{
283 int ret;
284
285 debug("asix_write_gpio() - value = 0x%04x\n", value);
286 ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
287 if (ret < 0) {
288 debug("Failed to write GPIO value 0x%04x: %02x\n",
289 value, ret);
290 }
291 if (sleep)
292 udelay(sleep * 1000);
293
294 return ret;
295}
296
Simon Glassf58369f2015-07-06 16:47:54 -0600297static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
Lucas Stachfc9a7582012-08-22 11:04:59 +0000298{
Lucas Stachfc9a7582012-08-22 11:04:59 +0000299 int ret;
300 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
301
Simon Glassf58369f2015-07-06 16:47:54 -0600302 memcpy(buf, enetaddr, ETH_ALEN);
Lucas Stachfc9a7582012-08-22 11:04:59 +0000303
304 ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
305 if (ret < 0)
306 debug("Failed to set MAC address: %02x\n", ret);
307
308 return ret;
309}
310
Simon Glass246d6932011-02-16 11:14:34 -0800311/*
312 * mii commands
313 */
314
315/*
316 * mii_nway_restart - restart NWay (autonegotiation) for this interface
317 *
318 * Returns 0 on success, negative on error.
319 */
320static int mii_nway_restart(struct ueth_data *dev)
321{
322 int bmcr;
323 int r = -1;
324
325 /* if autoneg is off, it's an error */
326 bmcr = asix_mdio_read(dev, dev->phy_id, MII_BMCR);
327
328 if (bmcr & BMCR_ANENABLE) {
329 bmcr |= BMCR_ANRESTART;
330 asix_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
331 r = 0;
332 }
333
334 return r;
335}
336
Simon Glassf58369f2015-07-06 16:47:54 -0600337static int asix_read_mac_common(struct ueth_data *dev,
338 struct asix_private *priv, uint8_t *enetaddr)
Lucas Stach95c359b2012-08-22 11:05:00 +0000339{
Lucas Stach95c359b2012-08-22 11:05:00 +0000340 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
Simon Glassf58369f2015-07-06 16:47:54 -0600341 int i;
Lucas Stach95c359b2012-08-22 11:05:00 +0000342
343 if (priv->flags & FLAG_EEPROM_MAC) {
344 for (i = 0; i < (ETH_ALEN >> 1); i++) {
345 if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,
346 0x04 + i, 0, 2, buf) < 0) {
347 debug("Failed to read SROM address 04h.\n");
348 return -1;
349 }
Simon Glassf58369f2015-07-06 16:47:54 -0600350 memcpy(enetaddr + i * 2, buf, 2);
Lucas Stach95c359b2012-08-22 11:05:00 +0000351 }
352 } else {
353 if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
354 < 0) {
355 debug("Failed to read MAC address.\n");
356 return -1;
357 }
Simon Glassf58369f2015-07-06 16:47:54 -0600358 memcpy(enetaddr, buf, ETH_ALEN);
Lucas Stach95c359b2012-08-22 11:05:00 +0000359 }
360
361 return 0;
362}
363
Lucas Stacha0d5d032012-08-22 11:04:58 +0000364static int asix_basic_reset(struct ueth_data *dev)
Simon Glass246d6932011-02-16 11:14:34 -0800365{
366 int embd_phy;
Simon Glass246d6932011-02-16 11:14:34 -0800367 u16 rx_ctl;
Simon Glass246d6932011-02-16 11:14:34 -0800368
369 if (asix_write_gpio(dev,
370 AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000371 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800372
373 /* 0x10 is the phy id of the embedded 10/100 ethernet phy */
374 embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
375 if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
376 embd_phy, 0, 0, NULL) < 0) {
377 debug("Select PHY #1 failed\n");
Lucas Stacha0d5d032012-08-22 11:04:58 +0000378 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800379 }
380
381 if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000382 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800383
384 if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000385 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800386
387 if (embd_phy) {
388 if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000389 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800390 } else {
391 if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000392 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800393 }
394
395 rx_ctl = asix_read_rx_ctl(dev);
396 debug("RX_CTL is 0x%04x after software reset\n", rx_ctl);
397 if (asix_write_rx_ctl(dev, 0x0000) < 0)
Lucas Stacha0d5d032012-08-22 11:04:58 +0000398 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800399
400 rx_ctl = asix_read_rx_ctl(dev);
401 debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
402
Simon Glass246d6932011-02-16 11:14:34 -0800403 dev->phy_id = asix_get_phy_addr(dev);
404 if (dev->phy_id < 0)
405 debug("Failed to read phy id\n");
406
Simon Glass246d6932011-02-16 11:14:34 -0800407 asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
408 asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
409 ADVERTISE_ALL | ADVERTISE_CSMA);
410 mii_nway_restart(dev);
411
412 if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0)
Julius Werner160298f2013-05-11 13:35:02 -0700413 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800414
415 if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
416 AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
417 AX88772_IPG2_DEFAULT, 0, NULL) < 0) {
418 debug("Write IPG,IPG1,IPG2 failed\n");
Julius Werner160298f2013-05-11 13:35:02 -0700419 return -1;
Simon Glass246d6932011-02-16 11:14:34 -0800420 }
421
Julius Werner160298f2013-05-11 13:35:02 -0700422 return 0;
423}
424
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200425static int asix_init_common(struct ueth_data *dev, uint8_t *enetaddr)
Julius Werner160298f2013-05-11 13:35:02 -0700426{
Julius Werner160298f2013-05-11 13:35:02 -0700427 int timeout = 0;
428#define TIMEOUT_RESOLUTION 50 /* ms */
429 int link_detected;
430
431 debug("** %s()\n", __func__);
432
Alban Bedel3cf1a962016-09-10 03:54:09 +0200433 if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200434 goto out_err;
435
436 if (asix_write_hwaddr_common(dev, enetaddr) < 0)
Simon Glass246d6932011-02-16 11:14:34 -0800437 goto out_err;
438
439 do {
440 link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) &
441 BMSR_LSTATUS;
442 if (!link_detected) {
443 if (timeout == 0)
444 printf("Waiting for Ethernet connection... ");
445 udelay(TIMEOUT_RESOLUTION * 1000);
446 timeout += TIMEOUT_RESOLUTION;
447 }
448 } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
449 if (link_detected) {
450 if (timeout != 0)
451 printf("done.\n");
452 } else {
453 printf("unable to connect.\n");
454 goto out_err;
455 }
456
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200457 /*
458 * Wait some more to avoid timeout on first transfer
459 * (e.g. EHCI timed out on TD - token=0x8008d80)
460 */
461 mdelay(25);
462
Simon Glass246d6932011-02-16 11:14:34 -0800463 return 0;
464out_err:
465 return -1;
466}
467
Simon Glassf58369f2015-07-06 16:47:54 -0600468static int asix_send_common(struct ueth_data *dev, void *packet, int length)
Simon Glass246d6932011-02-16 11:14:34 -0800469{
Simon Glass246d6932011-02-16 11:14:34 -0800470 int err;
471 u32 packet_len;
472 int actual_len;
Marek Vasut115436e2012-06-24 14:17:56 +0000473 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg,
474 PKTSIZE + sizeof(packet_len));
Simon Glass246d6932011-02-16 11:14:34 -0800475
476 debug("** %s(), len %d\n", __func__, length);
477
478 packet_len = (((length) ^ 0x0000ffff) << 16) + (length);
479 cpu_to_le32s(&packet_len);
480
481 memcpy(msg, &packet_len, sizeof(packet_len));
482 memcpy(msg + sizeof(packet_len), (void *)packet, length);
Simon Glass246d6932011-02-16 11:14:34 -0800483
484 err = usb_bulk_msg(dev->pusb_dev,
485 usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),
486 (void *)msg,
487 length + sizeof(packet_len),
488 &actual_len,
489 USB_BULK_SEND_TIMEOUT);
Thierry Reding7306e9c2015-03-20 12:41:23 +0100490 debug("Tx: len = %zu, actual = %u, err = %d\n",
Simon Glass246d6932011-02-16 11:14:34 -0800491 length + sizeof(packet_len), actual_len, err);
492
493 return err;
494}
495
Simon Glassf58369f2015-07-06 16:47:54 -0600496#ifndef CONFIG_DM_ETH
497/*
498 * Asix callbacks
499 */
500static int asix_init(struct eth_device *eth, bd_t *bd)
501{
502 struct ueth_data *dev = (struct ueth_data *)eth->priv;
503
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200504 return asix_init_common(dev, eth->enetaddr);
Simon Glassf58369f2015-07-06 16:47:54 -0600505}
506
507static int asix_send(struct eth_device *eth, void *packet, int length)
508{
509 struct ueth_data *dev = (struct ueth_data *)eth->priv;
510
511 return asix_send_common(dev, packet, length);
512}
513
Simon Glass246d6932011-02-16 11:14:34 -0800514static int asix_recv(struct eth_device *eth)
515{
516 struct ueth_data *dev = (struct ueth_data *)eth->priv;
Marek Vasut115436e2012-06-24 14:17:56 +0000517 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
Simon Glass246d6932011-02-16 11:14:34 -0800518 unsigned char *buf_ptr;
519 int err;
520 int actual_len;
521 u32 packet_len;
522
523 debug("** %s()\n", __func__);
524
525 err = usb_bulk_msg(dev->pusb_dev,
526 usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
527 (void *)recv_buf,
528 AX_RX_URB_SIZE,
529 &actual_len,
530 USB_BULK_RECV_TIMEOUT);
531 debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
532 actual_len, err);
533 if (err != 0) {
534 debug("Rx: failed to receive\n");
535 return -1;
536 }
537 if (actual_len > AX_RX_URB_SIZE) {
538 debug("Rx: received too many bytes %d\n", actual_len);
539 return -1;
540 }
541
542 buf_ptr = recv_buf;
543 while (actual_len > 0) {
544 /*
545 * 1st 4 bytes contain the length of the actual data as two
546 * complementary 16-bit words. Extract the length of the data.
547 */
548 if (actual_len < sizeof(packet_len)) {
549 debug("Rx: incomplete packet length\n");
550 return -1;
551 }
552 memcpy(&packet_len, buf_ptr, sizeof(packet_len));
553 le32_to_cpus(&packet_len);
Lucas Stach06e46932012-08-22 11:05:01 +0000554 if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
Simon Glass246d6932011-02-16 11:14:34 -0800555 debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
Lucas Stach06e46932012-08-22 11:05:01 +0000556 packet_len, (~packet_len >> 16) & 0x7ff,
557 packet_len & 0x7ff);
Simon Glass246d6932011-02-16 11:14:34 -0800558 return -1;
559 }
Lucas Stach06e46932012-08-22 11:05:01 +0000560 packet_len = packet_len & 0x7ff;
Simon Glass246d6932011-02-16 11:14:34 -0800561 if (packet_len > actual_len - sizeof(packet_len)) {
562 debug("Rx: too large packet: %d\n", packet_len);
563 return -1;
564 }
565
566 /* Notify net stack */
Joe Hershberger9f09a362015-04-08 01:41:06 -0500567 net_process_received_packet(buf_ptr + sizeof(packet_len),
568 packet_len);
Simon Glass246d6932011-02-16 11:14:34 -0800569
570 /* Adjust for next iteration. Packets are padded to 16-bits */
571 if (packet_len & 1)
572 packet_len++;
573 actual_len -= sizeof(packet_len) + packet_len;
574 buf_ptr += sizeof(packet_len) + packet_len;
575 }
576
577 return err;
578}
579
580static void asix_halt(struct eth_device *eth)
581{
582 debug("** %s()\n", __func__);
583}
584
Simon Glassf58369f2015-07-06 16:47:54 -0600585static int asix_write_hwaddr(struct eth_device *eth)
586{
587 struct ueth_data *dev = (struct ueth_data *)eth->priv;
588
589 return asix_write_hwaddr_common(dev, eth->enetaddr);
590}
591
Simon Glass246d6932011-02-16 11:14:34 -0800592/*
593 * Asix probing functions
594 */
595void asix_eth_before_probe(void)
596{
597 curr_eth_dev = 0;
598}
599
600struct asix_dongle {
601 unsigned short vendor;
602 unsigned short product;
Lucas Stachfc9a7582012-08-22 11:04:59 +0000603 int flags;
Simon Glass246d6932011-02-16 11:14:34 -0800604};
605
Jeroen Hofstee5528f4c2014-06-17 21:14:17 +0200606static const struct asix_dongle asix_dongles[] = {
Lucas Stachfc9a7582012-08-22 11:04:59 +0000607 { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */
608 { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */
Pierre Aubert75caa352013-06-27 09:01:54 +0200609 { 0x2001, 0x1a02, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver C1 */
Lucas Stachfc9a7582012-08-22 11:04:59 +0000610 /* Cables-to-Go USB Ethernet Adapter */
611 { 0x0b95, 0x772a, FLAG_TYPE_AX88772 },
612 { 0x0b95, 0x7720, FLAG_TYPE_AX88772 }, /* Trendnet TU2-ET100 V3.0R */
613 { 0x0b95, 0x1720, FLAG_TYPE_AX88172 }, /* SMC */
614 { 0x0db0, 0xa877, FLAG_TYPE_AX88772 }, /* MSI - ASIX 88772a */
615 { 0x13b1, 0x0018, FLAG_TYPE_AX88172 }, /* Linksys 200M v2.1 */
616 { 0x1557, 0x7720, FLAG_TYPE_AX88772 }, /* 0Q0 cable ethernet */
617 /* DLink DUB-E100 H/W Ver B1 Alternate */
618 { 0x2001, 0x3c05, FLAG_TYPE_AX88772 },
Lucas Stach06e46932012-08-22 11:05:01 +0000619 /* ASIX 88772B */
620 { 0x0b95, 0x772b, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
Alexandre Courbotceeb40c2014-10-09 12:43:30 +0900621 { 0x0b95, 0x7e2b, FLAG_TYPE_AX88772B },
Lucas Stachfc9a7582012-08-22 11:04:59 +0000622 { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */
Simon Glass246d6932011-02-16 11:14:34 -0800623};
624
625/* Probe to see if a new device is actually an asix device */
626int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
627 struct ueth_data *ss)
628{
629 struct usb_interface *iface;
630 struct usb_interface_descriptor *iface_desc;
Lucas Stach06e46932012-08-22 11:05:01 +0000631 int ep_in_found = 0, ep_out_found = 0;
Simon Glass246d6932011-02-16 11:14:34 -0800632 int i;
633
634 /* let's examine the device now */
635 iface = &dev->config.if_desc[ifnum];
636 iface_desc = &dev->config.if_desc[ifnum].desc;
637
638 for (i = 0; asix_dongles[i].vendor != 0; i++) {
639 if (dev->descriptor.idVendor == asix_dongles[i].vendor &&
640 dev->descriptor.idProduct == asix_dongles[i].product)
641 /* Found a supported dongle */
642 break;
643 }
644
645 if (asix_dongles[i].vendor == 0)
646 return 0;
647
648 memset(ss, 0, sizeof(struct ueth_data));
649
650 /* At this point, we know we've got a live one */
651 debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
652 dev->descriptor.idVendor, dev->descriptor.idProduct);
653
654 /* Initialize the ueth_data structure with some useful info */
655 ss->ifnum = ifnum;
656 ss->pusb_dev = dev;
657 ss->subclass = iface_desc->bInterfaceSubClass;
658 ss->protocol = iface_desc->bInterfaceProtocol;
659
Lucas Stachfc9a7582012-08-22 11:04:59 +0000660 /* alloc driver private */
661 ss->dev_priv = calloc(1, sizeof(struct asix_private));
662 if (!ss->dev_priv)
663 return 0;
664
665 ((struct asix_private *)ss->dev_priv)->flags = asix_dongles[i].flags;
666
Simon Glass246d6932011-02-16 11:14:34 -0800667 /*
668 * We are expecting a minimum of 3 endpoints - in, out (bulk), and
669 * int. We will ignore any others.
670 */
671 for (i = 0; i < iface_desc->bNumEndpoints; i++) {
672 /* is it an BULK endpoint? */
673 if ((iface->ep_desc[i].bmAttributes &
674 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
Lucas Stach06e46932012-08-22 11:05:01 +0000675 u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
676 if (ep_addr & USB_DIR_IN) {
677 if (!ep_in_found) {
678 ss->ep_in = ep_addr &
679 USB_ENDPOINT_NUMBER_MASK;
680 ep_in_found = 1;
681 }
682 } else {
683 if (!ep_out_found) {
684 ss->ep_out = ep_addr &
685 USB_ENDPOINT_NUMBER_MASK;
686 ep_out_found = 1;
687 }
688 }
Simon Glass246d6932011-02-16 11:14:34 -0800689 }
690
691 /* is it an interrupt endpoint? */
692 if ((iface->ep_desc[i].bmAttributes &
693 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
694 ss->ep_int = iface->ep_desc[i].bEndpointAddress &
695 USB_ENDPOINT_NUMBER_MASK;
696 ss->irqinterval = iface->ep_desc[i].bInterval;
697 }
698 }
699 debug("Endpoints In %d Out %d Int %d\n",
700 ss->ep_in, ss->ep_out, ss->ep_int);
701
702 /* Do some basic sanity checks, and bail if we find a problem */
703 if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
704 !ss->ep_in || !ss->ep_out || !ss->ep_int) {
705 debug("Problems with device\n");
706 return 0;
707 }
708 dev->privptr = (void *)ss;
709 return 1;
710}
711
712int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
713 struct eth_device *eth)
714{
Lucas Stachfc9a7582012-08-22 11:04:59 +0000715 struct asix_private *priv = (struct asix_private *)ss->dev_priv;
716
Simon Glass246d6932011-02-16 11:14:34 -0800717 if (!eth) {
718 debug("%s: missing parameter.\n", __func__);
719 return 0;
720 }
721 sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++);
722 eth->init = asix_init;
723 eth->send = asix_send;
724 eth->recv = asix_recv;
725 eth->halt = asix_halt;
Lucas Stachfc9a7582012-08-22 11:04:59 +0000726 if (!(priv->flags & FLAG_TYPE_AX88172))
727 eth->write_hwaddr = asix_write_hwaddr;
Simon Glass246d6932011-02-16 11:14:34 -0800728 eth->priv = ss;
729
Lucas Stacha0d5d032012-08-22 11:04:58 +0000730 if (asix_basic_reset(ss))
731 return 0;
Lucas Stach95c359b2012-08-22 11:05:00 +0000732
733 /* Get the MAC address */
Simon Glassf58369f2015-07-06 16:47:54 -0600734 if (asix_read_mac_common(ss, priv, eth->enetaddr))
Lucas Stach95c359b2012-08-22 11:05:00 +0000735 return 0;
736 debug("MAC %pM\n", eth->enetaddr);
Lucas Stacha0d5d032012-08-22 11:04:58 +0000737
Simon Glass246d6932011-02-16 11:14:34 -0800738 return 1;
739}
Simon Glassf58369f2015-07-06 16:47:54 -0600740#endif
741
742#ifdef CONFIG_DM_ETH
743static int asix_eth_start(struct udevice *dev)
744{
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200745 struct eth_pdata *pdata = dev_get_platdata(dev);
Simon Glassf58369f2015-07-06 16:47:54 -0600746 struct asix_private *priv = dev_get_priv(dev);
747
Marcel Ziswiler7bbbb3c2015-08-05 17:16:59 +0200748 return asix_init_common(&priv->ueth, pdata->enetaddr);
Simon Glassf58369f2015-07-06 16:47:54 -0600749}
750
751void asix_eth_stop(struct udevice *dev)
752{
753 debug("** %s()\n", __func__);
754}
755
756int asix_eth_send(struct udevice *dev, void *packet, int length)
757{
758 struct asix_private *priv = dev_get_priv(dev);
759
760 return asix_send_common(&priv->ueth, packet, length);
761}
762
763int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
764{
765 struct asix_private *priv = dev_get_priv(dev);
766 struct ueth_data *ueth = &priv->ueth;
767 uint8_t *ptr;
768 int ret, len;
769 u32 packet_len;
770
771 len = usb_ether_get_rx_bytes(ueth, &ptr);
772 debug("%s: first try, len=%d\n", __func__, len);
773 if (!len) {
774 if (!(flags & ETH_RECV_CHECK_DEVICE))
775 return -EAGAIN;
776 ret = usb_ether_receive(ueth, AX_RX_URB_SIZE);
777 if (ret == -EAGAIN)
778 return ret;
779
780 len = usb_ether_get_rx_bytes(ueth, &ptr);
781 debug("%s: second try, len=%d\n", __func__, len);
782 }
783
784 /*
785 * 1st 4 bytes contain the length of the actual data as two
786 * complementary 16-bit words. Extract the length of the data.
787 */
788 if (len < sizeof(packet_len)) {
789 debug("Rx: incomplete packet length\n");
790 goto err;
791 }
792 memcpy(&packet_len, ptr, sizeof(packet_len));
793 le32_to_cpus(&packet_len);
794 if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
795 debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
796 packet_len, (~packet_len >> 16) & 0x7ff,
797 packet_len & 0x7ff);
798 goto err;
799 }
800 packet_len = packet_len & 0x7ff;
801 if (packet_len > len - sizeof(packet_len)) {
802 debug("Rx: too large packet: %d\n", packet_len);
803 goto err;
804 }
805
806 *packetp = ptr + sizeof(packet_len);
807 return packet_len;
808
809err:
810 usb_ether_advance_rxbuf(ueth, -1);
811 return -EINVAL;
812}
813
814static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
815{
816 struct asix_private *priv = dev_get_priv(dev);
817
818 if (packet_len & 1)
819 packet_len++;
820 usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
821
822 return 0;
823}
824
825int asix_write_hwaddr(struct udevice *dev)
826{
827 struct eth_pdata *pdata = dev_get_platdata(dev);
828 struct asix_private *priv = dev_get_priv(dev);
829
830 if (priv->flags & FLAG_TYPE_AX88172)
831 return -ENOSYS;
832
833 return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
834}
835
836static int asix_eth_probe(struct udevice *dev)
837{
838 struct eth_pdata *pdata = dev_get_platdata(dev);
839 struct asix_private *priv = dev_get_priv(dev);
840 struct ueth_data *ss = &priv->ueth;
841 int ret;
842
843 priv->flags = dev->driver_data;
844 ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
845 if (ret)
846 return ret;
847
848 ret = asix_basic_reset(ss);
849 if (ret)
850 goto err;
851
852 /* Get the MAC address */
853 ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
854 if (ret)
855 goto err;
856 debug("MAC %pM\n", pdata->enetaddr);
857
858 return 0;
859
860err:
861 return usb_ether_deregister(ss);
862}
863
864static const struct eth_ops asix_eth_ops = {
865 .start = asix_eth_start,
866 .send = asix_eth_send,
867 .recv = asix_eth_recv,
868 .free_pkt = asix_free_pkt,
869 .stop = asix_eth_stop,
870 .write_hwaddr = asix_write_hwaddr,
871};
872
873U_BOOT_DRIVER(asix_eth) = {
874 .name = "asix_eth",
875 .id = UCLASS_ETH,
876 .probe = asix_eth_probe,
877 .ops = &asix_eth_ops,
878 .priv_auto_alloc_size = sizeof(struct asix_private),
879 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
880};
881
882static const struct usb_device_id asix_eth_id_table[] = {
883 /* Apple USB Ethernet Adapter */
884 { USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
885 /* D-Link DUB-E100 H/W Ver B1 */
886 { USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
887 /* D-Link DUB-E100 H/W Ver C1 */
888 { USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
889 /* Cables-to-Go USB Ethernet Adapter */
890 { USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
891 /* Trendnet TU2-ET100 V3.0R */
892 { USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
893 /* SMC */
894 { USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
895 /* MSI - ASIX 88772a */
896 { USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
897 /* Linksys 200M v2.1 */
898 { USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
899 /* 0Q0 cable ethernet */
900 { USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
901 /* DLink DUB-E100 H/W Ver B1 Alternate */
902 { USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
903 /* ASIX 88772B */
904 { USB_DEVICE(0x0b95, 0x772b),
905 .driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
906 { USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
907 { } /* Terminating entry */
908};
909
910U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
911#endif