blob: 6320feaba734315d5e3480b7a3c7660dc58ad93c [file] [log] [blame]
wdenk544e9732004-02-06 23:19:44 +00001/*-----------------------------------------------------------------------------+
2 |
3 | This source code has been made available to you by IBM on an AS-IS
4 | basis. Anyone receiving this source is licensed under IBM
5 | copyrights to use it in any way he or she deems fit, including
6 | copying it, modifying it, compiling it, and redistributing it either
7 | with or without modifications. No license under IBM patents or
8 | patent applications is to be implied by the copyright license.
9 |
10 | Any user of this software should understand that IBM cannot provide
11 | technical support for this software and will not be responsible for
12 | any consequences resulting from the use of this software.
13 |
14 | Any person who transfers this source code or any derivative work
15 | must include the IBM copyright notice, this paragraph, and the
16 | preceding two paragraphs in the transferred software.
17 |
18 | COPYRIGHT I B M CORPORATION 1995
19 | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
20 +-----------------------------------------------------------------------------*/
21/*-----------------------------------------------------------------------------+
22 |
23 | File Name: miiphy.c
24 |
25 | Function: This module has utilities for accessing the MII PHY through
26 | the EMAC3 macro.
27 |
28 | Author: Mark Wisner
29 |
30 | Change Activity-
31 |
32 | Date Description of Change BY
33 | --------- --------------------- ---
34 | 05-May-99 Created MKW
35 | 01-Jul-99 Changed clock setting of sta_reg from 66Mhz to 50Mhz to
36 | better match OPB speed. Also modified delay times. JWB
37 | 29-Jul-99 Added Full duplex support MKW
38 | 24-Aug-99 Removed printf from dp83843_duplex() JWB
39 | 19-Jul-00 Ported to esd cpci405 sr
40 | 23-Dec-03 Ported from miiphy.c to 440GX Travis Sawyer TBS
41 | <travis.sawyer@sandburst.com>
42 |
43 +-----------------------------------------------------------------------------*/
44
45#include <common.h>
46#include <asm/processor.h>
47#include <ppc_asm.tmpl>
48#include <commproc.h>
49#include <440gx_enet.h>
50#include <405_mal.h>
51#include <miiphy.h>
52
53#if defined(CONFIG_440) && defined(CONFIG_NET_MULTI)
54
55
56/***********************************************************/
57/* Dump out to the screen PHY regs */
58/***********************************************************/
59
60void miiphy_dump (unsigned char addr)
61{
62 unsigned long i;
63 unsigned short data;
64
65
66 for (i = 0; i < 0x1A; i++) {
67 if (miiphy_read (addr, i, &data)) {
68 printf ("read error for reg %lx\n", i);
69 return;
70 }
71 printf ("Phy reg %lx ==> %4x\n", i, data);
72
73 /* jump to the next set of regs */
74 if (i == 0x07)
75 i = 0x0f;
76
77 } /* end for loop */
78} /* end dump */
79
80
81/***********************************************************/
82/* (Re)start autonegotiation */
83/***********************************************************/
84int phy_setup_aneg (unsigned char addr)
85{
86 unsigned short ctl, adv;
87
88 /* Setup standard advertise */
89 miiphy_read (addr, PHY_ANAR, &adv);
90 adv |= (PHY_ANLPAR_ACK | PHY_ANLPAR_RF | PHY_ANLPAR_T4 |
91 PHY_ANLPAR_TXFD | PHY_ANLPAR_TX | PHY_ANLPAR_10FD |
92 PHY_ANLPAR_10);
93 miiphy_write (addr, PHY_ANAR, adv);
94
95 /* Start/Restart aneg */
96 miiphy_read (addr, PHY_BMCR, &ctl);
97 ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
98 miiphy_write (addr, PHY_BMCR, ctl);
99
100 return 0;
101}
102
103
104/***********************************************************/
105/* read a phy reg and return the value with a rc */
106/***********************************************************/
107unsigned int miiphy_getemac_offset (void)
108{
109 unsigned long zmii;
110 unsigned long eoffset;
111
112 /* Need to find out which mdi port we're using */
113 zmii = in32 (ZMII_FER);
114
115 if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0))) {
116 /* using port 0 */
117 eoffset = 0;
118 } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1))) {
119 /* using port 1 */
120 eoffset = 0x100;
121 } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2))) {
122 /* using port 2 */
123 eoffset = 0x400;
124 } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3))) {
125 /* using port 3 */
126 eoffset = 0x600;
127 } else {
128 /* None of the mdi ports are enabled! */
129 /* enable port 0 */
130 zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
131 out32 (ZMII_FER, zmii);
132 eoffset = 0;
133 /* need to soft reset port 0 */
134 zmii = in32 (EMAC_M0);
135 zmii |= EMAC_M0_SRST;
136 out32 (EMAC_M0, zmii);
137 }
138
139 return (eoffset);
140
141}
142
143
144int miiphy_read (unsigned char addr, unsigned char reg, unsigned short *value)
145{
146 unsigned long sta_reg; /* STA scratch area */
147 unsigned long i;
148 unsigned long emac_reg;
149
150
151 emac_reg = miiphy_getemac_offset ();
152 /* see if it is ready for 1000 nsec */
153 i = 0;
154
155 /* see if it is ready for sec */
156 while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) {
157 udelay (7);
158 if (i > 5) {
159#if 0
160 printf ("read err 1\n");
161#endif
162 return -1;
163 }
164 i++;
165 }
166 sta_reg = reg; /* reg address */
167 /* set clock (50Mhz) and read flags */
Stefan Roeseb30f2a12005-08-08 12:42:22 +0200168#if defined(CONFIG_440GX)
wdenk544e9732004-02-06 23:19:44 +0000169 sta_reg |= EMAC_STACR_READ;
170#else
171 sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ;
172#endif
173
Stefan Roeseb30f2a12005-08-08 12:42:22 +0200174#if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX)
wdenk544e9732004-02-06 23:19:44 +0000175 sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
176#endif
177 sta_reg = sta_reg | (addr << 5); /* Phy address */
178
179 out32 (EMAC_STACR + emac_reg, sta_reg);
180#if 0 /* test-only */
181 printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */
182#endif
183
184 sta_reg = in32 (EMAC_STACR + emac_reg);
185 i = 0;
186 while ((sta_reg & EMAC_STACR_OC) == 0) {
187 udelay (7);
188 if (i > 5) {
189 return -1;
190 }
191 i++;
192 sta_reg = in32 (EMAC_STACR + emac_reg);
193 }
194 if ((sta_reg & EMAC_STACR_PHYE) != 0) {
195 return -1;
196 }
197
198 *value = *(short *) (&sta_reg);
199 return 0;
200
201
202} /* phy_read */
203
204
205/***********************************************************/
206/* write a phy reg and return the value with a rc */
207/***********************************************************/
208
209int miiphy_write (unsigned char addr, unsigned char reg, unsigned short value)
210{
211 unsigned long sta_reg; /* STA scratch area */
212 unsigned long i;
213 unsigned long emac_reg;
214
215 emac_reg = miiphy_getemac_offset ();
216 /* see if it is ready for 1000 nsec */
217 i = 0;
218
219 while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) {
220 if (i > 5)
221 return -1;
222 udelay (7);
223 i++;
224 }
225 sta_reg = 0;
226 sta_reg = reg; /* reg address */
227 /* set clock (50Mhz) and read flags */
Stefan Roeseb30f2a12005-08-08 12:42:22 +0200228#if defined(CONFIG_440GX)
wdenk544e9732004-02-06 23:19:44 +0000229 sta_reg |= EMAC_STACR_WRITE;
230#else
231 sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ;
232#endif
233
Stefan Roeseb30f2a12005-08-08 12:42:22 +0200234#if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX)
wdenk544e9732004-02-06 23:19:44 +0000235 sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ; /* Set clock frequency (PLB freq. dependend) */
236#endif
237 sta_reg = sta_reg | ((unsigned long) addr << 5); /* Phy address */
238 memcpy (&sta_reg, &value, 2); /* put in data */
239
240 out32 (EMAC_STACR + emac_reg, sta_reg);
241
242 /* wait for completion */
243 i = 0;
244 sta_reg = in32 (EMAC_STACR + emac_reg);
245 while ((sta_reg & EMAC_STACR_OC) == 0) {
246 udelay (7);
247 if (i > 5)
248 return -1;
249 i++;
250 sta_reg = in32 (EMAC_STACR + emac_reg);
251 }
252
253 if ((sta_reg & EMAC_STACR_PHYE) != 0)
254 return -1;
255 return 0;
256
257} /* phy_write */
258
259#endif /* CONFIG_405GP */