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
47 extern 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
55 static int
aue_csr_read_1(pegasus_dev * sc,int reg)56 aue_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
78 static int
aue_csr_read_2(pegasus_dev * sc,int reg)79 aue_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
102 static int
aue_csr_write_1(pegasus_dev * sc,int reg,int val)103 aue_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
125 static int
aue_csr_write_2(pegasus_dev * sc,int reg,int val)126 aue_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 */
151 static void
aue_eeprom_getword(pegasus_dev * sc,int addr,u_int16_t * dest)152 aue_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 */
182 static void
aue_read_eeprom(pegasus_dev * sc,caddr_t dest,int off,int cnt,int swap)183 aue_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
201 static int
aue_miibus_readreg(pegasus_dev * sc,int phy,int reg)202 aue_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
245 static int
aue_miibus_writereg(pegasus_dev * sc,int phy,int reg,int data)246 aue_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
271 static uint16
aue_miibus_read(pegasus_dev * dev,uint16 reg)272 aue_miibus_read(pegasus_dev *dev, uint16 reg)
273 {
274 return aue_miibus_readreg(dev, dev->phy, reg);
275 }
276
277
278 static void
aue_miibus_write(pegasus_dev * dev,uint16 reg,uint16 value)279 aue_miibus_write(pegasus_dev *dev, uint16 reg, uint16 value)
280 {
281 aue_miibus_writereg(dev, dev->phy, reg, value);
282 }
283
284
285 static uint16
aue_miibus_status_from_phy(pegasus_dev * dev,uint16 phy)286 aue_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
300 static uint16
aue_miibus_status(pegasus_dev * dev)301 aue_miibus_status(pegasus_dev *dev)
302 {
303 return aue_miibus_status_from_phy(dev, dev->phy);
304 }
305
306
307 static status_t
aue_init_phy(pegasus_dev * dev)308 aue_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
351 static void
aue_reset_pegasus_II(pegasus_dev * sc)352 aue_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
365 static void
aue_reset(pegasus_dev * sc)366 aue_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 */
413 void
aue_attach(pegasus_dev * sc)414 aue_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
435 done:
436 AUE_UNLOCK(sc);
437 }
438
439
440 void
aue_init(pegasus_dev * sc)441 aue_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
452 void
aue_uninit(pegasus_dev * sc)453 aue_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