]>
Commit | Line | Data |
---|---|---|
cfb739b4 GKH |
1 | /* |
2 | * Agere Systems Inc. | |
3 | * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs | |
4 | * | |
64f93036 | 5 | * Copyright * 2005 Agere Systems Inc. |
cfb739b4 GKH |
6 | * 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 | * | |
64f93036 | 22 | * Copyright * 2005 Agere Systems Inc. |
cfb739b4 GKH |
23 | * 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 | * | |
64f93036 | 43 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
cfb739b4 GKH |
44 | * 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" | |
cfb739b4 GKH |
59 | #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> | |
cfb739b4 GKH |
69 | #include <linux/ctype.h> |
70 | #include <linux/string.h> | |
71 | #include <linux/timer.h> | |
72 | #include <linux/interrupt.h> | |
73 | #include <linux/in.h> | |
74 | #include <linux/delay.h> | |
64f93036 AC |
75 | #include <linux/io.h> |
76 | #include <linux/bitops.h> | |
cfb739b4 | 77 | #include <asm/system.h> |
cfb739b4 GKH |
78 | |
79 | #include <linux/netdevice.h> | |
80 | #include <linux/etherdevice.h> | |
81 | #include <linux/skbuff.h> | |
82 | #include <linux/if_arp.h> | |
83 | #include <linux/ioport.h> | |
84 | #include <linux/random.h> | |
cfb739b4 GKH |
85 | |
86 | #include "et1310_phy.h" | |
cfb739b4 GKH |
87 | |
88 | #include "et131x_adapter.h" | |
cfb739b4 GKH |
89 | |
90 | #include "et1310_address_map.h" | |
cfb739b4 GKH |
91 | #include "et1310_tx.h" |
92 | #include "et1310_rx.h" | |
69ea5fcb AC |
93 | |
94 | #include "et131x.h" | |
cfb739b4 | 95 | |
cfb739b4 | 96 | /* Prototypes for functions with local scope */ |
e1bc5845 | 97 | static void et131x_xcvr_init(struct et131x_adapter *etdev); |
cfb739b4 GKH |
98 | |
99 | /** | |
100 | * PhyMiRead - Read from the PHY through the MII Interface on the MAC | |
e1bc5845 | 101 | * @etdev: pointer to our private adapter structure |
cfb739b4 GKH |
102 | * @xcvrAddr: the address of the transciever |
103 | * @xcvrReg: the register to read | |
104 | * @value: pointer to a 16-bit value in which the value will be stored | |
105 | * | |
106 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
107 | */ | |
e1bc5845 | 108 | int PhyMiRead(struct et131x_adapter *etdev, u8 xcvrAddr, |
1210db95 | 109 | u8 xcvrReg, u16 *value) |
cfb739b4 | 110 | { |
e1bc5845 | 111 | struct _MAC_t __iomem *mac = &etdev->regs->mac; |
cfb739b4 | 112 | int status = 0; |
1210db95 | 113 | u32 delay; |
57aed3b4 AC |
114 | u32 miiAddr; |
115 | u32 miiCmd; | |
116 | u32 miiIndicator; | |
cfb739b4 GKH |
117 | |
118 | /* Save a local copy of the registers we are dealing with so we can | |
119 | * set them back | |
120 | */ | |
57aed3b4 AC |
121 | miiAddr = readl(&mac->mii_mgmt_addr); |
122 | miiCmd = readl(&mac->mii_mgmt_cmd); | |
cfb739b4 GKH |
123 | |
124 | /* Stop the current operation */ | |
57aed3b4 | 125 | writel(0, &mac->mii_mgmt_cmd); |
cfb739b4 GKH |
126 | |
127 | /* Set up the register we need to read from on the correct PHY */ | |
57aed3b4 | 128 | writel(MII_ADDR(xcvrAddr, xcvrReg), &mac->mii_mgmt_addr); |
cfb739b4 GKH |
129 | |
130 | /* Kick the read cycle off */ | |
131 | delay = 0; | |
132 | ||
57aed3b4 | 133 | writel(0x1, &mac->mii_mgmt_cmd); |
cfb739b4 GKH |
134 | |
135 | do { | |
136 | udelay(50); | |
137 | delay++; | |
57aed3b4 AC |
138 | miiIndicator = readl(&mac->mii_mgmt_indicator); |
139 | } while ((miiIndicator & MGMT_WAIT) && delay < 50); | |
cfb739b4 GKH |
140 | |
141 | /* If we hit the max delay, we could not read the register */ | |
57aed3b4 | 142 | if (delay == 50) { |
e1bc5845 | 143 | dev_warn(&etdev->pdev->dev, |
cfb739b4 | 144 | "xcvrReg 0x%08x could not be read\n", xcvrReg); |
e1bc5845 | 145 | dev_warn(&etdev->pdev->dev, "status is 0x%08x\n", |
57aed3b4 | 146 | miiIndicator); |
cfb739b4 GKH |
147 | |
148 | status = -EIO; | |
149 | } | |
150 | ||
151 | /* If we hit here we were able to read the register and we need to | |
57aed3b4 AC |
152 | * return the value to the caller */ |
153 | *value = readl(&mac->mii_mgmt_stat) & 0xFFFF; | |
cfb739b4 GKH |
154 | |
155 | /* Stop the read operation */ | |
57aed3b4 | 156 | writel(0, &mac->mii_mgmt_cmd); |
cfb739b4 | 157 | |
cfb739b4 GKH |
158 | /* set the registers we touched back to the state at which we entered |
159 | * this function | |
160 | */ | |
57aed3b4 AC |
161 | writel(miiAddr, &mac->mii_mgmt_addr); |
162 | writel(miiCmd, &mac->mii_mgmt_cmd); | |
cfb739b4 GKH |
163 | |
164 | return status; | |
165 | } | |
166 | ||
167 | /** | |
168 | * MiWrite - Write to a PHY register through the MII interface of the MAC | |
e1bc5845 | 169 | * @etdev: pointer to our private adapter structure |
cfb739b4 GKH |
170 | * @xcvrReg: the register to read |
171 | * @value: 16-bit value to write | |
172 | * | |
1210db95 AC |
173 | * FIXME: one caller in netdev still |
174 | * | |
cfb739b4 GKH |
175 | * Return 0 on success, errno on failure (as defined in errno.h) |
176 | */ | |
e1bc5845 | 177 | int MiWrite(struct et131x_adapter *etdev, u8 xcvrReg, u16 value) |
cfb739b4 | 178 | { |
e1bc5845 | 179 | struct _MAC_t __iomem *mac = &etdev->regs->mac; |
cfb739b4 | 180 | int status = 0; |
e1bc5845 | 181 | u8 xcvrAddr = etdev->Stats.xcvr_addr; |
1210db95 | 182 | u32 delay; |
57aed3b4 AC |
183 | u32 miiAddr; |
184 | u32 miiCmd; | |
185 | u32 miiIndicator; | |
cfb739b4 GKH |
186 | |
187 | /* Save a local copy of the registers we are dealing with so we can | |
188 | * set them back | |
189 | */ | |
57aed3b4 AC |
190 | miiAddr = readl(&mac->mii_mgmt_addr); |
191 | miiCmd = readl(&mac->mii_mgmt_cmd); | |
cfb739b4 GKH |
192 | |
193 | /* Stop the current operation */ | |
57aed3b4 | 194 | writel(0, &mac->mii_mgmt_cmd); |
cfb739b4 GKH |
195 | |
196 | /* Set up the register we need to write to on the correct PHY */ | |
57aed3b4 | 197 | writel(MII_ADDR(xcvrAddr, xcvrReg), &mac->mii_mgmt_addr); |
cfb739b4 GKH |
198 | |
199 | /* Add the value to write to the registers to the mac */ | |
57aed3b4 | 200 | writel(value, &mac->mii_mgmt_ctrl); |
cfb739b4 GKH |
201 | delay = 0; |
202 | ||
203 | do { | |
204 | udelay(50); | |
205 | delay++; | |
57aed3b4 AC |
206 | miiIndicator = readl(&mac->mii_mgmt_indicator); |
207 | } while ((miiIndicator & MGMT_BUSY) && delay < 100); | |
cfb739b4 GKH |
208 | |
209 | /* If we hit the max delay, we could not write the register */ | |
210 | if (delay == 100) { | |
1210db95 | 211 | u16 TempValue; |
cfb739b4 | 212 | |
e1bc5845 | 213 | dev_warn(&etdev->pdev->dev, |
15700039 | 214 | "xcvrReg 0x%08x could not be written", xcvrReg); |
e1bc5845 | 215 | dev_warn(&etdev->pdev->dev, "status is 0x%08x\n", |
57aed3b4 | 216 | miiIndicator); |
e1bc5845 | 217 | dev_warn(&etdev->pdev->dev, "command is 0x%08x\n", |
57aed3b4 | 218 | readl(&mac->mii_mgmt_cmd)); |
cfb739b4 | 219 | |
e1bc5845 | 220 | MiRead(etdev, xcvrReg, &TempValue); |
cfb739b4 GKH |
221 | |
222 | status = -EIO; | |
223 | } | |
cfb739b4 | 224 | /* Stop the write operation */ |
57aed3b4 | 225 | writel(0, &mac->mii_mgmt_cmd); |
cfb739b4 GKH |
226 | |
227 | /* set the registers we touched back to the state at which we entered | |
64f93036 AC |
228 | * this function |
229 | */ | |
57aed3b4 AC |
230 | writel(miiAddr, &mac->mii_mgmt_addr); |
231 | writel(miiCmd, &mac->mii_mgmt_cmd); | |
cfb739b4 | 232 | |
cfb739b4 GKH |
233 | return status; |
234 | } | |
235 | ||
236 | /** | |
237 | * et131x_xcvr_find - Find the PHY ID | |
e1bc5845 | 238 | * @etdev: pointer to our private adapter structure |
cfb739b4 GKH |
239 | * |
240 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
241 | */ | |
e1bc5845 | 242 | int et131x_xcvr_find(struct et131x_adapter *etdev) |
cfb739b4 | 243 | { |
1210db95 | 244 | u8 xcvr_addr; |
cfb739b4 GKH |
245 | MI_IDR1_t idr1; |
246 | MI_IDR2_t idr2; | |
1210db95 | 247 | u32 xcvr_id; |
cfb739b4 | 248 | |
cfb739b4 GKH |
249 | /* We need to get xcvr id and address we just get the first one */ |
250 | for (xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++) { | |
251 | /* Read the ID from the PHY */ | |
e1bc5845 | 252 | PhyMiRead(etdev, xcvr_addr, |
1210db95 | 253 | (u8) offsetof(MI_REGS_t, idr1), |
cfb739b4 | 254 | &idr1.value); |
e1bc5845 | 255 | PhyMiRead(etdev, xcvr_addr, |
1210db95 | 256 | (u8) offsetof(MI_REGS_t, idr2), |
cfb739b4 GKH |
257 | &idr2.value); |
258 | ||
1210db95 | 259 | xcvr_id = (u32) ((idr1.value << 16) | idr2.value); |
cfb739b4 | 260 | |
e1bc5845 AC |
261 | if (idr1.value != 0 && idr1.value != 0xffff) { |
262 | etdev->Stats.xcvr_id = xcvr_id; | |
263 | etdev->Stats.xcvr_addr = xcvr_addr; | |
264 | return 0; | |
cfb739b4 GKH |
265 | } |
266 | } | |
e1bc5845 | 267 | return -ENODEV; |
cfb739b4 GKH |
268 | } |
269 | ||
1210db95 | 270 | void ET1310_PhyReset(struct et131x_adapter *etdev) |
cfb739b4 | 271 | { |
1210db95 AC |
272 | MiWrite(etdev, PHY_CONTROL, 0x8000); |
273 | } | |
cfb739b4 | 274 | |
e1bc5845 AC |
275 | /** |
276 | * ET1310_PhyPowerDown - PHY power control | |
277 | * @etdev: device to control | |
278 | * @down: true for off/false for back on | |
279 | * | |
280 | * one hundred, ten, one thousand megs | |
281 | * How would you like to have your LAN accessed | |
282 | * Can't you see that this code processed | |
283 | * Phy power, phy power.. | |
284 | */ | |
285 | ||
1210db95 AC |
286 | void ET1310_PhyPowerDown(struct et131x_adapter *etdev, bool down) |
287 | { | |
288 | u16 data; | |
cfb739b4 | 289 | |
1210db95 | 290 | MiRead(etdev, PHY_CONTROL, &data); |
e1bc5845 AC |
291 | data &= ~0x0800; /* Power UP */ |
292 | if (down) /* Power DOWN */ | |
1210db95 | 293 | data |= 0x0800; |
e1bc5845 | 294 | MiWrite(etdev, PHY_CONTROL, data); |
1210db95 | 295 | } |
cfb739b4 | 296 | |
e1bc5845 AC |
297 | /** |
298 | * ET130_PhyAutoNEg - autonegotiate control | |
299 | * @etdev: device to control | |
300 | * @enabe: autoneg on/off | |
301 | * | |
302 | * Set up the autonegotiation state according to whether we will be | |
303 | * negotiating the state or forcing a speed. | |
304 | */ | |
305 | ||
1210db95 AC |
306 | static void ET1310_PhyAutoNeg(struct et131x_adapter *etdev, bool enable) |
307 | { | |
308 | u16 data; | |
cfb739b4 | 309 | |
1210db95 | 310 | MiRead(etdev, PHY_CONTROL, &data); |
e1bc5845 AC |
311 | data &= ~0x1000; /* Autonegotiation OFF */ |
312 | if (enable) | |
313 | data |= 0x1000; /* Autonegotiation ON */ | |
314 | MiWrite(etdev, PHY_CONTROL, data); | |
1210db95 | 315 | } |
cfb739b4 | 316 | |
e1bc5845 AC |
317 | /** |
318 | * ET130_PhyDuplexMode - duplex control | |
319 | * @etdev: device to control | |
320 | * @duplex: duplex on/off | |
321 | * | |
322 | * Set up the duplex state on the PHY | |
323 | */ | |
324 | ||
1210db95 AC |
325 | static void ET1310_PhyDuplexMode(struct et131x_adapter *etdev, u16 duplex) |
326 | { | |
327 | u16 data; | |
cfb739b4 | 328 | |
1210db95 | 329 | MiRead(etdev, PHY_CONTROL, &data); |
e1bc5845 AC |
330 | data &= ~0x100; /* Set Half Duplex */ |
331 | if (duplex == TRUEPHY_DUPLEX_FULL) | |
332 | data |= 0x100; /* Set Full Duplex */ | |
333 | MiWrite(etdev, PHY_CONTROL, data); | |
1210db95 | 334 | } |
cfb739b4 | 335 | |
e1bc5845 AC |
336 | /** |
337 | * ET130_PhySpeedSelect - speed control | |
338 | * @etdev: device to control | |
339 | * @duplex: duplex on/off | |
340 | * | |
341 | * Set the speed of our PHY. | |
342 | */ | |
343 | ||
1210db95 AC |
344 | static void ET1310_PhySpeedSelect(struct et131x_adapter *etdev, u16 speed) |
345 | { | |
346 | u16 data; | |
e1bc5845 | 347 | static const u16 bits[3]={0x0000, 0x2000, 0x0040}; |
cfb739b4 | 348 | |
1210db95 AC |
349 | /* Read the PHY control register */ |
350 | MiRead(etdev, PHY_CONTROL, &data); | |
1210db95 AC |
351 | /* Clear all Speed settings (Bits 6, 13) */ |
352 | data &= ~0x2040; | |
1210db95 | 353 | /* Write back the new speed */ |
e1bc5845 | 354 | MiWrite(etdev, PHY_CONTROL, data | bits[speed]); |
cfb739b4 GKH |
355 | } |
356 | ||
e1bc5845 AC |
357 | /** |
358 | * ET1310_PhyLinkStatus - read link state | |
359 | * @etdev: device to read | |
360 | * @link_status: reported link state | |
361 | * @autoneg: reported autonegotiation state (complete/incomplete/disabled) | |
362 | * @linkspeed: returnedlink speed in use | |
363 | * @duplex_mode: reported half/full duplex state | |
364 | * @mdi_mdix: not yet working | |
365 | * @masterslave: report whether we are master or slave | |
366 | * @polarity: link polarity | |
367 | * | |
368 | * I can read your lan like a magazine | |
369 | * I see if your up | |
370 | * I know your link speed | |
371 | * I see all the setting that you'd rather keep | |
372 | */ | |
373 | ||
1210db95 AC |
374 | static void ET1310_PhyLinkStatus(struct et131x_adapter *etdev, |
375 | u8 *link_status, | |
376 | u32 *autoneg, | |
377 | u32 *linkspeed, | |
378 | u32 *duplex_mode, | |
379 | u32 *mdi_mdix, | |
380 | u32 *masterslave, u32 *polarity) | |
cfb739b4 | 381 | { |
1210db95 AC |
382 | u16 mistatus = 0; |
383 | u16 is1000BaseT = 0; | |
384 | u16 vmi_phystatus = 0; | |
385 | u16 control = 0; | |
cfb739b4 | 386 | |
1210db95 AC |
387 | MiRead(etdev, PHY_STATUS, &mistatus); |
388 | MiRead(etdev, PHY_1000_STATUS, &is1000BaseT); | |
389 | MiRead(etdev, PHY_PHY_STATUS, &vmi_phystatus); | |
390 | MiRead(etdev, PHY_CONTROL, &control); | |
cfb739b4 | 391 | |
e1bc5845 AC |
392 | *link_status = (vmi_phystatus & 0x0040) ? 1 : 0; |
393 | *autoneg = (control & 0x1000) ? ((vmi_phystatus & 0x0020) ? | |
1210db95 AC |
394 | TRUEPHY_ANEG_COMPLETE : |
395 | TRUEPHY_ANEG_NOT_COMPLETE) : | |
396 | TRUEPHY_ANEG_DISABLED; | |
e1bc5845 AC |
397 | *linkspeed = (vmi_phystatus & 0x0300) >> 8; |
398 | *duplex_mode = (vmi_phystatus & 0x0080) >> 7; | |
399 | /* NOTE: Need to complete this */ | |
400 | *mdi_mdix = 0; | |
401 | ||
402 | *masterslave = (is1000BaseT & 0x4000) ? | |
403 | TRUEPHY_CFG_MASTER : TRUEPHY_CFG_SLAVE; | |
404 | *polarity = (vmi_phystatus & 0x0400) ? | |
405 | TRUEPHY_POLARITY_INVERTED : TRUEPHY_POLARITY_NORMAL; | |
1210db95 | 406 | } |
cfb739b4 | 407 | |
1210db95 AC |
408 | static void ET1310_PhyAndOrReg(struct et131x_adapter *etdev, |
409 | u16 regnum, u16 andMask, u16 orMask) | |
410 | { | |
411 | u16 reg; | |
cfb739b4 | 412 | |
1210db95 | 413 | MiRead(etdev, regnum, ®); |
1210db95 | 414 | reg &= andMask; |
1210db95 | 415 | reg |= orMask; |
1210db95 AC |
416 | MiWrite(etdev, regnum, reg); |
417 | } | |
cfb739b4 | 418 | |
e1bc5845 | 419 | /* Still used from _mac for BIT_READ */ |
1210db95 AC |
420 | void ET1310_PhyAccessMiBit(struct et131x_adapter *etdev, u16 action, |
421 | u16 regnum, u16 bitnum, u8 *value) | |
422 | { | |
423 | u16 reg; | |
e1bc5845 | 424 | u16 mask = 0x0001 << bitnum; |
cfb739b4 | 425 | |
1210db95 AC |
426 | /* Read the requested register */ |
427 | MiRead(etdev, regnum, ®); | |
428 | ||
429 | switch (action) { | |
430 | case TRUEPHY_BIT_READ: | |
e1bc5845 | 431 | *value = (reg & mask) >> bitnum; |
1210db95 AC |
432 | break; |
433 | ||
434 | case TRUEPHY_BIT_SET: | |
e1bc5845 | 435 | MiWrite(etdev, regnum, reg | mask); |
1210db95 AC |
436 | break; |
437 | ||
438 | case TRUEPHY_BIT_CLEAR: | |
e1bc5845 | 439 | MiWrite(etdev, regnum, reg & ~mask); |
1210db95 AC |
440 | break; |
441 | ||
442 | default: | |
443 | break; | |
cfb739b4 | 444 | } |
1210db95 | 445 | } |
cfb739b4 | 446 | |
1210db95 AC |
447 | void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *etdev, |
448 | u16 duplex) | |
449 | { | |
450 | u16 data; | |
cfb739b4 | 451 | |
1210db95 AC |
452 | /* Read the PHY 1000 Base-T Control Register */ |
453 | MiRead(etdev, PHY_1000_CONTROL, &data); | |
cfb739b4 | 454 | |
1210db95 AC |
455 | /* Clear Bits 8,9 */ |
456 | data &= ~0x0300; | |
cfb739b4 | 457 | |
1210db95 AC |
458 | switch (duplex) { |
459 | case TRUEPHY_ADV_DUPLEX_NONE: | |
460 | /* Duplex already cleared, do nothing */ | |
461 | break; | |
cfb739b4 | 462 | |
1210db95 AC |
463 | case TRUEPHY_ADV_DUPLEX_FULL: |
464 | /* Set Bit 9 */ | |
465 | data |= 0x0200; | |
466 | break; | |
cfb739b4 | 467 | |
1210db95 AC |
468 | case TRUEPHY_ADV_DUPLEX_HALF: |
469 | /* Set Bit 8 */ | |
470 | data |= 0x0100; | |
471 | break; | |
cfb739b4 | 472 | |
1210db95 AC |
473 | case TRUEPHY_ADV_DUPLEX_BOTH: |
474 | default: | |
475 | data |= 0x0300; | |
476 | break; | |
477 | } | |
cfb739b4 | 478 | |
1210db95 AC |
479 | /* Write back advertisement */ |
480 | MiWrite(etdev, PHY_1000_CONTROL, data); | |
481 | } | |
482 | ||
483 | static void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *etdev, | |
484 | u16 duplex) | |
485 | { | |
486 | u16 data; | |
487 | ||
488 | /* Read the Autonegotiation Register (10/100) */ | |
489 | MiRead(etdev, PHY_AUTO_ADVERTISEMENT, &data); | |
490 | ||
491 | /* Clear bits 7,8 */ | |
492 | data &= ~0x0180; | |
493 | ||
494 | switch (duplex) { | |
495 | case TRUEPHY_ADV_DUPLEX_NONE: | |
496 | /* Duplex already cleared, do nothing */ | |
497 | break; | |
498 | ||
499 | case TRUEPHY_ADV_DUPLEX_FULL: | |
500 | /* Set Bit 8 */ | |
501 | data |= 0x0100; | |
502 | break; | |
503 | ||
504 | case TRUEPHY_ADV_DUPLEX_HALF: | |
505 | /* Set Bit 7 */ | |
506 | data |= 0x0080; | |
507 | break; | |
508 | ||
509 | case TRUEPHY_ADV_DUPLEX_BOTH: | |
510 | default: | |
511 | /* Set Bits 7,8 */ | |
512 | data |= 0x0180; | |
513 | break; | |
514 | } | |
515 | ||
516 | /* Write back advertisement */ | |
517 | MiWrite(etdev, PHY_AUTO_ADVERTISEMENT, data); | |
518 | } | |
519 | ||
520 | static void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *etdev, | |
521 | u16 duplex) | |
522 | { | |
523 | u16 data; | |
524 | ||
525 | /* Read the Autonegotiation Register (10/100) */ | |
526 | MiRead(etdev, PHY_AUTO_ADVERTISEMENT, &data); | |
527 | ||
528 | /* Clear bits 5,6 */ | |
529 | data &= ~0x0060; | |
530 | ||
531 | switch (duplex) { | |
532 | case TRUEPHY_ADV_DUPLEX_NONE: | |
533 | /* Duplex already cleared, do nothing */ | |
534 | break; | |
535 | ||
536 | case TRUEPHY_ADV_DUPLEX_FULL: | |
537 | /* Set Bit 6 */ | |
538 | data |= 0x0040; | |
539 | break; | |
540 | ||
541 | case TRUEPHY_ADV_DUPLEX_HALF: | |
542 | /* Set Bit 5 */ | |
543 | data |= 0x0020; | |
544 | break; | |
545 | ||
546 | case TRUEPHY_ADV_DUPLEX_BOTH: | |
547 | default: | |
548 | /* Set Bits 5,6 */ | |
549 | data |= 0x0060; | |
550 | break; | |
cfb739b4 | 551 | } |
1210db95 AC |
552 | |
553 | /* Write back advertisement */ | |
554 | MiWrite(etdev, PHY_AUTO_ADVERTISEMENT, data); | |
cfb739b4 GKH |
555 | } |
556 | ||
cfb739b4 | 557 | /** |
e1bc5845 AC |
558 | * et131x_setphy_normal - Set PHY for normal operation. |
559 | * @etdev: pointer to our private adapter structure | |
cfb739b4 | 560 | * |
e1bc5845 AC |
561 | * Used by Power Management to force the PHY into 10 Base T half-duplex mode, |
562 | * when going to D3 in WOL mode. Also used during initialization to set the | |
563 | * PHY for normal operation. | |
cfb739b4 | 564 | */ |
e1bc5845 | 565 | void et131x_setphy_normal(struct et131x_adapter *etdev) |
cfb739b4 | 566 | { |
e1bc5845 | 567 | /* Make sure the PHY is powered up */ |
25ad00bb | 568 | ET1310_PhyPowerDown(etdev, 0); |
e1bc5845 | 569 | et131x_xcvr_init(etdev); |
cfb739b4 GKH |
570 | } |
571 | ||
572 | ||
1210db95 AC |
573 | /** |
574 | * et131x_xcvr_init - Init the phy if we are setting it into force mode | |
e1bc5845 | 575 | * @etdev: pointer to our private adapter structure |
1210db95 | 576 | * |
1210db95 | 577 | */ |
e1bc5845 | 578 | static void et131x_xcvr_init(struct et131x_adapter *etdev) |
1210db95 | 579 | { |
1210db95 AC |
580 | MI_IMR_t imr; |
581 | MI_ISR_t isr; | |
582 | MI_LCR2_t lcr2; | |
cfb739b4 | 583 | |
1210db95 | 584 | /* Zero out the adapter structure variable representing BMSR */ |
e1bc5845 | 585 | etdev->Bmsr.value = 0; |
cfb739b4 | 586 | |
e1bc5845 AC |
587 | MiRead(etdev, (u8) offsetof(MI_REGS_t, isr), &isr.value); |
588 | MiRead(etdev, (u8) offsetof(MI_REGS_t, imr), &imr.value); | |
cfb739b4 | 589 | |
1210db95 AC |
590 | /* Set the link status interrupt only. Bad behavior when link status |
591 | * and auto neg are set, we run into a nested interrupt problem | |
592 | */ | |
593 | imr.bits.int_en = 0x1; | |
594 | imr.bits.link_status = 0x1; | |
595 | imr.bits.autoneg_status = 0x1; | |
cfb739b4 | 596 | |
e1bc5845 | 597 | MiWrite(etdev, (u8) offsetof(MI_REGS_t, imr), imr.value); |
cfb739b4 | 598 | |
1210db95 AC |
599 | /* Set the LED behavior such that LED 1 indicates speed (off = |
600 | * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates | |
601 | * link and activity (on for link, blink off for activity). | |
602 | * | |
603 | * NOTE: Some customizations have been added here for specific | |
604 | * vendors; The LED behavior is now determined by vendor data in the | |
605 | * EEPROM. However, the above description is the default. | |
606 | */ | |
e1bc5845 AC |
607 | if ((etdev->eepromData[1] & 0x4) == 0) { |
608 | MiRead(etdev, (u8) offsetof(MI_REGS_t, lcr2), | |
1210db95 | 609 | &lcr2.value); |
e1bc5845 | 610 | if ((etdev->eepromData[1] & 0x8) == 0) |
1210db95 AC |
611 | lcr2.bits.led_tx_rx = 0x3; |
612 | else | |
613 | lcr2.bits.led_tx_rx = 0x4; | |
614 | lcr2.bits.led_link = 0xa; | |
e1bc5845 | 615 | MiWrite(etdev, (u8) offsetof(MI_REGS_t, lcr2), |
1210db95 AC |
616 | lcr2.value); |
617 | } | |
cfb739b4 | 618 | |
1210db95 | 619 | /* Determine if we need to go into a force mode and set it */ |
e1bc5845 AC |
620 | if (etdev->AiForceSpeed == 0 && etdev->AiForceDpx == 0) { |
621 | if (etdev->RegistryFlowControl == TxOnly || | |
622 | etdev->RegistryFlowControl == Both) | |
623 | ET1310_PhyAccessMiBit(etdev, | |
1210db95 AC |
624 | TRUEPHY_BIT_SET, 4, 11, NULL); |
625 | else | |
e1bc5845 | 626 | ET1310_PhyAccessMiBit(etdev, |
1210db95 | 627 | TRUEPHY_BIT_CLEAR, 4, 11, NULL); |
cfb739b4 | 628 | |
e1bc5845 AC |
629 | if (etdev->RegistryFlowControl == Both) |
630 | ET1310_PhyAccessMiBit(etdev, | |
1210db95 AC |
631 | TRUEPHY_BIT_SET, 4, 10, NULL); |
632 | else | |
e1bc5845 | 633 | ET1310_PhyAccessMiBit(etdev, |
1210db95 | 634 | TRUEPHY_BIT_CLEAR, 4, 10, NULL); |
cfb739b4 | 635 | |
1210db95 | 636 | /* Set the phy to autonegotiation */ |
e1bc5845 | 637 | ET1310_PhyAutoNeg(etdev, true); |
cfb739b4 | 638 | |
1210db95 | 639 | /* NOTE - Do we need this? */ |
e1bc5845 AC |
640 | ET1310_PhyAccessMiBit(etdev, TRUEPHY_BIT_SET, 0, 9, NULL); |
641 | return; | |
642 | } | |
643 | ||
644 | ET1310_PhyAutoNeg(etdev, false); | |
645 | ||
646 | /* Set to the correct force mode. */ | |
647 | if (etdev->AiForceDpx != 1) { | |
648 | if (etdev->RegistryFlowControl == TxOnly || | |
649 | etdev->RegistryFlowControl == Both) | |
650 | ET1310_PhyAccessMiBit(etdev, | |
651 | TRUEPHY_BIT_SET, 4, 11, NULL); | |
652 | else | |
653 | ET1310_PhyAccessMiBit(etdev, | |
654 | TRUEPHY_BIT_CLEAR, 4, 11, NULL); | |
655 | ||
656 | if (etdev->RegistryFlowControl == Both) | |
657 | ET1310_PhyAccessMiBit(etdev, | |
658 | TRUEPHY_BIT_SET, 4, 10, NULL); | |
659 | else | |
660 | ET1310_PhyAccessMiBit(etdev, | |
661 | TRUEPHY_BIT_CLEAR, 4, 10, NULL); | |
1210db95 | 662 | } else { |
e1bc5845 AC |
663 | ET1310_PhyAccessMiBit(etdev, TRUEPHY_BIT_CLEAR, 4, 10, NULL); |
664 | ET1310_PhyAccessMiBit(etdev, TRUEPHY_BIT_CLEAR, 4, 11, NULL); | |
665 | } | |
666 | ET1310_PhyPowerDown(etdev, 1); | |
667 | switch (etdev->AiForceSpeed) { | |
668 | case 10: | |
669 | /* First we need to turn off all other advertisement */ | |
670 | ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
671 | ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
672 | if (etdev->AiForceDpx == 1) { | |
673 | /* Set our advertise values accordingly */ | |
674 | ET1310_PhyAdvertise10BaseT(etdev, | |
675 | TRUEPHY_ADV_DUPLEX_HALF); | |
676 | } else if (etdev->AiForceDpx == 2) { | |
677 | /* Set our advertise values accordingly */ | |
678 | ET1310_PhyAdvertise10BaseT(etdev, | |
679 | TRUEPHY_ADV_DUPLEX_FULL); | |
1210db95 | 680 | } else { |
e1bc5845 AC |
681 | /* Disable autoneg */ |
682 | ET1310_PhyAutoNeg(etdev, false); | |
683 | /* Disable rest of the advertisements */ | |
684 | ET1310_PhyAdvertise10BaseT(etdev, | |
685 | TRUEPHY_ADV_DUPLEX_NONE); | |
686 | /* Force 10 Mbps */ | |
687 | ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_10MBPS); | |
688 | /* Force Full duplex */ | |
689 | ET1310_PhyDuplexMode(etdev, TRUEPHY_DUPLEX_FULL); | |
1210db95 | 690 | } |
e1bc5845 AC |
691 | break; |
692 | case 100: | |
693 | /* first we need to turn off all other advertisement */ | |
694 | ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
695 | ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
696 | if (etdev->AiForceDpx == 1) { | |
697 | /* Set our advertise values accordingly */ | |
698 | ET1310_PhyAdvertise100BaseT(etdev, | |
699 | TRUEPHY_ADV_DUPLEX_HALF); | |
700 | /* Set speed */ | |
701 | ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_100MBPS); | |
702 | } else if (etdev->AiForceDpx == 2) { | |
703 | /* Set our advertise values accordingly */ | |
704 | ET1310_PhyAdvertise100BaseT(etdev, | |
705 | TRUEPHY_ADV_DUPLEX_FULL); | |
706 | } else { | |
707 | /* Disable autoneg */ | |
708 | ET1310_PhyAutoNeg(etdev, false); | |
709 | /* Disable other advertisement */ | |
710 | ET1310_PhyAdvertise100BaseT(etdev, | |
711 | TRUEPHY_ADV_DUPLEX_NONE); | |
712 | /* Force 100 Mbps */ | |
713 | ET1310_PhySpeedSelect(etdev, TRUEPHY_SPEED_100MBPS); | |
714 | /* Force Full duplex */ | |
715 | ET1310_PhyDuplexMode(etdev, TRUEPHY_DUPLEX_FULL); | |
1210db95 | 716 | } |
e1bc5845 AC |
717 | break; |
718 | case 1000: | |
719 | /* first we need to turn off all other advertisement */ | |
720 | ET1310_PhyAdvertise100BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
721 | ET1310_PhyAdvertise10BaseT(etdev, TRUEPHY_ADV_DUPLEX_NONE); | |
722 | /* set our advertise values accordingly */ | |
723 | ET1310_PhyAdvertise1000BaseT(etdev, TRUEPHY_ADV_DUPLEX_FULL); | |
724 | break; | |
cfb739b4 | 725 | } |
e1bc5845 | 726 | ET1310_PhyPowerDown(etdev, 0); |
cfb739b4 GKH |
727 | } |
728 | ||
1210db95 AC |
729 | void et131x_Mii_check(struct et131x_adapter *etdev, |
730 | MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints) | |
cfb739b4 | 731 | { |
1210db95 AC |
732 | u8 link_status; |
733 | u32 autoneg_status; | |
734 | u32 speed; | |
735 | u32 duplex; | |
736 | u32 mdi_mdix; | |
737 | u32 masterslave; | |
738 | u32 polarity; | |
739 | unsigned long flags; | |
cfb739b4 | 740 | |
1210db95 AC |
741 | if (bmsr_ints.bits.link_status) { |
742 | if (bmsr.bits.link_status) { | |
743 | etdev->PoMgmt.TransPhyComaModeOnBoot = 20; | |
cfb739b4 | 744 | |
1210db95 AC |
745 | /* Update our state variables and indicate the |
746 | * connected state | |
747 | */ | |
748 | spin_lock_irqsave(&etdev->Lock, flags); | |
cfb739b4 | 749 | |
1210db95 AC |
750 | etdev->MediaState = NETIF_STATUS_MEDIA_CONNECT; |
751 | etdev->Flags &= ~fMP_ADAPTER_LINK_DETECTION; | |
cfb739b4 | 752 | |
1210db95 | 753 | spin_unlock_irqrestore(&etdev->Lock, flags); |
cfb739b4 | 754 | |
1210db95 AC |
755 | netif_carrier_on(etdev->netdev); |
756 | } else { | |
757 | dev_warn(&etdev->pdev->dev, | |
758 | "Link down - cable problem ?\n"); | |
cfb739b4 | 759 | |
1210db95 AC |
760 | if (etdev->linkspeed == TRUEPHY_SPEED_10MBPS) { |
761 | /* NOTE - Is there a way to query this without | |
762 | * TruePHY? | |
763 | * && TRU_QueryCoreType(etdev->hTruePhy, 0) == EMI_TRUEPHY_A13O) { | |
764 | */ | |
765 | u16 Register18; | |
cfb739b4 | 766 | |
1210db95 AC |
767 | MiRead(etdev, 0x12, &Register18); |
768 | MiWrite(etdev, 0x12, Register18 | 0x4); | |
769 | MiWrite(etdev, 0x10, Register18 | 0x8402); | |
770 | MiWrite(etdev, 0x11, Register18 | 511); | |
771 | MiWrite(etdev, 0x12, Register18); | |
772 | } | |
cfb739b4 | 773 | |
1210db95 AC |
774 | /* For the first N seconds of life, we are in "link |
775 | * detection" When we are in this state, we should | |
776 | * only report "connected". When the LinkDetection | |
777 | * Timer expires, we can report disconnected (handled | |
778 | * in the LinkDetectionDPC). | |
779 | */ | |
780 | if (!(etdev->Flags & fMP_ADAPTER_LINK_DETECTION) || | |
781 | (etdev->MediaState == NETIF_STATUS_MEDIA_DISCONNECT)) { | |
782 | spin_lock_irqsave(&etdev->Lock, flags); | |
783 | etdev->MediaState = | |
784 | NETIF_STATUS_MEDIA_DISCONNECT; | |
785 | spin_unlock_irqrestore(&etdev->Lock, | |
786 | flags); | |
cfb739b4 | 787 | |
1210db95 AC |
788 | netif_carrier_off(etdev->netdev); |
789 | } | |
cfb739b4 | 790 | |
1210db95 AC |
791 | etdev->linkspeed = 0; |
792 | etdev->duplex_mode = 0; | |
cfb739b4 | 793 | |
1210db95 AC |
794 | /* Free the packets being actively sent & stopped */ |
795 | et131x_free_busy_send_packets(etdev); | |
cfb739b4 | 796 | |
1210db95 AC |
797 | /* Re-initialize the send structures */ |
798 | et131x_init_send(etdev); | |
cfb739b4 | 799 | |
1210db95 AC |
800 | /* Reset the RFD list and re-start RU */ |
801 | et131x_reset_recv(etdev); | |
cfb739b4 | 802 | |
1210db95 AC |
803 | /* |
804 | * Bring the device back to the state it was during | |
805 | * init prior to autonegotiation being complete. This | |
806 | * way, when we get the auto-neg complete interrupt, | |
807 | * we can complete init by calling ConfigMacREGS2. | |
808 | */ | |
809 | et131x_soft_reset(etdev); | |
cfb739b4 | 810 | |
1210db95 AC |
811 | /* Setup ET1310 as per the documentation */ |
812 | et131x_adapter_setup(etdev); | |
cfb739b4 | 813 | |
1210db95 AC |
814 | /* Setup the PHY into coma mode until the cable is |
815 | * plugged back in | |
816 | */ | |
817 | if (etdev->RegistryPhyComa == 1) | |
818 | EnablePhyComa(etdev); | |
819 | } | |
cfb739b4 GKH |
820 | } |
821 | ||
1210db95 AC |
822 | if (bmsr_ints.bits.auto_neg_complete || |
823 | (etdev->AiForceDpx == 3 && bmsr_ints.bits.link_status)) { | |
824 | if (bmsr.bits.auto_neg_complete || etdev->AiForceDpx == 3) { | |
825 | ET1310_PhyLinkStatus(etdev, | |
826 | &link_status, &autoneg_status, | |
827 | &speed, &duplex, &mdi_mdix, | |
828 | &masterslave, &polarity); | |
cfb739b4 | 829 | |
1210db95 AC |
830 | etdev->linkspeed = speed; |
831 | etdev->duplex_mode = duplex; | |
cfb739b4 | 832 | |
1210db95 | 833 | etdev->PoMgmt.TransPhyComaModeOnBoot = 20; |
cfb739b4 | 834 | |
1210db95 AC |
835 | if (etdev->linkspeed == TRUEPHY_SPEED_10MBPS) { |
836 | /* | |
837 | * NOTE - Is there a way to query this without | |
838 | * TruePHY? | |
839 | * && TRU_QueryCoreType(etdev->hTruePhy, 0)== EMI_TRUEPHY_A13O) { | |
840 | */ | |
841 | u16 Register18; | |
cfb739b4 | 842 | |
1210db95 AC |
843 | MiRead(etdev, 0x12, &Register18); |
844 | MiWrite(etdev, 0x12, Register18 | 0x4); | |
845 | MiWrite(etdev, 0x10, Register18 | 0x8402); | |
846 | MiWrite(etdev, 0x11, Register18 | 511); | |
847 | MiWrite(etdev, 0x12, Register18); | |
848 | } | |
cfb739b4 | 849 | |
1210db95 | 850 | ConfigFlowControl(etdev); |
cfb739b4 | 851 | |
1210db95 AC |
852 | if (etdev->linkspeed == TRUEPHY_SPEED_1000MBPS && |
853 | etdev->RegistryJumboPacket > 2048) | |
854 | ET1310_PhyAndOrReg(etdev, 0x16, 0xcfff, | |
855 | 0x2000); | |
cfb739b4 | 856 | |
1210db95 AC |
857 | SetRxDmaTimer(etdev); |
858 | ConfigMACRegs2(etdev); | |
859 | } | |
cfb739b4 | 860 | } |
cfb739b4 GKH |
861 | } |
862 | ||
1210db95 AC |
863 | /* |
864 | * The routines which follow provide low-level access to the PHY, and are used | |
865 | * primarily by the routines above (although there are a few places elsewhere | |
866 | * in the driver where this level of access is required). | |
867 | */ | |
cfb739b4 | 868 | |
1210db95 AC |
869 | static const u16 ConfigPhy[25][2] = { |
870 | /* Reg Value Register */ | |
871 | /* Addr */ | |
872 | {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */ | |
873 | {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */ | |
874 | {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */ | |
cfb739b4 | 875 | |
1210db95 AC |
876 | {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */ |
877 | {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */ | |
878 | {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */ | |
cfb739b4 | 879 | |
1210db95 AC |
880 | {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */ |
881 | {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */ | |
882 | {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */ | |
cfb739b4 | 883 | |
1210db95 AC |
884 | {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */ |
885 | {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */ | |
886 | {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */ | |
cfb739b4 | 887 | |
1210db95 | 888 | {0x300D, 1}, /* DisableNorm */ |
cfb739b4 | 889 | |
1210db95 | 890 | {0x280C, 0x0180}, /* LinkHoldEnd */ |
9fa81099 | 891 | |
1210db95 | 892 | {0x1C21, 0x0002}, /* AlphaM */ |
9fa81099 | 893 | |
1210db95 AC |
894 | {0x3821, 6}, /* FfeLkgTx0 */ |
895 | {0x381D, 1}, /* FfeLkg1g4 */ | |
896 | {0x381E, 1}, /* FfeLkg1g5 */ | |
897 | {0x381F, 1}, /* FfeLkg1g6 */ | |
898 | {0x3820, 1}, /* FfeLkg1g7 */ | |
cfb739b4 | 899 | |
1210db95 AC |
900 | {0x8402, 0x01F0}, /* Btinact */ |
901 | {0x800E, 20}, /* LftrainTime */ | |
902 | {0x800F, 24}, /* DvguardTime */ | |
903 | {0x8010, 46}, /* IdlguardTime */ | |
cfb739b4 | 904 | |
1210db95 | 905 | {0, 0} |
cfb739b4 | 906 | |
1210db95 | 907 | }; |
cfb739b4 | 908 | |
1210db95 AC |
909 | /* condensed version of the phy initialization routine */ |
910 | void ET1310_PhyInit(struct et131x_adapter *etdev) | |
911 | { | |
912 | u16 data, index; | |
cfb739b4 | 913 | |
1210db95 AC |
914 | if (etdev == NULL) |
915 | return; | |
cfb739b4 | 916 | |
1210db95 AC |
917 | /* get the identity (again ?) */ |
918 | MiRead(etdev, PHY_ID_1, &data); | |
919 | MiRead(etdev, PHY_ID_2, &data); | |
cfb739b4 | 920 | |
1210db95 AC |
921 | /* what does this do/achieve ? */ |
922 | MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */ | |
923 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0006); | |
cfb739b4 | 924 | |
1210db95 AC |
925 | /* read modem register 0402, should I do something with the return |
926 | data ? */ | |
927 | MiWrite(etdev, PHY_INDEX_REG, 0x0402); | |
928 | MiRead(etdev, PHY_DATA_REG, &data); | |
cfb739b4 | 929 | |
1210db95 AC |
930 | /* what does this do/achieve ? */ |
931 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002); | |
cfb739b4 | 932 | |
1210db95 AC |
933 | /* get the identity (again ?) */ |
934 | MiRead(etdev, PHY_ID_1, &data); | |
935 | MiRead(etdev, PHY_ID_2, &data); | |
cfb739b4 | 936 | |
1210db95 AC |
937 | /* what does this achieve ? */ |
938 | MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */ | |
939 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0006); | |
cfb739b4 | 940 | |
1210db95 AC |
941 | /* read modem register 0402, should I do something with |
942 | the return data? */ | |
943 | MiWrite(etdev, PHY_INDEX_REG, 0x0402); | |
944 | MiRead(etdev, PHY_DATA_REG, &data); | |
cfb739b4 | 945 | |
1210db95 | 946 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002); |
cfb739b4 | 947 | |
1210db95 AC |
948 | /* what does this achieve (should return 0x1040) */ |
949 | MiRead(etdev, PHY_CONTROL, &data); | |
950 | MiRead(etdev, PHY_MPHY_CONTROL_REG, &data); /* should read 0002 */ | |
951 | MiWrite(etdev, PHY_CONTROL, 0x1840); | |
cfb739b4 | 952 | |
1210db95 | 953 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0007); |
cfb739b4 | 954 | |
1210db95 AC |
955 | /* here the writing of the array starts.... */ |
956 | index = 0; | |
957 | while (ConfigPhy[index][0] != 0x0000) { | |
958 | /* write value */ | |
959 | MiWrite(etdev, PHY_INDEX_REG, ConfigPhy[index][0]); | |
960 | MiWrite(etdev, PHY_DATA_REG, ConfigPhy[index][1]); | |
cfb739b4 | 961 | |
1210db95 AC |
962 | /* read it back */ |
963 | MiWrite(etdev, PHY_INDEX_REG, ConfigPhy[index][0]); | |
964 | MiRead(etdev, PHY_DATA_REG, &data); | |
cfb739b4 | 965 | |
1210db95 AC |
966 | /* do a check on the value read back ? */ |
967 | index++; | |
cfb739b4 | 968 | } |
1210db95 AC |
969 | /* here the writing of the array ends... */ |
970 | ||
971 | MiRead(etdev, PHY_CONTROL, &data); /* 0x1840 */ | |
972 | MiRead(etdev, PHY_MPHY_CONTROL_REG, &data);/* should read 0007 */ | |
973 | MiWrite(etdev, PHY_CONTROL, 0x1040); | |
974 | MiWrite(etdev, PHY_MPHY_CONTROL_REG, 0x0002); | |
cfb739b4 | 975 | } |
1210db95 | 976 |