blob: bdd16215dc12ef763fd16a319b0c5a03f070fdf1 [file] [log] [blame]
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001/*
2 * Agere Systems Inc.
3 * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
4 *
Alan Cox64f93032009-06-10 17:30:41 +01005 * Copyright * 2005 Agere Systems Inc.
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07006 * All rights reserved.
7 * http://www.agere.com
8 *
9 *------------------------------------------------------------------------------
10 *
11 * et1310_phy.c - Routines for configuring and accessing the PHY
12 *
13 *------------------------------------------------------------------------------
14 *
15 * SOFTWARE LICENSE
16 *
17 * This software is provided subject to the following terms and conditions,
18 * which you should read carefully before using the software. Using this
19 * software indicates your acceptance of these terms and conditions. If you do
20 * not agree with these terms and conditions, do not use the software.
21 *
Alan Cox64f93032009-06-10 17:30:41 +010022 * Copyright * 2005 Agere Systems Inc.
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070023 * All rights reserved.
24 *
25 * Redistribution and use in source or binary forms, with or without
26 * modifications, are permitted provided that the following conditions are met:
27 *
28 * . Redistributions of source code must retain the above copyright notice, this
29 * list of conditions and the following Disclaimer as comments in the code as
30 * well as in the documentation and/or other materials provided with the
31 * distribution.
32 *
33 * . Redistributions in binary form must reproduce the above copyright notice,
34 * this list of conditions and the following Disclaimer in the documentation
35 * and/or other materials provided with the distribution.
36 *
37 * . Neither the name of Agere Systems Inc. nor the names of the contributors
38 * may be used to endorse or promote products derived from this software
39 * without specific prior written permission.
40 *
41 * Disclaimer
42 *
Alan Cox64f93032009-06-10 17:30:41 +010043 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070044 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
45 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
46 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
47 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
49 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
50 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
51 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
53 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
54 * DAMAGE.
55 *
56 */
57
58#include "et131x_version.h"
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070059#include "et131x_defs.h"
60
61#include <linux/pci.h>
62#include <linux/init.h>
63#include <linux/module.h>
64#include <linux/types.h>
65#include <linux/kernel.h>
66
67#include <linux/sched.h>
68#include <linux/ptrace.h>
69#include <linux/slab.h>
70#include <linux/ctype.h>
71#include <linux/string.h>
72#include <linux/timer.h>
73#include <linux/interrupt.h>
74#include <linux/in.h>
75#include <linux/delay.h>
Alan Cox64f93032009-06-10 17:30:41 +010076#include <linux/io.h>
77#include <linux/bitops.h>
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070078#include <asm/system.h>
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070079
80#include <linux/netdevice.h>
81#include <linux/etherdevice.h>
82#include <linux/skbuff.h>
83#include <linux/if_arp.h>
84#include <linux/ioport.h>
85#include <linux/random.h>
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070086
87#include "et1310_phy.h"
88#include "et1310_pm.h"
89#include "et1310_jagcore.h"
90
91#include "et131x_adapter.h"
92#include "et131x_netdev.h"
93#include "et131x_initpci.h"
94
95#include "et1310_address_map.h"
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -070096#include "et1310_tx.h"
97#include "et1310_rx.h"
98#include "et1310_mac.h"
99
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700100/* Prototypes for functions with local scope */
101static int et131x_xcvr_init(struct et131x_adapter *adapter);
102
103/**
104 * PhyMiRead - Read from the PHY through the MII Interface on the MAC
105 * @adapter: pointer to our private adapter structure
106 * @xcvrAddr: the address of the transciever
107 * @xcvrReg: the register to read
108 * @value: pointer to a 16-bit value in which the value will be stored
109 *
110 * Returns 0 on success, errno on failure (as defined in errno.h)
111 */
112int PhyMiRead(struct et131x_adapter *adapter, uint8_t xcvrAddr,
113 uint8_t xcvrReg, uint16_t *value)
114{
Alan Coxf3f415a2009-08-27 10:59:30 +0100115 struct _MAC_t __iomem *mac = &adapter->regs->mac;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700116 int status = 0;
117 uint32_t delay;
118 MII_MGMT_ADDR_t miiAddr;
119 MII_MGMT_CMD_t miiCmd;
120 MII_MGMT_INDICATOR_t miiIndicator;
121
122 /* Save a local copy of the registers we are dealing with so we can
123 * set them back
124 */
125 miiAddr.value = readl(&mac->mii_mgmt_addr.value);
126 miiCmd.value = readl(&mac->mii_mgmt_cmd.value);
127
128 /* Stop the current operation */
129 writel(0, &mac->mii_mgmt_cmd.value);
130
131 /* Set up the register we need to read from on the correct PHY */
132 {
133 MII_MGMT_ADDR_t mii_mgmt_addr = { 0 };
134
135 mii_mgmt_addr.bits.phy_addr = xcvrAddr;
136 mii_mgmt_addr.bits.reg_addr = xcvrReg;
137 writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value);
138 }
139
140 /* Kick the read cycle off */
141 delay = 0;
142
143 writel(0x1, &mac->mii_mgmt_cmd.value);
144
145 do {
146 udelay(50);
147 delay++;
148 miiIndicator.value = readl(&mac->mii_mgmt_indicator.value);
149 } while ((miiIndicator.bits.not_valid || miiIndicator.bits.busy) &&
150 delay < 50);
151
152 /* If we hit the max delay, we could not read the register */
153 if (delay >= 50) {
Alan Cox15700032009-08-27 11:03:09 +0100154 dev_warn(&adapter->pdev->dev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700155 "xcvrReg 0x%08x could not be read\n", xcvrReg);
Alan Cox15700032009-08-27 11:03:09 +0100156 dev_warn(&adapter->pdev->dev, "status is 0x%08x\n",
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700157 miiIndicator.value);
158
159 status = -EIO;
160 }
161
162 /* If we hit here we were able to read the register and we need to
163 * return the value to the caller
164 */
165 /* TODO: make this stuff a simple readw()?! */
166 {
167 MII_MGMT_STAT_t mii_mgmt_stat;
168
169 mii_mgmt_stat.value = readl(&mac->mii_mgmt_stat.value);
170 *value = (uint16_t) mii_mgmt_stat.bits.phy_stat;
171 }
172
173 /* Stop the read operation */
174 writel(0, &mac->mii_mgmt_cmd.value);
175
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700176 /* set the registers we touched back to the state at which we entered
177 * this function
178 */
179 writel(miiAddr.value, &mac->mii_mgmt_addr.value);
180 writel(miiCmd.value, &mac->mii_mgmt_cmd.value);
181
182 return status;
183}
184
185/**
186 * MiWrite - Write to a PHY register through the MII interface of the MAC
187 * @adapter: pointer to our private adapter structure
188 * @xcvrReg: the register to read
189 * @value: 16-bit value to write
190 *
191 * Return 0 on success, errno on failure (as defined in errno.h)
192 */
193int MiWrite(struct et131x_adapter *adapter, uint8_t xcvrReg, uint16_t value)
194{
Alan Coxf3f415a2009-08-27 10:59:30 +0100195 struct _MAC_t __iomem *mac = &adapter->regs->mac;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700196 int status = 0;
197 uint8_t xcvrAddr = adapter->Stats.xcvr_addr;
198 uint32_t delay;
199 MII_MGMT_ADDR_t miiAddr;
200 MII_MGMT_CMD_t miiCmd;
201 MII_MGMT_INDICATOR_t miiIndicator;
202
203 /* Save a local copy of the registers we are dealing with so we can
204 * set them back
205 */
206 miiAddr.value = readl(&mac->mii_mgmt_addr.value);
207 miiCmd.value = readl(&mac->mii_mgmt_cmd.value);
208
209 /* Stop the current operation */
210 writel(0, &mac->mii_mgmt_cmd.value);
211
212 /* Set up the register we need to write to on the correct PHY */
213 {
214 MII_MGMT_ADDR_t mii_mgmt_addr;
215
216 mii_mgmt_addr.bits.phy_addr = xcvrAddr;
217 mii_mgmt_addr.bits.reg_addr = xcvrReg;
218 writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value);
219 }
220
221 /* Add the value to write to the registers to the mac */
222 writel(value, &mac->mii_mgmt_ctrl.value);
223 delay = 0;
224
225 do {
226 udelay(50);
227 delay++;
228 miiIndicator.value = readl(&mac->mii_mgmt_indicator.value);
229 } while (miiIndicator.bits.busy && delay < 100);
230
231 /* If we hit the max delay, we could not write the register */
232 if (delay == 100) {
233 uint16_t TempValue;
234
Alan Cox15700032009-08-27 11:03:09 +0100235 dev_warn(&adapter->pdev->dev,
236 "xcvrReg 0x%08x could not be written", xcvrReg);
237 dev_warn(&adapter->pdev->dev, "status is 0x%08x\n",
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700238 miiIndicator.value);
Alan Cox15700032009-08-27 11:03:09 +0100239 dev_warn(&adapter->pdev->dev, "command is 0x%08x\n",
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700240 readl(&mac->mii_mgmt_cmd.value));
241
242 MiRead(adapter, xcvrReg, &TempValue);
243
244 status = -EIO;
245 }
246
247 /* Stop the write operation */
248 writel(0, &mac->mii_mgmt_cmd.value);
249
250 /* set the registers we touched back to the state at which we entered
Alan Cox64f93032009-06-10 17:30:41 +0100251 * this function
252 */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700253 writel(miiAddr.value, &mac->mii_mgmt_addr.value);
254 writel(miiCmd.value, &mac->mii_mgmt_cmd.value);
255
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700256 return status;
257}
258
259/**
260 * et131x_xcvr_find - Find the PHY ID
261 * @adapter: pointer to our private adapter structure
262 *
263 * Returns 0 on success, errno on failure (as defined in errno.h)
264 */
265int et131x_xcvr_find(struct et131x_adapter *adapter)
266{
267 int status = -ENODEV;
268 uint8_t xcvr_addr;
269 MI_IDR1_t idr1;
270 MI_IDR2_t idr2;
271 uint32_t xcvr_id;
272
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700273 /* We need to get xcvr id and address we just get the first one */
274 for (xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++) {
275 /* Read the ID from the PHY */
276 PhyMiRead(adapter, xcvr_addr,
277 (uint8_t) offsetof(MI_REGS_t, idr1),
278 &idr1.value);
279 PhyMiRead(adapter, xcvr_addr,
280 (uint8_t) offsetof(MI_REGS_t, idr2),
281 &idr2.value);
282
283 xcvr_id = (uint32_t) ((idr1.value << 16) | idr2.value);
284
285 if ((idr1.value != 0) && (idr1.value != 0xffff)) {
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700286 adapter->Stats.xcvr_id = xcvr_id;
287 adapter->Stats.xcvr_addr = xcvr_addr;
288
289 status = 0;
290 break;
291 }
292 }
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700293 return status;
294}
295
296/**
297 * et131x_setphy_normal - Set PHY for normal operation.
298 * @adapter: pointer to our private adapter structure
299 *
300 * Used by Power Management to force the PHY into 10 Base T half-duplex mode,
301 * when going to D3 in WOL mode. Also used during initialization to set the
302 * PHY for normal operation.
303 */
304int et131x_setphy_normal(struct et131x_adapter *adapter)
305{
306 int status;
307
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700308 /* Make sure the PHY is powered up */
309 ET1310_PhyPowerDown(adapter, 0);
310 status = et131x_xcvr_init(adapter);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700311 return status;
312}
313
314/**
315 * et131x_xcvr_init - Init the phy if we are setting it into force mode
316 * @adapter: pointer to our private adapter structure
317 *
318 * Returns 0 on success, errno on failure (as defined in errno.h)
319 */
320static int et131x_xcvr_init(struct et131x_adapter *adapter)
321{
322 int status = 0;
323 MI_IMR_t imr;
324 MI_ISR_t isr;
325 MI_LCR2_t lcr2;
326
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700327 /* Zero out the adapter structure variable representing BMSR */
328 adapter->Bmsr.value = 0;
329
330 MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, isr), &isr.value);
331
332 MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, imr), &imr.value);
333
334 /* Set the link status interrupt only. Bad behavior when link status
335 * and auto neg are set, we run into a nested interrupt problem
336 */
337 imr.bits.int_en = 0x1;
338 imr.bits.link_status = 0x1;
339 imr.bits.autoneg_status = 0x1;
340
341 MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, imr), imr.value);
342
343 /* Set the LED behavior such that LED 1 indicates speed (off =
344 * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates
345 * link and activity (on for link, blink off for activity).
346 *
347 * NOTE: Some customizations have been added here for specific
348 * vendors; The LED behavior is now determined by vendor data in the
349 * EEPROM. However, the above description is the default.
350 */
351 if ((adapter->eepromData[1] & 0x4) == 0) {
352 MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2),
353 &lcr2.value);
354 if ((adapter->eepromData[1] & 0x8) == 0)
355 lcr2.bits.led_tx_rx = 0x3;
356 else
357 lcr2.bits.led_tx_rx = 0x4;
358 lcr2.bits.led_link = 0xa;
359 MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2),
360 lcr2.value);
361 }
362
363 /* Determine if we need to go into a force mode and set it */
364 if (adapter->AiForceSpeed == 0 && adapter->AiForceDpx == 0) {
365 if ((adapter->RegistryFlowControl == TxOnly) ||
366 (adapter->RegistryFlowControl == Both)) {
367 ET1310_PhyAccessMiBit(adapter,
368 TRUEPHY_BIT_SET, 4, 11, NULL);
369 } else {
370 ET1310_PhyAccessMiBit(adapter,
371 TRUEPHY_BIT_CLEAR, 4, 11, NULL);
372 }
373
374 if (adapter->RegistryFlowControl == Both) {
375 ET1310_PhyAccessMiBit(adapter,
376 TRUEPHY_BIT_SET, 4, 10, NULL);
377 } else {
378 ET1310_PhyAccessMiBit(adapter,
379 TRUEPHY_BIT_CLEAR, 4, 10, NULL);
380 }
381
382 /* Set the phy to autonegotiation */
383 ET1310_PhyAutoNeg(adapter, true);
384
385 /* NOTE - Do we need this? */
386 ET1310_PhyAccessMiBit(adapter, TRUEPHY_BIT_SET, 0, 9, NULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700387 return status;
388 } else {
389 ET1310_PhyAutoNeg(adapter, false);
390
391 /* Set to the correct force mode. */
392 if (adapter->AiForceDpx != 1) {
393 if ((adapter->RegistryFlowControl == TxOnly) ||
394 (adapter->RegistryFlowControl == Both)) {
395 ET1310_PhyAccessMiBit(adapter,
396 TRUEPHY_BIT_SET, 4, 11,
397 NULL);
398 } else {
399 ET1310_PhyAccessMiBit(adapter,
400 TRUEPHY_BIT_CLEAR, 4, 11,
401 NULL);
402 }
403
404 if (adapter->RegistryFlowControl == Both) {
405 ET1310_PhyAccessMiBit(adapter,
406 TRUEPHY_BIT_SET, 4, 10,
407 NULL);
408 } else {
409 ET1310_PhyAccessMiBit(adapter,
410 TRUEPHY_BIT_CLEAR, 4, 10,
411 NULL);
412 }
413 } else {
414 ET1310_PhyAccessMiBit(adapter,
415 TRUEPHY_BIT_CLEAR, 4, 10, NULL);
416 ET1310_PhyAccessMiBit(adapter,
417 TRUEPHY_BIT_CLEAR, 4, 11, NULL);
418 }
419
420 switch (adapter->AiForceSpeed) {
421 case 10:
Alan Cox64f93032009-06-10 17:30:41 +0100422 if (adapter->AiForceDpx == 1)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700423 TPAL_SetPhy10HalfDuplex(adapter);
Alan Cox64f93032009-06-10 17:30:41 +0100424 else if (adapter->AiForceDpx == 2)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700425 TPAL_SetPhy10FullDuplex(adapter);
Alan Cox64f93032009-06-10 17:30:41 +0100426 else
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700427 TPAL_SetPhy10Force(adapter);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700428 break;
429 case 100:
Alan Cox64f93032009-06-10 17:30:41 +0100430 if (adapter->AiForceDpx == 1)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700431 TPAL_SetPhy100HalfDuplex(adapter);
Alan Cox64f93032009-06-10 17:30:41 +0100432 else if (adapter->AiForceDpx == 2)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700433 TPAL_SetPhy100FullDuplex(adapter);
Alan Cox64f93032009-06-10 17:30:41 +0100434 else
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700435 TPAL_SetPhy100Force(adapter);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700436 break;
437 case 1000:
438 TPAL_SetPhy1000FullDuplex(adapter);
439 break;
440 }
441
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700442 return status;
443 }
444}
445
Alan Cox25ad00b2009-08-19 18:21:44 +0100446void et131x_Mii_check(struct et131x_adapter *etdev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700447 MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints)
448{
Alan Cox9fa81092009-08-27 11:00:36 +0100449 uint8_t link_status;
450 uint32_t autoneg_status;
451 uint32_t speed;
452 uint32_t duplex;
453 uint32_t mdi_mdix;
454 uint32_t masterslave;
455 uint32_t polarity;
Alan Cox37628602009-08-19 18:21:50 +0100456 unsigned long flags;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700457
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700458 if (bmsr_ints.bits.link_status) {
459 if (bmsr.bits.link_status) {
Alan Cox25ad00b2009-08-19 18:21:44 +0100460 etdev->PoMgmt.TransPhyComaModeOnBoot = 20;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700461
462 /* Update our state variables and indicate the
463 * connected state
464 */
Alan Cox37628602009-08-19 18:21:50 +0100465 spin_lock_irqsave(&etdev->Lock, flags);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700466
Alan Cox25ad00b2009-08-19 18:21:44 +0100467 etdev->MediaState = NETIF_STATUS_MEDIA_CONNECT;
Alan Coxf6b35d62009-08-27 11:02:05 +0100468 etdev->Flags &= ~fMP_ADAPTER_LINK_DETECTION;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700469
Alan Cox37628602009-08-19 18:21:50 +0100470 spin_unlock_irqrestore(&etdev->Lock, flags);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700471
Alan Cox5f1377d2009-10-06 15:47:55 +0100472 netif_carrier_on(etdev->netdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700473 } else {
Alan Cox15700032009-08-27 11:03:09 +0100474 dev_warn(&etdev->pdev->dev,
475 "Link down - cable problem ?\n");
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700476
Alan Cox9fa81092009-08-27 11:00:36 +0100477 if (etdev->linkspeed == TRUEPHY_SPEED_10MBPS) {
Alan Cox64f93032009-06-10 17:30:41 +0100478 /* NOTE - Is there a way to query this without
479 * TruePHY?
Alan Cox25ad00b2009-08-19 18:21:44 +0100480 * && TRU_QueryCoreType(etdev->hTruePhy, 0) == EMI_TRUEPHY_A13O) {
Alan Cox64f93032009-06-10 17:30:41 +0100481 */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700482 uint16_t Register18;
483
Alan Cox25ad00b2009-08-19 18:21:44 +0100484 MiRead(etdev, 0x12, &Register18);
485 MiWrite(etdev, 0x12, Register18 | 0x4);
486 MiWrite(etdev, 0x10, Register18 | 0x8402);
487 MiWrite(etdev, 0x11, Register18 | 511);
488 MiWrite(etdev, 0x12, Register18);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700489 }
490
491 /* For the first N seconds of life, we are in "link
492 * detection" When we are in this state, we should
493 * only report "connected". When the LinkDetection
494 * Timer expires, we can report disconnected (handled
495 * in the LinkDetectionDPC).
496 */
Alan Coxf6b35d62009-08-27 11:02:05 +0100497 if (!(etdev->Flags & fMP_ADAPTER_LINK_DETECTION) ||
498 (etdev->MediaState == NETIF_STATUS_MEDIA_DISCONNECT)) {
Alan Cox37628602009-08-19 18:21:50 +0100499 spin_lock_irqsave(&etdev->Lock, flags);
Alan Cox25ad00b2009-08-19 18:21:44 +0100500 etdev->MediaState =
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700501 NETIF_STATUS_MEDIA_DISCONNECT;
Alan Cox25ad00b2009-08-19 18:21:44 +0100502 spin_unlock_irqrestore(&etdev->Lock,
Alan Cox37628602009-08-19 18:21:50 +0100503 flags);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700504
Alan Cox5f1377d2009-10-06 15:47:55 +0100505 netif_carrier_off(etdev->netdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700506 }
507
Alan Cox9fa81092009-08-27 11:00:36 +0100508 etdev->linkspeed = 0;
Alan Cox576b38e2009-08-27 11:00:47 +0100509 etdev->duplex_mode = 0;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700510
511 /* Free the packets being actively sent & stopped */
Alan Cox25ad00b2009-08-19 18:21:44 +0100512 et131x_free_busy_send_packets(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700513
514 /* Re-initialize the send structures */
Alan Cox25ad00b2009-08-19 18:21:44 +0100515 et131x_init_send(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700516
517 /* Reset the RFD list and re-start RU */
Alan Cox25ad00b2009-08-19 18:21:44 +0100518 et131x_reset_recv(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700519
520 /*
521 * Bring the device back to the state it was during
522 * init prior to autonegotiation being complete. This
523 * way, when we get the auto-neg complete interrupt,
524 * we can complete init by calling ConfigMacREGS2.
525 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100526 et131x_soft_reset(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700527
528 /* Setup ET1310 as per the documentation */
Alan Cox25ad00b2009-08-19 18:21:44 +0100529 et131x_adapter_setup(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700530
531 /* Setup the PHY into coma mode until the cable is
532 * plugged back in
533 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100534 if (etdev->RegistryPhyComa == 1)
535 EnablePhyComa(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700536 }
537 }
538
539 if (bmsr_ints.bits.auto_neg_complete ||
Alan Cox25ad00b2009-08-19 18:21:44 +0100540 (etdev->AiForceDpx == 3 && bmsr_ints.bits.link_status)) {
541 if (bmsr.bits.auto_neg_complete || etdev->AiForceDpx == 3) {
542 ET1310_PhyLinkStatus(etdev,
Alan Cox9fa81092009-08-27 11:00:36 +0100543 &link_status, &autoneg_status,
544 &speed, &duplex, &mdi_mdix,
545 &masterslave, &polarity);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700546
Alan Cox9fa81092009-08-27 11:00:36 +0100547 etdev->linkspeed = speed;
548 etdev->duplex_mode = duplex;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700549
Alan Cox25ad00b2009-08-19 18:21:44 +0100550 etdev->PoMgmt.TransPhyComaModeOnBoot = 20;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700551
Alan Cox9fa81092009-08-27 11:00:36 +0100552 if (etdev->linkspeed == TRUEPHY_SPEED_10MBPS) {
Alan Cox64f93032009-06-10 17:30:41 +0100553 /*
554 * NOTE - Is there a way to query this without
555 * TruePHY?
Alan Cox25ad00b2009-08-19 18:21:44 +0100556 * && TRU_QueryCoreType(etdev->hTruePhy, 0)== EMI_TRUEPHY_A13O) {
Alan Cox64f93032009-06-10 17:30:41 +0100557 */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700558 uint16_t Register18;
559
Alan Cox25ad00b2009-08-19 18:21:44 +0100560 MiRead(etdev, 0x12, &Register18);
561 MiWrite(etdev, 0x12, Register18 | 0x4);
562 MiWrite(etdev, 0x10, Register18 | 0x8402);
563 MiWrite(etdev, 0x11, Register18 | 511);
564 MiWrite(etdev, 0x12, Register18);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700565 }
566
Alan Cox25ad00b2009-08-19 18:21:44 +0100567 ConfigFlowControl(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700568
Alan Cox9fa81092009-08-27 11:00:36 +0100569 if (etdev->linkspeed == TRUEPHY_SPEED_1000MBPS &&
Alan Cox25ad00b2009-08-19 18:21:44 +0100570 etdev->RegistryJumboPacket > 2048)
571 ET1310_PhyAndOrReg(etdev, 0x16, 0xcfff,
Alan Cox64f93032009-06-10 17:30:41 +0100572 0x2000);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700573
Alan Cox25ad00b2009-08-19 18:21:44 +0100574 SetRxDmaTimer(etdev);
575 ConfigMACRegs2(etdev);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700576 }
577 }
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700578}
579
580/**
581 * TPAL_SetPhy10HalfDuplex - Force the phy into 10 Base T Half Duplex mode.
Alan Cox25ad00b2009-08-19 18:21:44 +0100582 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700583 *
584 * Also sets the MAC so it is syncd up properly
585 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100586void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700587{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700588 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100589 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700590
591 /* First we need to turn off all other advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100592 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700593
Alan Cox25ad00b2009-08-19 18:21:44 +0100594 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700595
596 /* Set our advertise values accordingly */
Alan Cox25ad00b2009-08-19 18:21:44 +0100597 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_HALF);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700598
599 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100600 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700601}
602
603/**
604 * TPAL_SetPhy10FullDuplex - Force the phy into 10 Base T Full Duplex mode.
Alan Cox25ad00b2009-08-19 18:21:44 +0100605 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700606 *
607 * Also sets the MAC so it is syncd up properly
608 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100609void TPAL_SetPhy10FullDuplex(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700610{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700611 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100612 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700613
614 /* First we need to turn off all other advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100615 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700616
Alan Cox25ad00b2009-08-19 18:21:44 +0100617 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700618
619 /* Set our advertise values accordingly */
Alan Cox25ad00b2009-08-19 18:21:44 +0100620 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_FULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700621
622 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100623 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700624}
625
626/**
627 * TPAL_SetPhy10Force - Force Base-T FD mode WITHOUT using autonegotiation
Alan Cox25ad00b2009-08-19 18:21:44 +0100628 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700629 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100630void TPAL_SetPhy10Force(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700631{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700632 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100633 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700634
635 /* Disable autoneg */
Alan Cox25ad00b2009-08-19 18:21:44 +0100636 ET1310_PhyAutoNeg(etdev, false);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700637
638 /* Disable all advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100639 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
640 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
641 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700642
643 /* Force 10 Mbps */
Alan Cox25ad00b2009-08-19 18:21:44 +0100644 ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_10MBPS);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700645
646 /* Force Full duplex */
Alan Cox25ad00b2009-08-19 18:21:44 +0100647 ET1310_PhyDuplexMode(etdev, TRUEPHY_DUPLEX_FULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700648
649 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100650 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700651}
652
653/**
654 * TPAL_SetPhy100HalfDuplex - Force 100 Base T Half Duplex mode.
Alan Cox25ad00b2009-08-19 18:21:44 +0100655 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700656 *
657 * Also sets the MAC so it is syncd up properly.
658 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100659void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700660{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700661 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100662 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700663
664 /* first we need to turn off all other advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100665 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700666
Alan Cox25ad00b2009-08-19 18:21:44 +0100667 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700668
669 /* Set our advertise values accordingly */
Alan Cox25ad00b2009-08-19 18:21:44 +0100670 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_HALF);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700671
672 /* Set speed */
Alan Cox25ad00b2009-08-19 18:21:44 +0100673 ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_100MBPS);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700674
675 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100676 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700677}
678
679/**
680 * TPAL_SetPhy100FullDuplex - Force 100 Base T Full Duplex mode.
Alan Cox25ad00b2009-08-19 18:21:44 +0100681 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700682 *
683 * Also sets the MAC so it is syncd up properly
684 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100685void TPAL_SetPhy100FullDuplex(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700686{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700687 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100688 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700689
690 /* First we need to turn off all other advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100691 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700692
Alan Cox25ad00b2009-08-19 18:21:44 +0100693 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700694
695 /* Set our advertise values accordingly */
Alan Cox25ad00b2009-08-19 18:21:44 +0100696 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_FULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700697
698 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100699 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700700}
701
702/**
703 * TPAL_SetPhy100Force - Force 100 BaseT FD mode WITHOUT using autonegotiation
Alan Cox25ad00b2009-08-19 18:21:44 +0100704 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700705 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100706void TPAL_SetPhy100Force(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700707{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700708 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100709 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700710
711 /* Disable autoneg */
Alan Cox25ad00b2009-08-19 18:21:44 +0100712 ET1310_PhyAutoNeg(etdev, false);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700713
714 /* Disable all advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100715 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
716 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
717 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700718
719 /* Force 100 Mbps */
Alan Cox25ad00b2009-08-19 18:21:44 +0100720 ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_100MBPS);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700721
722 /* Force Full duplex */
Alan Cox25ad00b2009-08-19 18:21:44 +0100723 ET1310_PhyDuplexMode(etdev, TRUEPHY_DUPLEX_FULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700724
725 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100726 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700727}
728
729/**
730 * TPAL_SetPhy1000FullDuplex - Force 1000 Base T Full Duplex mode
Alan Cox25ad00b2009-08-19 18:21:44 +0100731 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700732 *
733 * Also sets the MAC so it is syncd up properly.
734 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100735void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700736{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700737 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100738 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700739
740 /* first we need to turn off all other advertisement */
Alan Cox25ad00b2009-08-19 18:21:44 +0100741 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700742
Alan Cox25ad00b2009-08-19 18:21:44 +0100743 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700744
745 /* set our advertise values accordingly */
Alan Cox25ad00b2009-08-19 18:21:44 +0100746 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_FULL);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700747
748 /* power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100749 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700750}
751
752/**
753 * TPAL_SetPhyAutoNeg - Set phy to autonegotiation mode.
Alan Cox25ad00b2009-08-19 18:21:44 +0100754 * @etdev: pointer to the adapter structure
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700755 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100756void TPAL_SetPhyAutoNeg(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700757{
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700758 /* Power down PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100759 ET1310_PhyPowerDown(etdev, 1);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700760
761 /* Turn on advertisement of all capabilities */
Alan Cox25ad00b2009-08-19 18:21:44 +0100762 ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_BOTH);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700763
Alan Cox25ad00b2009-08-19 18:21:44 +0100764 ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_BOTH);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700765
Alan Cox5ec34872009-08-27 10:59:13 +0100766 if (etdev->pdev->device != ET131X_PCI_DEVICE_ID_FAST)
Alan Cox25ad00b2009-08-19 18:21:44 +0100767 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_FULL);
Alan Cox64f93032009-06-10 17:30:41 +0100768 else
Alan Cox25ad00b2009-08-19 18:21:44 +0100769 ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700770
771 /* Make sure auto-neg is ON (it is disabled in FORCE modes) */
Alan Cox25ad00b2009-08-19 18:21:44 +0100772 ET1310_PhyAutoNeg(etdev, true);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700773
774 /* Power up PHY */
Alan Cox25ad00b2009-08-19 18:21:44 +0100775 ET1310_PhyPowerDown(etdev, 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700776}
777
778
779/*
780 * The routines which follow provide low-level access to the PHY, and are used
781 * primarily by the routines above (although there are a few places elsewhere
782 * in the driver where this level of access is required).
783 */
784
785static const uint16_t ConfigPhy[25][2] = {
786 /* Reg Value Register */
787 /* Addr */
788 {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */
789 {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */
790 {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */
791
792 {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */
793 {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */
794 {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */
795
796 {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */
797 {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */
798 {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */
799
800 {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */
801 {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */
802 {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */
803
804 {0x300D, 1}, /* DisableNorm */
805
806 {0x280C, 0x0180}, /* LinkHoldEnd */
807
808 {0x1C21, 0x0002}, /* AlphaM */
809
810 {0x3821, 6}, /* FfeLkgTx0 */
811 {0x381D, 1}, /* FfeLkg1g4 */
812 {0x381E, 1}, /* FfeLkg1g5 */
813 {0x381F, 1}, /* FfeLkg1g6 */
814 {0x3820, 1}, /* FfeLkg1g7 */
815
816 {0x8402, 0x01F0}, /* Btinact */
817 {0x800E, 20}, /* LftrainTime */
818 {0x800F, 24}, /* DvguardTime */
819 {0x8010, 46}, /* IdlguardTime */
820
821 {0, 0}
822
823};
824
825/* condensed version of the phy initialization routine */
Alan Cox25ad00b2009-08-19 18:21:44 +0100826void ET1310_PhyInit(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700827{
Alan Cox9fa81092009-08-27 11:00:36 +0100828 uint16_t data, index;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700829
Alan Cox25ad00b2009-08-19 18:21:44 +0100830 if (etdev == NULL)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700831 return;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700832
Alan Cox64f93032009-06-10 17:30:41 +0100833 /* get the identity (again ?) */
Alan Cox9fa81092009-08-27 11:00:36 +0100834 MiRead(etdev, PHY_ID_1, &data);
835 MiRead(etdev, PHY_ID_2, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700836
Alan Cox64f93032009-06-10 17:30:41 +0100837 /* what does this do/achieve ? */
Alan Cox9fa81092009-08-27 11:00:36 +0100838 MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100839 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0006);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700840
Alan Cox64f93032009-06-10 17:30:41 +0100841 /* read modem register 0402, should I do something with the return
842 data ? */
Alan Cox25ad00b2009-08-19 18:21:44 +0100843 MiWrite(etdev, PHY_INDEX_REG, 0x0402);
Alan Cox9fa81092009-08-27 11:00:36 +0100844 MiRead(etdev, PHY_DATA_REG, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700845
Alan Cox64f93032009-06-10 17:30:41 +0100846 /* what does this do/achieve ? */
Alan Cox25ad00b2009-08-19 18:21:44 +0100847 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700848
Alan Cox64f93032009-06-10 17:30:41 +0100849 /* get the identity (again ?) */
Alan Cox9fa81092009-08-27 11:00:36 +0100850 MiRead(etdev, PHY_ID_1, &data);
851 MiRead(etdev, PHY_ID_2, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700852
Alan Cox64f93032009-06-10 17:30:41 +0100853 /* what does this achieve ? */
Alan Cox9fa81092009-08-27 11:00:36 +0100854 MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100855 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0006);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700856
Alan Cox64f93032009-06-10 17:30:41 +0100857 /* read modem register 0402, should I do something with
858 the return data? */
Alan Cox25ad00b2009-08-19 18:21:44 +0100859 MiWrite(etdev, PHY_INDEX_REG, 0x0402);
Alan Cox9fa81092009-08-27 11:00:36 +0100860 MiRead(etdev, PHY_DATA_REG, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700861
Alan Cox25ad00b2009-08-19 18:21:44 +0100862 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700863
Alan Cox64f93032009-06-10 17:30:41 +0100864 /* what does this achieve (should return 0x1040) */
Alan Cox9fa81092009-08-27 11:00:36 +0100865 MiRead(etdev, PHY_CONTROL, &data);
866 MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100867 MiWrite(etdev, PHY_CONTROL, 0x1840);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700868
Alan Cox25ad00b2009-08-19 18:21:44 +0100869 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0007);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700870
Alan Cox64f93032009-06-10 17:30:41 +0100871 /* here the writing of the array starts.... */
Alan Cox9fa81092009-08-27 11:00:36 +0100872 index = 0;
873 while (ConfigPhy[index][0] != 0x0000) {
Alan Cox64f93032009-06-10 17:30:41 +0100874 /* write value */
Alan Cox9fa81092009-08-27 11:00:36 +0100875 MiWrite(etdev, PHY_INDEX_REG, ConfigPhy[index][0]);
876 MiWrite(etdev, PHY_DATA_REG, ConfigPhy[index][1]);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700877
Alan Cox64f93032009-06-10 17:30:41 +0100878 /* read it back */
Alan Cox9fa81092009-08-27 11:00:36 +0100879 MiWrite(etdev, PHY_INDEX_REG, ConfigPhy[index][0]);
880 MiRead(etdev, PHY_DATA_REG, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700881
Alan Cox64f93032009-06-10 17:30:41 +0100882 /* do a check on the value read back ? */
Alan Cox9fa81092009-08-27 11:00:36 +0100883 index++;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700884 }
Alan Cox64f93032009-06-10 17:30:41 +0100885 /* here the writing of the array ends... */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700886
Alan Cox9fa81092009-08-27 11:00:36 +0100887 MiRead(etdev, PHY_CONTROL, &data); /* 0x1840 */
888 MiRead(etdev, PHY_MPHY_CONTROL_REG, &data);/* should read 0007 */
Alan Cox25ad00b2009-08-19 18:21:44 +0100889 MiWrite(etdev, PHY_CONTROL, 0x1040);
890 MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700891}
892
Alan Cox25ad00b2009-08-19 18:21:44 +0100893void ET1310_PhyReset(struct et131x_adapter *etdev)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700894{
Alan Cox25ad00b2009-08-19 18:21:44 +0100895 MiWrite(etdev, PHY_CONTROL, 0x8000);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700896}
897
Alan Cox25ad00b2009-08-19 18:21:44 +0100898void ET1310_PhyPowerDown(struct et131x_adapter *etdev, bool down)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700899{
Alan Cox9fa81092009-08-27 11:00:36 +0100900 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700901
Alan Cox9fa81092009-08-27 11:00:36 +0100902 MiRead(etdev, PHY_CONTROL, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700903
904 if (down == false) {
Alan Cox64f93032009-06-10 17:30:41 +0100905 /* Power UP */
Alan Cox9fa81092009-08-27 11:00:36 +0100906 data &= ~0x0800;
907 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700908 } else {
Alan Cox64f93032009-06-10 17:30:41 +0100909 /* Power DOWN */
Alan Cox9fa81092009-08-27 11:00:36 +0100910 data |= 0x0800;
911 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700912 }
913}
914
Alan Cox25ad00b2009-08-19 18:21:44 +0100915void ET1310_PhyAutoNeg(struct et131x_adapter *etdev, bool enable)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700916{
Alan Cox9fa81092009-08-27 11:00:36 +0100917 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700918
Alan Cox9fa81092009-08-27 11:00:36 +0100919 MiRead(etdev, PHY_CONTROL, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700920
921 if (enable == true) {
Alan Cox64f93032009-06-10 17:30:41 +0100922 /* Autonegotiation ON */
Alan Cox9fa81092009-08-27 11:00:36 +0100923 data |= 0x1000;
924 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700925 } else {
Alan Cox64f93032009-06-10 17:30:41 +0100926 /* Autonegotiation OFF */
Alan Cox9fa81092009-08-27 11:00:36 +0100927 data &= ~0x1000;
928 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700929 }
930}
931
Alan Cox25ad00b2009-08-19 18:21:44 +0100932void ET1310_PhyDuplexMode(struct et131x_adapter *etdev, uint16_t duplex)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700933{
Alan Cox9fa81092009-08-27 11:00:36 +0100934 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700935
Alan Cox9fa81092009-08-27 11:00:36 +0100936 MiRead(etdev, PHY_CONTROL, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700937
938 if (duplex == TRUEPHY_DUPLEX_FULL) {
Alan Cox64f93032009-06-10 17:30:41 +0100939 /* Set Full Duplex */
Alan Cox9fa81092009-08-27 11:00:36 +0100940 data |= 0x100;
941 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700942 } else {
Alan Cox64f93032009-06-10 17:30:41 +0100943 /* Set Half Duplex */
Alan Cox9fa81092009-08-27 11:00:36 +0100944 data &= ~0x100;
945 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700946 }
947}
948
Alan Cox25ad00b2009-08-19 18:21:44 +0100949void ET1310_PhySpeedSelect(struct et131x_adapter *etdev, uint16_t speed)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700950{
Alan Cox9fa81092009-08-27 11:00:36 +0100951 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700952
Alan Cox64f93032009-06-10 17:30:41 +0100953 /* Read the PHY control register */
Alan Cox9fa81092009-08-27 11:00:36 +0100954 MiRead(etdev, PHY_CONTROL, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700955
Alan Cox64f93032009-06-10 17:30:41 +0100956 /* Clear all Speed settings (Bits 6, 13) */
Alan Cox9fa81092009-08-27 11:00:36 +0100957 data &= ~0x2040;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700958
Alan Cox64f93032009-06-10 17:30:41 +0100959 /* Reset the speed bits based on user selection */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700960 switch (speed) {
961 case TRUEPHY_SPEED_10MBPS:
Alan Cox64f93032009-06-10 17:30:41 +0100962 /* Bits already cleared above, do nothing */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700963 break;
964
965 case TRUEPHY_SPEED_100MBPS:
Alan Cox64f93032009-06-10 17:30:41 +0100966 /* 100M == Set bit 13 */
Alan Cox9fa81092009-08-27 11:00:36 +0100967 data |= 0x2000;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700968 break;
969
970 case TRUEPHY_SPEED_1000MBPS:
971 default:
Alan Cox9fa81092009-08-27 11:00:36 +0100972 data |= 0x0040;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700973 break;
974 }
975
Alan Cox64f93032009-06-10 17:30:41 +0100976 /* Write back the new speed */
Alan Cox9fa81092009-08-27 11:00:36 +0100977 MiWrite(etdev, PHY_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700978}
979
Alan Cox25ad00b2009-08-19 18:21:44 +0100980void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *etdev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700981 uint16_t duplex)
982{
Alan Cox9fa81092009-08-27 11:00:36 +0100983 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700984
Alan Cox64f93032009-06-10 17:30:41 +0100985 /* Read the PHY 1000 Base-T Control Register */
Alan Cox9fa81092009-08-27 11:00:36 +0100986 MiRead(etdev, PHY_1000_CONTROL, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700987
Alan Cox64f93032009-06-10 17:30:41 +0100988 /* Clear Bits 8,9 */
Alan Cox9fa81092009-08-27 11:00:36 +0100989 data &= ~0x0300;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700990
991 switch (duplex) {
992 case TRUEPHY_ADV_DUPLEX_NONE:
Alan Cox64f93032009-06-10 17:30:41 +0100993 /* Duplex already cleared, do nothing */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700994 break;
995
996 case TRUEPHY_ADV_DUPLEX_FULL:
Alan Cox64f93032009-06-10 17:30:41 +0100997 /* Set Bit 9 */
Alan Cox9fa81092009-08-27 11:00:36 +0100998 data |= 0x0200;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -0700999 break;
1000
1001 case TRUEPHY_ADV_DUPLEX_HALF:
Alan Cox64f93032009-06-10 17:30:41 +01001002 /* Set Bit 8 */
Alan Cox9fa81092009-08-27 11:00:36 +01001003 data |= 0x0100;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001004 break;
1005
1006 case TRUEPHY_ADV_DUPLEX_BOTH:
1007 default:
Alan Cox9fa81092009-08-27 11:00:36 +01001008 data |= 0x0300;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001009 break;
1010 }
1011
Alan Cox64f93032009-06-10 17:30:41 +01001012 /* Write back advertisement */
Alan Cox9fa81092009-08-27 11:00:36 +01001013 MiWrite(etdev, PHY_1000_CONTROL, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001014}
1015
Alan Cox25ad00b2009-08-19 18:21:44 +01001016void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *etdev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001017 uint16_t duplex)
1018{
Alan Cox9fa81092009-08-27 11:00:36 +01001019 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001020
Alan Cox64f93032009-06-10 17:30:41 +01001021 /* Read the Autonegotiation Register (10/100) */
Alan Cox9fa81092009-08-27 11:00:36 +01001022 MiRead(etdev, PHY_AUTO_ADVERTISEMENT, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001023
Alan Cox64f93032009-06-10 17:30:41 +01001024 /* Clear bits 7,8 */
Alan Cox9fa81092009-08-27 11:00:36 +01001025 data &= ~0x0180;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001026
1027 switch (duplex) {
1028 case TRUEPHY_ADV_DUPLEX_NONE:
Alan Cox64f93032009-06-10 17:30:41 +01001029 /* Duplex already cleared, do nothing */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001030 break;
1031
1032 case TRUEPHY_ADV_DUPLEX_FULL:
Alan Cox64f93032009-06-10 17:30:41 +01001033 /* Set Bit 8 */
Alan Cox9fa81092009-08-27 11:00:36 +01001034 data |= 0x0100;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001035 break;
1036
1037 case TRUEPHY_ADV_DUPLEX_HALF:
Alan Cox64f93032009-06-10 17:30:41 +01001038 /* Set Bit 7 */
Alan Cox9fa81092009-08-27 11:00:36 +01001039 data |= 0x0080;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001040 break;
1041
1042 case TRUEPHY_ADV_DUPLEX_BOTH:
1043 default:
Alan Cox64f93032009-06-10 17:30:41 +01001044 /* Set Bits 7,8 */
Alan Cox9fa81092009-08-27 11:00:36 +01001045 data |= 0x0180;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001046 break;
1047 }
1048
Alan Cox64f93032009-06-10 17:30:41 +01001049 /* Write back advertisement */
Alan Cox9fa81092009-08-27 11:00:36 +01001050 MiWrite(etdev, PHY_AUTO_ADVERTISEMENT, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001051}
1052
Alan Cox25ad00b2009-08-19 18:21:44 +01001053void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *etdev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001054 uint16_t duplex)
1055{
Alan Cox9fa81092009-08-27 11:00:36 +01001056 uint16_t data;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001057
Alan Cox64f93032009-06-10 17:30:41 +01001058 /* Read the Autonegotiation Register (10/100) */
Alan Cox9fa81092009-08-27 11:00:36 +01001059 MiRead(etdev, PHY_AUTO_ADVERTISEMENT, &data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001060
Alan Cox64f93032009-06-10 17:30:41 +01001061 /* Clear bits 5,6 */
Alan Cox9fa81092009-08-27 11:00:36 +01001062 data &= ~0x0060;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001063
1064 switch (duplex) {
1065 case TRUEPHY_ADV_DUPLEX_NONE:
Alan Cox64f93032009-06-10 17:30:41 +01001066 /* Duplex already cleared, do nothing */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001067 break;
1068
1069 case TRUEPHY_ADV_DUPLEX_FULL:
Alan Cox64f93032009-06-10 17:30:41 +01001070 /* Set Bit 6 */
Alan Cox9fa81092009-08-27 11:00:36 +01001071 data |= 0x0040;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001072 break;
1073
1074 case TRUEPHY_ADV_DUPLEX_HALF:
Alan Cox64f93032009-06-10 17:30:41 +01001075 /* Set Bit 5 */
Alan Cox9fa81092009-08-27 11:00:36 +01001076 data |= 0x0020;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001077 break;
1078
1079 case TRUEPHY_ADV_DUPLEX_BOTH:
1080 default:
Alan Cox64f93032009-06-10 17:30:41 +01001081 /* Set Bits 5,6 */
Alan Cox9fa81092009-08-27 11:00:36 +01001082 data |= 0x0060;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001083 break;
1084 }
1085
Alan Cox64f93032009-06-10 17:30:41 +01001086 /* Write back advertisement */
Alan Cox9fa81092009-08-27 11:00:36 +01001087 MiWrite(etdev, PHY_AUTO_ADVERTISEMENT, data);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001088}
1089
Alan Cox25ad00b2009-08-19 18:21:44 +01001090void ET1310_PhyLinkStatus(struct et131x_adapter *etdev,
Alan Cox9fa81092009-08-27 11:00:36 +01001091 uint8_t *link_status,
1092 uint32_t *autoneg,
1093 uint32_t *linkspeed,
1094 uint32_t *duplex_mode,
1095 uint32_t *mdi_mdix,
1096 uint32_t *masterslave, uint32_t *polarity)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001097{
Alan Cox9fa81092009-08-27 11:00:36 +01001098 uint16_t mistatus = 0;
1099 uint16_t is1000BaseT = 0;
1100 uint16_t vmi_phystatus = 0;
1101 uint16_t control = 0;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001102
Alan Cox9fa81092009-08-27 11:00:36 +01001103 MiRead(etdev, PHY_STATUS, &mistatus);
1104 MiRead(etdev, PHY_1000_STATUS, &is1000BaseT);
1105 MiRead(etdev, PHY_PHY_STATUS, &vmi_phystatus);
1106 MiRead(etdev, PHY_CONTROL, &control);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001107
Alan Cox9fa81092009-08-27 11:00:36 +01001108 if (link_status) {
1109 *link_status =
1110 (unsigned char)((vmi_phystatus & 0x0040) ? 1 : 0);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001111 }
1112
Alan Cox9fa81092009-08-27 11:00:36 +01001113 if (autoneg) {
1114 *autoneg =
1115 (control & 0x1000) ? ((vmi_phystatus & 0x0020) ?
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001116 TRUEPHY_ANEG_COMPLETE :
1117 TRUEPHY_ANEG_NOT_COMPLETE) :
1118 TRUEPHY_ANEG_DISABLED;
1119 }
1120
Alan Cox9fa81092009-08-27 11:00:36 +01001121 if (linkspeed)
1122 *linkspeed = (vmi_phystatus & 0x0300) >> 8;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001123
Alan Cox9fa81092009-08-27 11:00:36 +01001124 if (duplex_mode)
1125 *duplex_mode = (vmi_phystatus & 0x0080) >> 7;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001126
Alan Cox9fa81092009-08-27 11:00:36 +01001127 if (mdi_mdix)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001128 /* NOTE: Need to complete this */
Alan Cox9fa81092009-08-27 11:00:36 +01001129 *mdi_mdix = 0;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001130
Alan Cox9fa81092009-08-27 11:00:36 +01001131 if (masterslave) {
1132 *masterslave =
1133 (is1000BaseT & 0x4000) ? TRUEPHY_CFG_MASTER :
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001134 TRUEPHY_CFG_SLAVE;
1135 }
1136
Alan Cox9fa81092009-08-27 11:00:36 +01001137 if (polarity) {
1138 *polarity =
1139 (vmi_phystatus & 0x0400) ? TRUEPHY_POLARITY_INVERTED :
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001140 TRUEPHY_POLARITY_NORMAL;
1141 }
1142}
1143
Alan Cox25ad00b2009-08-19 18:21:44 +01001144void ET1310_PhyAndOrReg(struct et131x_adapter *etdev,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001145 uint16_t regnum, uint16_t andMask, uint16_t orMask)
1146{
1147 uint16_t reg;
1148
Alan Cox64f93032009-06-10 17:30:41 +01001149 /* Read the requested register */
Alan Cox25ad00b2009-08-19 18:21:44 +01001150 MiRead(etdev, regnum, &reg);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001151
Alan Cox64f93032009-06-10 17:30:41 +01001152 /* Apply the AND mask */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001153 reg &= andMask;
1154
Alan Cox64f93032009-06-10 17:30:41 +01001155 /* Apply the OR mask */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001156 reg |= orMask;
1157
Alan Cox64f93032009-06-10 17:30:41 +01001158 /* Write the value back to the register */
Alan Cox25ad00b2009-08-19 18:21:44 +01001159 MiWrite(etdev, regnum, reg);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001160}
1161
Alan Cox25ad00b2009-08-19 18:21:44 +01001162void ET1310_PhyAccessMiBit(struct et131x_adapter *etdev, uint16_t action,
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001163 uint16_t regnum, uint16_t bitnum, uint8_t *value)
1164{
1165 uint16_t reg;
1166 uint16_t mask = 0;
1167
Alan Cox64f93032009-06-10 17:30:41 +01001168 /* Create a mask to isolate the requested bit */
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001169 mask = 0x0001 << bitnum;
1170
Alan Cox64f93032009-06-10 17:30:41 +01001171 /* Read the requested register */
Alan Cox25ad00b2009-08-19 18:21:44 +01001172 MiRead(etdev, regnum, &reg);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001173
1174 switch (action) {
1175 case TRUEPHY_BIT_READ:
Alan Cox64f93032009-06-10 17:30:41 +01001176 if (value != NULL)
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001177 *value = (reg & mask) >> bitnum;
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001178 break;
1179
1180 case TRUEPHY_BIT_SET:
1181 reg |= mask;
Alan Cox25ad00b2009-08-19 18:21:44 +01001182 MiWrite(etdev, regnum, reg);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001183 break;
1184
1185 case TRUEPHY_BIT_CLEAR:
1186 reg &= ~mask;
Alan Cox25ad00b2009-08-19 18:21:44 +01001187 MiWrite(etdev, regnum, reg);
Greg Kroah-Hartmancfb739b2008-04-03 17:30:53 -07001188 break;
1189
1190 default:
1191 break;
1192 }
1193}