1/*
2 * Pegasus BeOS Driver
3 *
4 * Copyright 2006, Haiku, Inc. All Rights Reserved.
5 * Distributed under the terms of the MIT License.
6 *
7 * Authors:
8 *		J��r��me Duval
9 */
10
11/*-
12 * Copyright (c) 1997, 1998, 1999, 2000
13 *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 *    must display the following acknowledgement:
25 *	This product includes software developed by Bill Paul.
26 * 4. Neither the name of the author nor the names of any co-contributors
27 *    may be used to endorse or promote products derived from this software
28 *    without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
40 * THE POSSIBILITY OF SUCH DAMAGE.
41 */
42
43#include <string.h>
44#include "driver.h"
45#include "usbdevs.h"
46
47extern usb_module_info *usb;
48
49#define AUE_SETBIT(sc, reg, x)				\
50	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x))
51
52#define AUE_CLRBIT(sc, reg, x)				\
53	aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x))
54
55static int
56aue_csr_read_1(pegasus_dev *sc, int reg)
57{
58	status_t		err;
59	uint8		val = 0;
60	size_t		length;
61
62	if (sc->aue_dying)
63		return (0);
64
65	AUE_LOCK(sc);
66
67	err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
68		AUE_UR_READREG, 0, reg, 1, &val, &length);
69	AUE_UNLOCK(sc);
70
71	if (err) {
72		return (0);
73	}
74
75	return (val);
76}
77
78static int
79aue_csr_read_2(pegasus_dev *sc, int reg)
80{
81	status_t		err;
82	uint16		val = 0;
83	size_t		length;
84
85	if (sc->aue_dying)
86		return (0);
87
88	AUE_LOCK(sc);
89
90	err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
91		AUE_UR_READREG, 0, reg, 2, &val, &length);
92
93	AUE_UNLOCK(sc);
94
95	if (err) {
96		return (0);
97	}
98
99	return (val);
100}
101
102static int
103aue_csr_write_1(pegasus_dev *sc, int reg, int val)
104{
105	status_t		err;
106	size_t		length = 1;
107
108	if (sc->aue_dying)
109		return (0);
110
111	AUE_LOCK(sc);
112
113	err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
114		AUE_UR_WRITEREG, val, reg, 1, &val, &length);
115
116	AUE_UNLOCK(sc);
117
118	if (err) {
119		return (-1);
120	}
121
122	return (0);
123}
124
125static int
126aue_csr_write_2(pegasus_dev *sc, int reg, int val)
127{
128	status_t		err;
129	size_t			length = 2;
130
131	if (sc->aue_dying)
132		return (0);
133
134	AUE_LOCK(sc);
135
136	err = usb->send_request(sc->dev, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
137		AUE_UR_WRITEREG, val, reg, 2, &val, &length);
138
139	AUE_UNLOCK(sc);
140
141	if (err) {
142		return (-1);
143	}
144
145	return (0);
146}
147
148/*
149 * Read a word of data stored in the EEPROM at address 'addr.'
150 */
151static void
152aue_eeprom_getword(pegasus_dev *sc, int addr, u_int16_t *dest)
153{
154	int		i;
155	u_int16_t	word = 0;
156
157	aue_csr_write_1(sc, AUE_EE_REG, addr);
158	aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ);
159
160	for (i = 0; i < AUE_TIMEOUT; i++) {
161		if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE)
162			break;
163	}
164
165	if (i == AUE_TIMEOUT) {
166		dprintf("aue%d: EEPROM read timed out\n",
167		    sc->aue_unit);
168	}
169
170	word = aue_csr_read_2(sc, AUE_EE_DATA);
171	*dest = word;
172
173	return;
174}
175
176
177
178
179/*
180 * Read a sequence of words from the EEPROM.
181 */
182static void
183aue_read_eeprom(pegasus_dev *sc, caddr_t dest, int off, int cnt, int swap)
184{
185	int			i;
186	u_int16_t		word = 0, *ptr;
187
188	for (i = 0; i < cnt; i++) {
189		aue_eeprom_getword(sc, off + i, &word);
190		ptr = (u_int16_t *)(dest + (i * 2));
191		if (swap)
192			*ptr = B_BENDIAN_TO_HOST_INT16(word);
193		else
194			*ptr = word;
195	}
196
197	return;
198}
199
200
201static int
202aue_miibus_readreg(pegasus_dev *sc, int phy, int reg)
203{
204	int			i;
205	u_int16_t		val = 0;
206
207	/*
208	 * The Am79C901 HomePNA PHY actually contains
209	 * two transceivers: a 1Mbps HomePNA PHY and a
210	 * 10Mbps full/half duplex ethernet PHY with
211	 * NWAY autoneg. However in the ADMtek adapter,
212	 * only the 1Mbps PHY is actually connected to
213	 * anything, so we ignore the 10Mbps one. It
214	 * happens to be configured for MII address 3,
215	 * so we filter that out.
216	 */
217	if (sc->aue_vendor == USB_VENDOR_ADMTEK &&
218	    sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) {
219		if (phy == 3)
220			return (0);
221#ifdef notdef
222		if (phy != 1)
223			return (0);
224#endif
225	}
226
227	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
228	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ);
229
230	for (i = 0; i < AUE_TIMEOUT; i++) {
231		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
232			break;
233	}
234
235	if (i == AUE_TIMEOUT) {
236		dprintf("aue%d: MII read timed out\n", sc->aue_unit);
237	}
238
239	val = aue_csr_read_2(sc, AUE_PHY_DATA);
240
241	return (val);
242}
243
244
245static int
246aue_miibus_writereg(pegasus_dev *sc, int phy, int reg, int data)
247{
248	int			i;
249
250	if (phy == 3)
251		return (0);
252
253	aue_csr_write_2(sc, AUE_PHY_DATA, data);
254	aue_csr_write_1(sc, AUE_PHY_ADDR, phy);
255	aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE);
256
257	for (i = 0; i < AUE_TIMEOUT; i++) {
258		if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE)
259			break;
260	}
261
262	if (i == AUE_TIMEOUT) {
263		dprintf("aue%d: MII read timed out\n",
264		    sc->aue_unit);
265	}
266
267	return (0);
268}
269
270
271static uint16
272aue_miibus_read(pegasus_dev *dev, uint16 reg)
273{
274	return aue_miibus_readreg(dev, dev->phy, reg);
275}
276
277
278static void
279aue_miibus_write(pegasus_dev *dev, uint16 reg, uint16 value)
280{
281	aue_miibus_writereg(dev, dev->phy, reg, value);
282}
283
284
285static uint16
286aue_miibus_status_from_phy(pegasus_dev *dev, uint16 phy)
287{
288	uint16 status;
289	int i = 0;
290
291	// the status must be retrieved two times, because the first
292	// one may not work on some PHYs (notably ICS 1893)
293	while (i++ < 2)
294		status = aue_miibus_readreg(dev, phy, MII_STATUS);
295
296	return status;
297}
298
299
300static uint16
301aue_miibus_status(pegasus_dev *dev)
302{
303	return aue_miibus_status_from_phy(dev, dev->phy);
304}
305
306
307static status_t
308aue_init_phy(pegasus_dev *dev)
309{
310	uint16 phy, status;
311	int i;
312
313	dev->phy = 255;
314
315	// search for total of 32 possible MII PHY addresses
316	for (phy = 0; phy < 32; phy++) {
317		uint16 status;
318
319		status = aue_miibus_status_from_phy(dev, phy);
320		if (status == 0xffff || status == 0x0000)
321			// this MII is not accessable
322			continue;
323
324		dev->phy = phy;
325	}
326
327	if (dev->phy == 255) {
328		DPRINTF_ERR("No MII PHY transceiver found!\n");
329		return B_ENTRY_NOT_FOUND;
330	}
331	DPRINTF_INFO("aue_init_phy MII PHY found at %d\n", dev->phy);
332
333	status = aue_miibus_read(dev, MII_CONTROL);
334	status &= ~MII_CONTROL_ISOLATE;
335
336	aue_miibus_write(dev, MII_CONTROL, status);
337
338	aue_miibus_write(dev, MII_CONTROL, MII_CONTROL_RESET);
339	for (i = 0; i < 100; i++) {
340		if ((aue_miibus_read(dev, MII_STATUS) & MII_CONTROL_RESET) == 0)
341			break;
342		DELAY(1000);
343	}
344
345	dev->link = aue_miibus_status(dev) & MII_STATUS_LINK;
346
347	return B_OK;
348}
349
350
351static void
352aue_reset_pegasus_II(pegasus_dev *sc)
353{
354	/* Magic constants taken from Linux driver. */
355	aue_csr_write_1(sc, AUE_REG_1D, 0);
356	aue_csr_write_1(sc, AUE_REG_7B, 2);
357#if 0
358	if ((sc->aue_flags & HAS_HOME_PNA) && mii_mode)
359		aue_csr_write_1(sc, AUE_REG_81, 6);
360	else
361#endif
362		aue_csr_write_1(sc, AUE_REG_81, 2);
363}
364
365static void
366aue_reset(pegasus_dev *sc)
367{
368	int		i;
369
370	AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC);
371
372	for (i = 0; i < AUE_TIMEOUT; i++) {
373		if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC))
374			break;
375	}
376
377	if (i == AUE_TIMEOUT)
378		dprintf("aue%d: reset failed\n", sc->aue_unit);
379
380	/*
381	 * The PHY(s) attached to the Pegasus chip may be held
382	 * in reset until we flip on the GPIO outputs. Make sure
383	 * to set the GPIO pins high so that the PHY(s) will
384	 * be enabled.
385	 *
386	 * Note: We force all of the GPIO pins low first, *then*
387	 * enable the ones we want.
388	 */
389	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0);
390	aue_csr_write_1(sc, AUE_GPIO0, AUE_GPIO_OUT0|AUE_GPIO_SEL0|AUE_GPIO_SEL1);
391
392	if (sc->aue_flags & LSYS) {
393		/* Grrr. LinkSys has to be different from everyone else. */
394		aue_csr_write_1(sc, AUE_GPIO0,
395			AUE_GPIO_SEL0 | AUE_GPIO_SEL1);
396		aue_csr_write_1(sc, AUE_GPIO0,
397			AUE_GPIO_SEL0 | AUE_GPIO_SEL1 | AUE_GPIO_OUT0);
398	}
399
400	if (sc->aue_flags & PII)
401		aue_reset_pegasus_II(sc);
402
403	/* Wait a little while for the chip to get its brains in order. */
404	DELAY(10000);
405
406	return;
407}
408
409
410/*
411 * Attach
412 */
413void
414aue_attach(pegasus_dev *sc)
415{
416	u_char		eaddr[ETHER_ADDRESS_LENGTH];
417
418	AUE_LOCK(sc);
419
420	/* Reset the adapter. */
421	aue_reset(sc);
422
423	/*
424	 * Get station address from the EEPROM.
425	 */
426	aue_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 0);
427
428	memcpy(sc->macaddr, eaddr, ETHER_ADDRESS_LENGTH);
429
430	if (aue_init_phy(sc) != B_OK)
431		goto done;
432
433	sc->aue_dying = 0;
434
435done:
436	AUE_UNLOCK(sc);
437}
438
439
440void
441aue_init(pegasus_dev *sc)
442{
443
444	/* Enable RX and TX */
445	aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB);
446	AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB);
447	AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR);
448
449}
450
451
452void
453aue_uninit(pegasus_dev *sc)
454{
455	aue_csr_write_1(sc, AUE_CTL0, 0);
456	aue_csr_write_1(sc, AUE_CTL1, 0);
457	aue_reset(sc);
458}
459