]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - arch/ppc/cpu/ppc4xx/miiphy.c
1 /*-----------------------------------------------------------------------------+
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.
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.
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.
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.
20 | COPYRIGHT I B M CORPORATION 1995
21 | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
22 +-----------------------------------------------------------------------------*/
23 /*-----------------------------------------------------------------------------+
27 | Function: This module has utilities for accessing the MII PHY through
32 +-----------------------------------------------------------------------------*/
34 /* define DEBUG for debugging output (obviously ;-)) */
40 #include <asm/processor.h>
42 #include <ppc_asm.tmpl>
44 #include <ppc4xx_enet.h>
48 #if !defined(CONFIG_PHY_CLK_FREQ)
49 #define CONFIG_PHY_CLK_FREQ 0
52 /***********************************************************/
53 /* Dump out to the screen PHY regs */
54 /***********************************************************/
56 void miiphy_dump (char *devname
, unsigned char addr
)
61 for (i
= 0; i
< 0x1A; i
++) {
62 if (miiphy_read (devname
, addr
, i
, &data
)) {
63 printf ("read error for reg %lx\n", i
);
66 printf ("Phy reg %lx ==> %4x\n", i
, data
);
68 /* jump to the next set of regs */
75 /***********************************************************/
76 /* (Re)start autonegotiation */
77 /***********************************************************/
78 int phy_setup_aneg (char *devname
, unsigned char addr
)
82 #if defined(CONFIG_PHY_DYNAMIC_ANEG)
84 * Set up advertisement based on capablilities reported by the PHY.
85 * This should work for both copper and fiber.
88 #if defined(CONFIG_PHY_GIGE)
92 miiphy_read (devname
, addr
, PHY_BMSR
, &bmsr
);
94 #if defined(CONFIG_PHY_GIGE)
95 if (bmsr
& PHY_BMSR_EXT_STAT
)
96 miiphy_read (devname
, addr
, PHY_EXSR
, &exsr
);
98 if (exsr
& (PHY_EXSR_1000XF
| PHY_EXSR_1000XH
)) {
102 if (exsr
& PHY_EXSR_1000XF
)
103 anar
|= PHY_X_ANLPAR_FD
;
105 if (exsr
& PHY_EXSR_1000XH
)
106 anar
|= PHY_X_ANLPAR_HD
;
108 miiphy_write (devname
, addr
, PHY_ANAR
, anar
);
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
);
118 miiphy_read (devname
, addr
, PHY_1000BTCR
, &btcr
);
119 btcr
&= ~(0x00FF | PHY_1000BTCR_1000FD
| PHY_1000BTCR_1000HD
);
121 if (bmsr
& PHY_BMSR_100T4
)
122 anar
|= PHY_ANLPAR_T4
;
124 if (bmsr
& PHY_BMSR_100TXF
)
125 anar
|= PHY_ANLPAR_TXFD
;
127 if (bmsr
& PHY_BMSR_100TXH
)
128 anar
|= PHY_ANLPAR_TX
;
130 if (bmsr
& PHY_BMSR_10TF
)
131 anar
|= PHY_ANLPAR_10FD
;
133 if (bmsr
& PHY_BMSR_10TH
)
134 anar
|= PHY_ANLPAR_10
;
136 miiphy_write (devname
, addr
, PHY_ANAR
, anar
);
138 #if defined(CONFIG_PHY_GIGE)
139 if (exsr
& PHY_EXSR_1000TF
)
140 btcr
|= PHY_1000BTCR_1000FD
;
142 if (exsr
& PHY_EXSR_1000TH
)
143 btcr
|= PHY_1000BTCR_1000HD
;
145 miiphy_write (devname
, addr
, PHY_1000BTCR
, btcr
);
149 #else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
151 * Set up standard advertisement
155 miiphy_read (devname
, addr
, PHY_ANAR
, &adv
);
156 adv
|= (PHY_ANLPAR_ACK
| PHY_ANLPAR_TXFD
| PHY_ANLPAR_TX
|
157 PHY_ANLPAR_10FD
| PHY_ANLPAR_10
);
158 miiphy_write (devname
, addr
, PHY_ANAR
, adv
);
160 miiphy_read (devname
, addr
, PHY_1000BTCR
, &adv
);
162 miiphy_write (devname
, addr
, PHY_1000BTCR
, adv
);
164 #endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
166 /* Start/Restart aneg */
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
);
174 /***********************************************************/
175 /* read a phy reg and return the value with a rc */
176 /***********************************************************/
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.
183 * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
184 * return EMAC0 offset here
185 * vg: For 460EX/460GT if internal GPCS PHY address is specified
186 * return appropriate EMAC offset
188 unsigned int miiphy_getemac_offset(u8 addr
)
190 #if (defined(CONFIG_440) && \
191 !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
192 !defined(CONFIG_460EX) && !defined(CONFIG_460GT)) && \
193 defined(CONFIG_NET_MULTI)
195 unsigned long eoffset
;
197 /* Need to find out which mdi port we're using */
198 zmii
= in_be32((void *)ZMII0_FER
);
200 if (zmii
& (ZMII_FER_MDI
<< ZMII_FER_V (0)))
204 else if (zmii
& (ZMII_FER_MDI
<< ZMII_FER_V (1)))
208 else if (zmii
& (ZMII_FER_MDI
<< ZMII_FER_V (2)))
212 else if (zmii
& (ZMII_FER_MDI
<< ZMII_FER_V (3)))
217 /* None of the mdi ports are enabled! */
219 zmii
|= ZMII_FER_MDI
<< ZMII_FER_V (0);
220 out_be32((void *)ZMII0_FER
, zmii
);
222 /* need to soft reset port 0 */
223 zmii
= in_be32((void *)EMAC0_MR0
);
224 zmii
|= EMAC_MR0_SRST
;
225 out_be32((void *)EMAC0_MR0
, zmii
);
231 #if defined(CONFIG_NET_MULTI) && defined(CONFIG_405EX)
235 rgmii
= in_be32((void *)RGMII_FER
);
236 if (rgmii
& (1 << (19 - devnum
)))
240 #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
244 #if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
245 case CONFIG_GPCS_PHY1_ADDR
:
246 if (addr
== EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1
+ 0x100)))
250 #if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
251 case CONFIG_GPCS_PHY2_ADDR
:
252 if (addr
== EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1
+ 0x300)))
256 #if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
257 case CONFIG_GPCS_PHY3_ADDR
:
258 if (addr
== EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1
+ 0x400)))
273 static int emac_miiphy_wait(u32 emac_reg
)
278 /* wait for completion */
281 sta_reg
= in_be32((void *)EMAC0_STACR
+ emac_reg
);
283 debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__
,
288 } while ((sta_reg
& EMAC_STACR_OC
) == EMAC_STACR_OC_MASK
);
293 static int emac_miiphy_command(u8 addr
, u8 reg
, int cmd
, u16 value
)
298 emac_reg
= miiphy_getemac_offset(addr
);
300 /* wait for completion */
301 if (emac_miiphy_wait(emac_reg
) != 0)
304 sta_reg
= reg
; /* reg address */
306 /* set clock (50MHz) and read flags */
307 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
308 defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
309 defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
310 defined(CONFIG_405EX)
311 #if defined(CONFIG_IBM_EMAC4_V4) /* EMAC4 V4 changed bit setting */
312 sta_reg
= (sta_reg
& ~EMAC_STACR_OP_MASK
) | cmd
;
317 sta_reg
= (sta_reg
| cmd
) & ~EMAC_STACR_CLK_100MHZ
;
320 /* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
321 sta_reg
= sta_reg
| CONFIG_PHY_CLK_FREQ
;
322 sta_reg
= sta_reg
| ((u32
)addr
<< 5); /* Phy address */
323 sta_reg
= sta_reg
| EMAC_STACR_OC_MASK
; /* new IBM emac v4 */
324 if (cmd
== EMAC_STACR_WRITE
)
325 memcpy(&sta_reg
, &value
, 2); /* put in data */
327 out_be32((void *)EMAC0_STACR
+ emac_reg
, sta_reg
);
328 debug("%s [%d]: sta_reg=%08x\n", __func__
, __LINE__
, sta_reg
);
330 /* wait for completion */
331 if (emac_miiphy_wait(emac_reg
) != 0)
334 debug("%s [%d]: sta_reg=%08x\n", __func__
, __LINE__
, sta_reg
);
335 if ((sta_reg
& EMAC_STACR_PHYE
) != 0)
341 int emac4xx_miiphy_read (char *devname
, unsigned char addr
, unsigned char reg
,
342 unsigned short *value
)
344 unsigned long sta_reg
;
345 unsigned long emac_reg
;
347 emac_reg
= miiphy_getemac_offset(addr
);
349 if (emac_miiphy_command(addr
, reg
, EMAC_STACR_READ
, 0) != 0)
352 sta_reg
= in_be32((void *)EMAC0_STACR
+ emac_reg
);
353 *value
= sta_reg
>> 16;
358 /***********************************************************/
359 /* write a phy reg and return the value with a rc */
360 /***********************************************************/
362 int emac4xx_miiphy_write (char *devname
, unsigned char addr
, unsigned char reg
,
363 unsigned short value
)
365 return emac_miiphy_command(addr
, reg
, EMAC_STACR_WRITE
, value
);