1/*
2 *	ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
3 *	Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
4 *	Distributed under the terms of the MIT license.
5 *
6 *	Heavily based on code of the
7 *	Driver for USB Ethernet Control Model devices
8 *	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
9 *	Distributed under the terms of the MIT license.
10 *
11 */
12
13
14#include "AX88772Device.h"
15
16#include <net/if_media.h>
17
18#include "ASIXVendorRequests.h"
19#include "Settings.h"
20
21
22// Most of vendor requests for all supported chip types use the same
23// constants (see ASIXVendorRequests.h) but the layout of request data
24// may be slightly diferrent for specific chip type. Below is a quick
25// reference for AX88772 vendor requests data layout.
26
27// READ_RXTX_SRAM,		//C002_AA0B_0C00_0800 Rx/Tx SRAM Read
28// WRITE_RXTX_SRAM,		//4003_AA0B_0C00_0800 Rx/Tx SRAM Write
29// SW_MII_OP,			//4006_0000_0000_0000 SW Serial Management Control
30// READ_MII,			//c007_aa00_cc00_0200 PHY Read
31// WRITE_MII,			//4008_aa00_cc00_0200 PHY Write
32// READ_MII_OP_MODE,	//c009_0000_0000_0100 Serial Management Status
33// HW_MII_OP,			//400a_0000_0000_0000 HW Serial Management Control
34// READ_SROM,			//C00B_AA00_0000_0200 SROM Read
35// WRITE_SROM,			//400C_AA00_CCDD_0000 SROM Write
36// WRITE_SROM_ENABLE,	//400D_0000_0000_0000 SROM Write Enable
37// WRITE_SROM_DISABLE,	//400E_0000_0000_0000 SROM Write Disable
38// READ_RX_CONTROL,		//C00F_0000_0000_0200 Read Rx Control
39// WRITE_RX_CONTROL,	//4010_AABB_0000_0000 Write Rx Control
40// READ_IPGS,			//C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register
41// WRITE_IPGS,			//4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register
42// READ_NODEID,			//C013_0000_0000_0600 Read Node ID
43// WRITE_NODEID,		//4014_0000_0000_0600 Write Node ID
44// READ_MF_ARRAY,		//C015_0000_0000_0800 Read Multicast Filter Array
45// WRITE_MF_ARRAY,		//4016_0000_0000_0800 Write Multicast Filter Array
46// READ_TEST,			//4017_AA00_0000_0000 Write Test Register
47// READ_PHYID,			//C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address
48// READ_MEDIUM_STATUS,	//C01A_0000_0000_0200 Read Medium Status
49// WRITE_MEDIUM_MODE,	//401B_AABB_0000_0000 Write Medium Mode Register
50// GET_MONITOR_MODE,	//C01C_0000_0000_0100 Read Monitor Mode Status
51// SET_MONITOR_MODE,	//401D_AA00_0000_0000 Write Monitor Mode Register
52// READ_GPIOS,			//C01E_0000_0000_0100 Read GPIOs Status
53// WRITE_GPIOS,			//401F_AA00_0000_0000 Write GPIOs
54// WRITE_SOFT_RESET,	//4020_AA00_0000_0000 Write Software Reset
55// READ_PHY_SEL_STATE,	//C021_AA00_0000_0100 Read Software PHY Select Status
56// WRITE_PHY_SEL,		//4022_AA00_0000_0000 Write Software PHY Select
57
58// RX Control Register bits
59// RXCTL_PROMISCUOUS,	// forward all frames up to the host
60// RXCTL_ALL_MULTICAT,	// forward all multicast frames up to the host
61// RXCTL_SEP,			// forward frames with CRC error up to the host
62// RXCTL_BROADCAST,		// forward broadcast frames up to the host
63// RXCTL_MULTICAST,		// forward multicast frames that are
64//							matching to multicast filter up to the host
65// RXCTL_AP,			// forward unicast frames that are matching
66//							to multicast filter up to the host
67// RXCTL_START,			// ethernet MAC start operating
68// RXCTL_USB_MFB,		// Max Frame Burst TX on USB
69
70
71// PHY IDs request answer data layout
72struct AX88772_PhyIDs {
73	uint8 SecPhyID;
74	uint8 PriPhyID2;
75} _PACKED;
76
77
78// Medium state bits
79enum AX88772_MediumState {
80	MEDIUM_STATE_FD		= 0x0002,
81	MEDIUM_STATE_BIT2	= 0x0004, // must be always set
82	MEDIUM_STATE_RFC	= 0x0010,
83	MEDIUM_STATE_TFC	= 0x0020,
84	MEDIUM_STATE_PF_ON	= 0x0040,
85	MEDIUM_STATE_PF_OFF	= 0x0000,
86	MEDIUM_STATE_RE	   	= 0x0100,
87	MEDIUM_STATE_PS_100	= 0x0200,
88	MEDIUM_STATE_PS_10 	= 0x0000,
89	MEDIUM_STATE_SBP1  	= 0x0800,
90	MEDIUM_STATE_SBP0  	= 0x0000,
91	MEDIUM_STATE_SM_ON 	= 0x1000
92};
93
94
95// Monitor Mode bits
96enum AX88772_MonitorMode {
97	MONITOR_MODE_MOM	= 0x01,
98	MONITOR_MODE_RWLU	= 0x02,
99	MONITOR_MODE_RWMP	= 0x04,
100	MONITOR_MODE_US 	= 0x10
101};
102
103
104// General Purpose I/O Register
105enum AX88772_GPIO {
106	GPIO_OO_0EN	= 0x01,
107	GPIO_IO_0	= 0x02,
108	GPIO_OO_1EN	= 0x04,
109	GPIO_IO_1	= 0x08,
110	GPIO_OO_2EN	= 0x10,
111	GPIO_IO_2	= 0x20,
112	GPIO_RSE	= 0x80
113};
114
115
116// Software Reset Register bits
117enum AX88772_SoftwareReset {
118	SW_RESET_CLR	= 0x00,
119	SW_RESET_RR		= 0x01,
120	SW_RESET_RT		= 0x02,
121	SW_RESET_PRTE	= 0x04,
122	SW_RESET_PRL	= 0x08,
123	SW_RESET_BZ		= 0x10,
124	SW_RESET_IPRL	= 0x20,
125	SW_RESET_IPPD	= 0x40
126};
127
128
129// Software PHY Select Status
130enum AX88772_SoftwarePHYSelStatus {
131	SW_PHY_SEL_STATUS_EXT		= 0x00,
132	SW_PHY_SEL_STATUS_INT		= 0x01,
133	SW_PHY_SEL_STATUS_ASEL		= 0x02,
134	SW_PHY_SEL_STATUS_SS_MII	= 0x04,
135	SW_PHY_SEL_STATUS_SS_RVRS_MII	= 0x08,
136	SW_PHY_SEL_STATUS_SS_RVRS_GMII	= 0x0C,
137	SW_PHY_SEL_STATUS_SS_ENB	= 0x10
138};
139
140
141// Notification data layout
142struct AX88772_Notify {
143	uint8  btA1;
144	uint8  bt01;
145	uint8  btBB; // AX88772_BBState below
146	uint8  bt03;
147	uint16 regCCDD;
148	uint16 regEEFF;
149} _PACKED;
150
151
152// Link-State bits
153enum AX88772_BBState {
154	LINK_STATE_PPLS		= 0x01,
155	LINK_STATE_SPLS		= 0x02,
156	LINK_STATE_FLE		= 0x04,
157	LINK_STATE_MDINT	= 0x08
158};
159
160// RX Control Register bits (772B)
161enum ASIX772RXControl {
162	RXCTL_HDR_TYPE_0	= 0x0000,
163	RXCTL_HDR_TYPE_1	= 0x0100,
164	RXCTL_HDR_IPALIGN	= 0x0200,
165	RXCTL_ADD_CHKSUM	= 0x0400,
166};
167
168// EEPROM Map.
169enum AX88772B_EEPROM {
170	EEPROM_772B_NODE_ID	= 0x04,
171	EEPROM_772B_PHY_PWRCFG	= 0x18
172};
173
174enum AX88772B_MFB {
175	AX88772B_MFB_2K = 0,
176	AX88772B_MFB_4K = 1,
177	AX88772B_MFB_6K = 2,
178	AX88772B_MFB_8K = 3,
179	AX88772B_MFB_16K = 4,
180	AX88772B_MFB_20K = 5,
181	AX88772B_MFB_24K = 6,
182	AX88772B_MFB_32K = 7,
183	AX88772B_MFB_Count = 8
184};
185
186struct _AX88772B_MFB {
187	size_t ByteCount;
188	size_t Threshold;
189	size_t Size;
190
191} AX88772B_MFBTable[AX88772B_MFB_Count] = {
192	{ 0x8000, 0x8001, 2048 },
193	{ 0x8100, 0x8147, 4096 },
194	{ 0x8200, 0x81EB, 6144 },
195	{ 0x8300, 0x83D7, 8192 },
196	{ 0x8400, 0x851E, 16384 },
197	{ 0x8500, 0x8666, 20480 },
198	{ 0x8600, 0x87AE, 24576 },
199	{ 0x8700, 0x8A3D, 32768 }
200};
201
202const uint16 maxFrameSize = 1536;
203
204
205AX88772Device::AX88772Device(usb_device device, DeviceInfo& deviceInfo)
206	:
207	ASIXDevice(device, deviceInfo)
208{
209	fStatus = InitDevice();
210}
211
212
213status_t
214AX88772Device::InitDevice()
215{
216	fFrameSize = maxFrameSize;
217	fUseTRXHeader = true;
218
219	fReadNodeIDRequest = READ_NODEID;
220
221	fNotifyBufferLength = sizeof(AX88772_Notify);
222	fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength);
223	if (fNotifyBuffer == NULL) {
224		TRACE_ALWAYS("Error of allocating memory for notify buffer.\n");
225		return B_NO_MEMORY;
226	}
227
228	return B_OK;
229}
230
231
232status_t
233AX88772Device::ReadMACAddress(ether_address_t *address)
234{
235	if (fDeviceInfo.fType != DeviceInfo::AX88772B)
236		return ASIXDevice::ReadMACAddress(address);
237
238	// Auto-loaded default station address from internal ROM is
239	// 00:00:00:00:00:00 such that an explicit access to EEPROM
240	// is required to get real station address.
241	for (size_t i = 0; i < sizeof(ether_address_t) / 2; i++) {
242		size_t actual_length = 0;
243		uint16 addr = 0;
244		status_t result = gUSBModule->send_request(fDevice,
245			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_SROM,
246			EEPROM_772B_NODE_ID + i, 0, sizeof(addr), &addr, &actual_length);
247		if (result != B_OK) {
248			TRACE_ALWAYS("Error reading MAC[%d] address:%#010x\n", i, result);
249			return result;
250		}
251
252		address->ebyte[i * 2 + 0] = (uint8)addr;
253		address->ebyte[i * 2 + 1] = (uint8)(addr >> 8);
254	}
255
256	return B_OK;
257}
258
259
260status_t
261AX88772Device::SetupDevice(bool deviceReplugged)
262{
263	status_t result = ASIXDevice::SetupDevice(deviceReplugged);
264	if (result != B_OK) {
265		return result;
266	}
267
268	result = fMII.Init(fDevice);
269
270	switch (fDeviceInfo.fType) {
271		case DeviceInfo::AX88772A:
272			result = _SetupAX88772A();
273			break;
274		case DeviceInfo::AX88772B:
275			result = _SetupAX88772B();
276			break;
277		default:
278			result = _SetupAX88772();
279			break;
280	}
281
282	if (result != B_OK)
283		return result;
284
285	result = fMII.SetupPHY();
286	if (result != B_OK) {
287		return result;
288	}
289
290	size_t actualLength = 0;
291	result = gUSBModule->send_request(fDevice,
292		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_MEDIUM_MODE,
293		MEDIUM_STATE_FD | MEDIUM_STATE_BIT2 | MEDIUM_STATE_RFC
294		| MEDIUM_STATE_TFC | MEDIUM_STATE_RE | MEDIUM_STATE_PS_100,
295		0, 0, 0, &actualLength);
296
297	if (result != B_OK) {
298		TRACE_ALWAYS("Error of setting medium mode: %#010x\n", result);
299	}
300
301	TRACE_RET(result);
302	return result;
303}
304
305
306status_t
307AX88772Device::_SetupAX88772()
308{
309	size_t actualLength = 0;
310	// enable GPIO2 - magic from FreeBSD's if_axe
311	uint16 GPIOs = GPIO_OO_2EN | GPIO_IO_2 | GPIO_RSE;
312	status_t result = gUSBModule->send_request(fDevice,
313		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_GPIOS,
314		GPIOs, 0, 0, 0, &actualLength);
315
316	if (result != B_OK) {
317		TRACE_ALWAYS("Error of wrinting GPIOs: %#010x\n", result);
318		return result;
319	}
320
321	// select PHY
322	bool useEmbeddedPHY = fMII.PHYID() == PHYIDEmbedded;
323	uint16 selectPHY = useEmbeddedPHY
324		? SW_PHY_SEL_STATUS_INT : SW_PHY_SEL_STATUS_EXT;
325
326	result = gUSBModule->send_request(fDevice,
327		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
328		WRITE_PHY_SEL, selectPHY, 0, 0, 0, &actualLength);
329	snooze(10000);
330
331	TRACE("Selecting %s PHY[%#02x].\n",
332		useEmbeddedPHY ? "embedded" : "external", selectPHY);
333
334	if (result != B_OK) {
335		TRACE_ALWAYS("Error of selecting PHY:%#010x\n", result);
336		return result;
337	}
338
339	struct SWReset {
340		uint16 		reset;
341		bigtime_t	delay;
342	} resetCommands[] = {
343	// EMBEDDED PHY
344		// power down and reset state, pin reset state
345		{ SW_RESET_CLR, 60000 },
346		// power down/reset state, pin operating state
347		{ SW_RESET_PRL | SW_RESET_IPPD, 150000 },
348		// power up, reset
349		{ SW_RESET_PRL, 0 },
350		// power up, operating
351		{ SW_RESET_PRL | SW_RESET_IPRL, 0 },
352	// EXTERNAL PHY
353		// power down/reset state, pin operating state
354		{ SW_RESET_PRL | SW_RESET_IPPD, 0 }
355	};
356
357	size_t from = useEmbeddedPHY ? 0 : 4;
358	size_t to   = useEmbeddedPHY ? 3 : 4;
359
360	for (size_t i = from; i <= to; i++) {
361		result = gUSBModule->send_request(fDevice,
362			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET,
363			resetCommands[i].reset, 0, 0, 0, &actualLength);
364
365		snooze(resetCommands[i].delay);
366
367		if (result != B_OK) {
368			TRACE_ALWAYS("Error of SW reset command %d:[%#04x]: %#010x\n",
369				i, resetCommands[i].reset, result);
370			return result;
371		}
372	}
373
374	snooze(150000);
375
376	return B_OK;
377}
378
379
380status_t
381AX88772Device::_WakeupPHY()
382{
383	// select PHY
384	bool useEmbeddedPHY = fMII.PHYID() == PHYIDEmbedded;
385	uint16 selectPHY = useEmbeddedPHY
386		? SW_PHY_SEL_STATUS_INT : SW_PHY_SEL_STATUS_EXT;
387
388	selectPHY |= SW_PHY_SEL_STATUS_SS_MII | SW_PHY_SEL_STATUS_SS_ENB;
389
390	size_t actualLength = 0;
391	status_t result = gUSBModule->send_request(fDevice,
392		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_PHY_SEL,
393		selectPHY, 0, 0, 0, &actualLength);
394	snooze(31000);
395
396	TRACE("Selecting %s PHY[%#02x].\n",
397		useEmbeddedPHY ? "embedded" : "external", selectPHY);
398
399	if (result != B_OK) {
400		TRACE_ALWAYS("Error of selecting PHY:%#010x\n", result);
401		return result;
402	}
403
404	struct SWReset {
405		uint16 		reset;
406		bigtime_t	delay;
407	} resetCommands[] = {
408		{ SW_RESET_IPRL | SW_RESET_IPPD, 250000 },
409		{ SW_RESET_IPRL, 1000000 },
410		{ SW_RESET_CLR, 31000 },
411		{ SW_RESET_IPRL, 31000 }
412	};
413
414	for (size_t i = 0; i < B_COUNT_OF(resetCommands); i++) {
415		result = gUSBModule->send_request(fDevice,
416			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_SOFT_RESET,
417			resetCommands[i].reset, 0, 0, 0, &actualLength);
418
419		snooze(resetCommands[i].delay);
420
421		if (result != B_OK) {
422			TRACE_ALWAYS("Error of SW reset command %d:[%#04x]: %#010x\n",
423				i, resetCommands[i].reset, result);
424			return result;
425		}
426	}
427
428	return B_OK;
429}
430
431
432status_t
433AX88772Device::_SetupAX88772A()
434{
435	// Reload EEPROM
436	size_t actualLength = 0;
437	status_t result = gUSBModule->send_request(fDevice,
438		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_GPIOS,
439		GPIO_RSE, 0, 0, 0, &actualLength);
440
441	if (result != B_OK) {
442		TRACE_ALWAYS("Error of reloading EEPROM: %#010x\n", result);
443		return result;
444	}
445
446	result = _WakeupPHY();
447	if (result != B_OK)
448		return result;
449
450	fIPG[0] = 0x15;
451	fIPG[1] = 0x16;
452	fIPG[2] = 0x1A;
453
454	return B_OK;
455}
456
457
458status_t
459AX88772Device::_SetupAX88772B()
460{
461	// Reload EEPROM
462	size_t actualLength = 0;
463	status_t result = gUSBModule->send_request(fDevice,
464		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_GPIOS,
465		GPIO_RSE, 0, 0, 0, &actualLength);
466
467	if (result != B_OK) {
468		TRACE_ALWAYS("Error of reloading EEPROM: %#010x\n", result);
469		return result;
470	}
471
472	result = _WakeupPHY();
473	if (result != B_OK)
474		return result;
475
476	fIPG[0] = 0x15;
477	fIPG[1] = 0x16;
478	fIPG[2] = 0x1A;
479
480	return B_OK;
481}
482
483
484status_t
485AX88772Device::StartDevice()
486{
487	size_t actualLength = 0;
488	status_t result = gUSBModule->send_request(fDevice,
489		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_IPGS,
490		0, 0, sizeof(fIPG), fIPG, &actualLength);
491
492	if (result != B_OK) {
493		TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result);
494		return result;
495	}
496
497	if (actualLength != sizeof(fIPG)) {
498		TRACE_ALWAYS("Mismatch of written IPGs data. "
499			"%d bytes of %d written.\n", actualLength, sizeof(fIPG));
500
501	}
502
503	uint16 rxcontrol = 0;
504
505	// AX88772B uses different maximum frame burst configuration.
506	if (fDeviceInfo.fType == DeviceInfo::AX88772B) {
507		result = gUSBModule->send_request(fDevice,
508			USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, WRITE_RXCONTROL_CFG,
509			AX88772B_MFBTable[AX88772B_MFB_2K].ByteCount,
510			AX88772B_MFBTable[AX88772B_MFB_2K].Threshold, 0, 0, &actualLength);
511
512		if (result != B_OK) {
513			TRACE_ALWAYS("Error of writing frame burst:%#010x\n", result);
514			return result;
515		}
516		rxcontrol = RXCTL_HDR_TYPE_1;
517	} else {
518		// TODO: FreeBSD documents this to speed up xfers, I don't
519		// have the hardware to test however.
520		// rxcontrol = RXCTL_USB_MFB_MAX;
521	}
522
523	rxcontrol |= RXCTL_START | RXCTL_BROADCAST;
524	result = WriteRXControlRegister(rxcontrol);
525	if (result != B_OK) {
526		TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
527			rxcontrol, result);
528	}
529
530	TRACE_RET(result);
531	return result;
532}
533
534
535status_t
536AX88772Device::OnNotify(uint32 actualLength)
537{
538	if (actualLength < sizeof(AX88772_Notify)) {
539		TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n",
540			actualLength, sizeof(AX88772_Notify));
541		return B_BAD_DATA;
542	}
543
544	AX88772_Notify *notification = (AX88772_Notify *)fNotifyBuffer;
545
546	if (notification->btA1 != 0xa1) {
547		TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
548			notification->btA1);
549	}
550
551	uint phyIndex = 0;
552	bool linkIsUp = fHasConnection;
553	switch(fMII.ActivePHY()) {
554		case PrimaryPHY:
555			phyIndex = 1;
556			linkIsUp = (notification->btBB & LINK_STATE_PPLS)
557				== LINK_STATE_PPLS;
558			break;
559		case SecondaryPHY:
560			phyIndex = 2;
561			linkIsUp = (notification->btBB & LINK_STATE_SPLS)
562				== LINK_STATE_SPLS;
563			break;
564		default:
565		case CurrentPHY:
566			TRACE_ALWAYS("Error: PHY is not initialized.\n");
567			return B_NO_INIT;
568	}
569
570	bool linkStateChange = linkIsUp != fHasConnection;
571	fHasConnection = linkIsUp;
572
573	if (linkStateChange) {
574		TRACE("Link state of PHY%d has been changed to '%s'\n",
575			phyIndex, fHasConnection ? "up" : "down");
576	}
577
578	if (linkStateChange && fLinkStateChangeSem >= B_OK)
579		release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
580
581	return B_OK;
582}
583
584
585status_t
586AX88772Device::GetLinkState(ether_link_state *linkState)
587{
588	size_t actualLength = 0;
589	uint16 mediumStatus = 0;
590	status_t result = gUSBModule->send_request(fDevice,
591		USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, READ_MEDIUM_STATUS,
592		0, 0, sizeof(mediumStatus), &mediumStatus, &actualLength);
593
594	if (result != B_OK) {
595		TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result);
596		return result;
597	}
598
599	if (actualLength != sizeof(mediumStatus)) {
600		TRACE_ALWAYS("Mismatch of reading medium status."
601			"Read %d bytes instead of %d\n", actualLength,
602			sizeof(mediumStatus));
603	}
604
605	TRACE_FLOW("Medium status is %#04x\n", mediumStatus);
606
607	linkState->quality = 1000;
608
609	linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0);
610	linkState->media |= (mediumStatus & MEDIUM_STATE_FD)
611		? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
612
613	linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100)
614		? 100000000 : 10000000;
615
616	TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
617		(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
618		linkState->speed / 1000000,
619		(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
620	return B_OK;
621}
622