]> git.ipfire.org Git - people/ms/u-boot.git/blame - arch/powerpc/cpu/ppc4xx/miiphy.c
Move arch/ppc to arch/powerpc
[people/ms/u-boot.git] / arch / powerpc / cpu / ppc4xx / miiphy.c
CommitLineData
affae2bf 1/*-----------------------------------------------------------------------------+
31773496
JB
2 | This source code is dual-licensed. You may use it under the terms of the
3 | GNU General Public License version 2, or under the license below.
affae2bf 4 |
d6c61aab
SR
5 | This source code has been made available to you by IBM on an AS-IS
6 | basis. Anyone receiving this source is licensed under IBM
7 | copyrights to use it in any way he or she deems fit, including
8 | copying it, modifying it, compiling it, and redistributing it either
9 | with or without modifications. No license under IBM patents or
10 | patent applications is to be implied by the copyright license.
affae2bf 11 |
d6c61aab
SR
12 | Any user of this software should understand that IBM cannot provide
13 | technical support for this software and will not be responsible for
14 | any consequences resulting from the use of this software.
affae2bf 15 |
d6c61aab
SR
16 | Any person who transfers this source code or any derivative work
17 | must include the IBM copyright notice, this paragraph, and the
18 | preceding two paragraphs in the transferred software.
affae2bf 19 |
d6c61aab
SR
20 | COPYRIGHT I B M CORPORATION 1995
21 | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
affae2bf
WD
22 +-----------------------------------------------------------------------------*/
23/*-----------------------------------------------------------------------------+
24 |
d6c61aab 25 | File Name: miiphy.c
affae2bf 26 |
d6c61aab 27 | Function: This module has utilities for accessing the MII PHY through
affae2bf
WD
28 | the EMAC3 macro.
29 |
d6c61aab 30 | Author: Mark Wisner
affae2bf 31 |
affae2bf
WD
32 +-----------------------------------------------------------------------------*/
33
c3307fa1
SR
34/* define DEBUG for debugging output (obviously ;-)) */
35#if 0
36#define DEBUG
37#endif
38
affae2bf
WD
39#include <common.h>
40#include <asm/processor.h>
2d83476a 41#include <asm/io.h>
affae2bf
WD
42#include <ppc_asm.tmpl>
43#include <commproc.h>
d6c61aab 44#include <ppc4xx_enet.h>
affae2bf
WD
45#include <405_mal.h>
46#include <miiphy.h>
47
c3307fa1
SR
48#if !defined(CONFIG_PHY_CLK_FREQ)
49#define CONFIG_PHY_CLK_FREQ 0
50#endif
51
affae2bf 52/***********************************************************/
d6c61aab 53/* Dump out to the screen PHY regs */
affae2bf
WD
54/***********************************************************/
55
63ff004c 56void miiphy_dump (char *devname, unsigned char addr)
affae2bf
WD
57{
58 unsigned long i;
59 unsigned short data;
60
affae2bf 61 for (i = 0; i < 0x1A; i++) {
63ff004c 62 if (miiphy_read (devname, addr, i, &data)) {
affae2bf
WD
63 printf ("read error for reg %lx\n", i);
64 return;
65 }
66 printf ("Phy reg %lx ==> %4x\n", i, data);
67
68 /* jump to the next set of regs */
69 if (i == 0x07)
70 i = 0x0f;
71
d6c61aab
SR
72 } /* end for loop */
73} /* end dump */
affae2bf 74
affae2bf 75/***********************************************************/
d6c61aab 76/* (Re)start autonegotiation */
affae2bf 77/***********************************************************/
63ff004c 78int phy_setup_aneg (char *devname, unsigned char addr)
d6c61aab 79{
c348578b
LJ
80 u16 bmcr;
81
82#if defined(CONFIG_PHY_DYNAMIC_ANEG)
83 /*
84 * Set up advertisement based on capablilities reported by the PHY.
85 * This should work for both copper and fiber.
86 */
87 u16 bmsr;
88#if defined(CONFIG_PHY_GIGE)
89 u16 exsr = 0x0000;
90#endif
91
92 miiphy_read (devname, addr, PHY_BMSR, &bmsr);
93
94#if defined(CONFIG_PHY_GIGE)
95 if (bmsr & PHY_BMSR_EXT_STAT)
96 miiphy_read (devname, addr, PHY_EXSR, &exsr);
97
98 if (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH)) {
99 /* 1000BASE-X */
100 u16 anar = 0x0000;
101
102 if (exsr & PHY_EXSR_1000XF)
103 anar |= PHY_X_ANLPAR_FD;
104
105 if (exsr & PHY_EXSR_1000XH)
106 anar |= PHY_X_ANLPAR_HD;
107
108 miiphy_write (devname, addr, PHY_ANAR, anar);
109 } else
110#endif
111 {
112 u16 anar, btcr;
113
114 miiphy_read (devname, addr, PHY_ANAR, &anar);
115 anar &= ~(0x5000 | PHY_ANLPAR_T4 | PHY_ANLPAR_TXFD |
116 PHY_ANLPAR_TX | PHY_ANLPAR_10FD | PHY_ANLPAR_10);
117
118 miiphy_read (devname, addr, PHY_1000BTCR, &btcr);
119 btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
120
121 if (bmsr & PHY_BMSR_100T4)
122 anar |= PHY_ANLPAR_T4;
123
124 if (bmsr & PHY_BMSR_100TXF)
125 anar |= PHY_ANLPAR_TXFD;
126
127 if (bmsr & PHY_BMSR_100TXH)
128 anar |= PHY_ANLPAR_TX;
129
130 if (bmsr & PHY_BMSR_10TF)
131 anar |= PHY_ANLPAR_10FD;
132
133 if (bmsr & PHY_BMSR_10TH)
134 anar |= PHY_ANLPAR_10;
135
136 miiphy_write (devname, addr, PHY_ANAR, anar);
137
138#if defined(CONFIG_PHY_GIGE)
139 if (exsr & PHY_EXSR_1000TF)
140 btcr |= PHY_1000BTCR_1000FD;
141
142 if (exsr & PHY_EXSR_1000TH)
143 btcr |= PHY_1000BTCR_1000HD;
144
145 miiphy_write (devname, addr, PHY_1000BTCR, btcr);
146#endif
147 }
148
149#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
150 /*
151 * Set up standard advertisement
152 */
153 u16 adv;
d6c61aab 154
63ff004c 155 miiphy_read (devname, addr, PHY_ANAR, &adv);
74eb0222
MN
156 adv |= (PHY_ANLPAR_ACK | PHY_ANLPAR_TXFD | PHY_ANLPAR_TX |
157 PHY_ANLPAR_10FD | PHY_ANLPAR_10);
63ff004c 158 miiphy_write (devname, addr, PHY_ANAR, adv);
affae2bf 159
6c5879f3
MB
160 miiphy_read (devname, addr, PHY_1000BTCR, &adv);
161 adv |= (0x0300);
162 miiphy_write (devname, addr, PHY_1000BTCR, adv);
163
c348578b
LJ
164#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
165
d6c61aab 166 /* Start/Restart aneg */
c348578b
LJ
167 miiphy_read (devname, addr, PHY_BMCR, &bmcr);
168 bmcr |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
169 miiphy_write (devname, addr, PHY_BMCR, bmcr);
d6c61aab
SR
170
171 return 0;
172}
173
d6c61aab
SR
174/***********************************************************/
175/* read a phy reg and return the value with a rc */
176/***********************************************************/
c3307fa1
SR
177/* AMCC_TODO:
178 * Find out of the choice for the emac for MDIO is from the bridges,
179 * i.e. ZMII or RGMII as approporiate. If the bridges are not used
180 * to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
181 * used? If so, then this routine below does not apply to the 460EX/GT.
182 *
183 * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
184 * return EMAC0 offset here
78d78236
VG
185 * vg: For 460EX/460GT if internal GPCS PHY address is specified
186 * return appropriate EMAC offset
c3307fa1 187 */
78d78236 188unsigned int miiphy_getemac_offset(u8 addr)
affae2bf 189{
c3307fa1
SR
190#if (defined(CONFIG_440) && \
191 !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
192 !defined(CONFIG_460EX) && !defined(CONFIG_460GT)) && \
193 defined(CONFIG_NET_MULTI)
d6c61aab
SR
194 unsigned long zmii;
195 unsigned long eoffset;
196
197 /* Need to find out which mdi port we're using */
ddc922ff 198 zmii = in_be32((void *)ZMII0_FER);
d6c61aab 199
c348578b 200 if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
d6c61aab
SR
201 /* using port 0 */
202 eoffset = 0;
c348578b
LJ
203
204 else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
d6c61aab
SR
205 /* using port 1 */
206 eoffset = 0x100;
c348578b
LJ
207
208 else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
d6c61aab
SR
209 /* using port 2 */
210 eoffset = 0x400;
c348578b
LJ
211
212 else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
d6c61aab
SR
213 /* using port 3 */
214 eoffset = 0x600;
c348578b
LJ
215
216 else {
d6c61aab
SR
217 /* None of the mdi ports are enabled! */
218 /* enable port 0 */
219 zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
ddc922ff 220 out_be32((void *)ZMII0_FER, zmii);
d6c61aab
SR
221 eoffset = 0;
222 /* need to soft reset port 0 */
ddc922ff
NG
223 zmii = in_be32((void *)EMAC0_MR0);
224 zmii |= EMAC_MR0_SRST;
225 out_be32((void *)EMAC0_MR0, zmii);
d6c61aab
SR
226 }
227
228 return (eoffset);
229#else
dbbd1257
SR
230
231#if defined(CONFIG_NET_MULTI) && defined(CONFIG_405EX)
232 unsigned long rgmii;
233 int devnum = 1;
234
2d83476a 235 rgmii = in_be32((void *)RGMII_FER);
dbbd1257
SR
236 if (rgmii & (1 << (19 - devnum)))
237 return 0x100;
238#endif
239
78d78236 240#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
78d78236
VG
241 u32 eoffset = 0;
242
243 switch (addr) {
244#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
245 case CONFIG_GPCS_PHY1_ADDR:
ddc922ff 246 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
78d78236
VG
247 eoffset = 0x100;
248 break;
249#endif
250#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
251 case CONFIG_GPCS_PHY2_ADDR:
ddc922ff 252 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
78d78236
VG
253 eoffset = 0x300;
254 break;
255#endif
256#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
257 case CONFIG_GPCS_PHY3_ADDR:
ddc922ff 258 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
78d78236
VG
259 eoffset = 0x400;
260 break;
261#endif
262 default:
263 eoffset = 0;
264 break;
265 }
266 return eoffset;
267#endif
268
d6c61aab
SR
269 return 0;
270#endif
271}
272
c3307fa1 273static int emac_miiphy_wait(u32 emac_reg)
d6c61aab 274{
c3307fa1
SR
275 u32 sta_reg;
276 int i;
d6c61aab 277
c3307fa1 278 /* wait for completion */
affae2bf 279 i = 0;
c3307fa1 280 do {
ddc922ff 281 sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
c3307fa1 282 if (i++ > 5) {
ddc922ff 283 debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
c3307fa1 284 __LINE__, sta_reg);
affae2bf
WD
285 return -1;
286 }
c3307fa1
SR
287 udelay(10);
288 } while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
289
290 return 0;
291}
292
293static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
294{
295 u32 emac_reg;
296 u32 sta_reg;
297
78d78236 298 emac_reg = miiphy_getemac_offset(addr);
c3307fa1
SR
299
300 /* wait for completion */
301 if (emac_miiphy_wait(emac_reg) != 0)
302 return -1;
303
d6c61aab 304 sta_reg = reg; /* reg address */
c3307fa1 305
8ed44d91 306 /* set clock (50MHz) and read flags */
887e2ec9 307#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
dbbd1257 308 defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
c3307fa1 309 defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
dbbd1257 310 defined(CONFIG_405EX)
c348578b 311#if defined(CONFIG_IBM_EMAC4_V4) /* EMAC4 V4 changed bit setting */
c3307fa1 312 sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
6c5879f3 313#else
c3307fa1 314 sta_reg |= cmd;
6c5879f3 315#endif
d6c61aab 316#else
c3307fa1 317 sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
d6c61aab
SR
318#endif
319
c3307fa1 320 /* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
12f34241 321 sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
c3307fa1 322 sta_reg = sta_reg | ((u32)addr << 5); /* Phy address */
6c5879f3 323 sta_reg = sta_reg | EMAC_STACR_OC_MASK; /* new IBM emac v4 */
c3307fa1
SR
324 if (cmd == EMAC_STACR_WRITE)
325 memcpy(&sta_reg, &value, 2); /* put in data */
326
ddc922ff 327 out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
c3307fa1 328 debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
affae2bf 329
c3307fa1
SR
330 /* wait for completion */
331 if (emac_miiphy_wait(emac_reg) != 0)
332 return -1;
c348578b 333
c3307fa1 334 debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
c348578b 335 if ((sta_reg & EMAC_STACR_PHYE) != 0)
affae2bf 336 return -1;
affae2bf 337
affae2bf 338 return 0;
c3307fa1 339}
affae2bf 340
c3307fa1
SR
341int emac4xx_miiphy_read (char *devname, unsigned char addr, unsigned char reg,
342 unsigned short *value)
affae2bf 343{
c3307fa1 344 unsigned long sta_reg;
d6c61aab 345 unsigned long emac_reg;
affae2bf 346
78d78236 347 emac_reg = miiphy_getemac_offset(addr);
affae2bf 348
c3307fa1
SR
349 if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
350 return -1;
affae2bf 351
ddc922ff 352 sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
0b34dbbd 353 *value = sta_reg >> 16;
c348578b 354
affae2bf 355 return 0;
c3307fa1 356}
affae2bf 357
c3307fa1
SR
358/***********************************************************/
359/* write a phy reg and return the value with a rc */
360/***********************************************************/
361
362int emac4xx_miiphy_write (char *devname, unsigned char addr, unsigned char reg,
363 unsigned short value)
364{
365 return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
366}