]>
Commit | Line | Data |
---|---|---|
affae2bf WD |
1 | /*-----------------------------------------------------------------------------+ |
2 | | | |
d6c61aab SR |
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. | |
affae2bf | 9 | | |
d6c61aab SR |
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. | |
affae2bf | 13 | | |
d6c61aab SR |
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. | |
affae2bf | 17 | | |
d6c61aab SR |
18 | | COPYRIGHT I B M CORPORATION 1995 |
19 | | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M | |
affae2bf WD |
20 | +-----------------------------------------------------------------------------*/ |
21 | /*-----------------------------------------------------------------------------+ | |
22 | | | |
d6c61aab | 23 | | File Name: miiphy.c |
affae2bf | 24 | | |
d6c61aab | 25 | | Function: This module has utilities for accessing the MII PHY through |
affae2bf WD |
26 | | the EMAC3 macro. |
27 | | | |
d6c61aab | 28 | | Author: Mark Wisner |
affae2bf WD |
29 | | |
30 | | Change Activity- | |
31 | | | |
d6c61aab SR |
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 | | <[email protected]> | |
affae2bf WD |
42 | | |
43 | +-----------------------------------------------------------------------------*/ | |
44 | ||
45 | #include <common.h> | |
46 | #include <asm/processor.h> | |
47 | #include <ppc_asm.tmpl> | |
48 | #include <commproc.h> | |
d6c61aab | 49 | #include <ppc4xx_enet.h> |
affae2bf WD |
50 | #include <405_mal.h> |
51 | #include <miiphy.h> | |
52 | ||
affae2bf WD |
53 | |
54 | /***********************************************************/ | |
d6c61aab | 55 | /* Dump out to the screen PHY regs */ |
affae2bf WD |
56 | /***********************************************************/ |
57 | ||
58 | void miiphy_dump (unsigned char addr) | |
59 | { | |
60 | unsigned long i; | |
61 | unsigned short data; | |
62 | ||
63 | ||
64 | for (i = 0; i < 0x1A; i++) { | |
65 | if (miiphy_read (addr, i, &data)) { | |
66 | printf ("read error for reg %lx\n", i); | |
67 | return; | |
68 | } | |
69 | printf ("Phy reg %lx ==> %4x\n", i, data); | |
70 | ||
71 | /* jump to the next set of regs */ | |
72 | if (i == 0x07) | |
73 | i = 0x0f; | |
74 | ||
d6c61aab SR |
75 | } /* end for loop */ |
76 | } /* end dump */ | |
affae2bf WD |
77 | |
78 | ||
affae2bf | 79 | /***********************************************************/ |
d6c61aab | 80 | /* (Re)start autonegotiation */ |
affae2bf | 81 | /***********************************************************/ |
d6c61aab SR |
82 | int phy_setup_aneg (unsigned char addr) |
83 | { | |
84 | unsigned short ctl, adv; | |
85 | ||
86 | /* Setup standard advertise */ | |
87 | miiphy_read (addr, PHY_ANAR, &adv); | |
88 | adv |= (PHY_ANLPAR_ACK | PHY_ANLPAR_RF | PHY_ANLPAR_T4 | | |
89 | PHY_ANLPAR_TXFD | PHY_ANLPAR_TX | PHY_ANLPAR_10FD | | |
90 | PHY_ANLPAR_10); | |
91 | miiphy_write (addr, PHY_ANAR, adv); | |
affae2bf | 92 | |
d6c61aab SR |
93 | /* Start/Restart aneg */ |
94 | miiphy_read (addr, PHY_BMCR, &ctl); | |
95 | ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); | |
96 | miiphy_write (addr, PHY_BMCR, ctl); | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | ||
102 | /***********************************************************/ | |
103 | /* read a phy reg and return the value with a rc */ | |
104 | /***********************************************************/ | |
105 | unsigned int miiphy_getemac_offset (void) | |
affae2bf | 106 | { |
d6c61aab SR |
107 | #if defined(CONFIG_440) && defined(CONFIG_NET_MULTI) |
108 | unsigned long zmii; | |
109 | unsigned long eoffset; | |
110 | ||
111 | /* Need to find out which mdi port we're using */ | |
112 | zmii = in32 (ZMII_FER); | |
113 | ||
114 | if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0))) { | |
115 | /* using port 0 */ | |
116 | eoffset = 0; | |
117 | } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1))) { | |
118 | /* using port 1 */ | |
119 | eoffset = 0x100; | |
120 | } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2))) { | |
121 | /* using port 2 */ | |
122 | eoffset = 0x400; | |
123 | } else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3))) { | |
124 | /* using port 3 */ | |
125 | eoffset = 0x600; | |
126 | } else { | |
127 | /* None of the mdi ports are enabled! */ | |
128 | /* enable port 0 */ | |
129 | zmii |= ZMII_FER_MDI << ZMII_FER_V (0); | |
130 | out32 (ZMII_FER, zmii); | |
131 | eoffset = 0; | |
132 | /* need to soft reset port 0 */ | |
133 | zmii = in32 (EMAC_M0); | |
134 | zmii |= EMAC_M0_SRST; | |
135 | out32 (EMAC_M0, zmii); | |
136 | } | |
137 | ||
138 | return (eoffset); | |
139 | #else | |
140 | return 0; | |
141 | #endif | |
142 | } | |
143 | ||
144 | ||
145 | int miiphy_read (unsigned char addr, unsigned char reg, unsigned short *value) | |
146 | { | |
147 | unsigned long sta_reg; /* STA scratch area */ | |
affae2bf | 148 | unsigned long i; |
d6c61aab SR |
149 | unsigned long emac_reg; |
150 | ||
affae2bf | 151 | |
d6c61aab | 152 | emac_reg = miiphy_getemac_offset (); |
affae2bf WD |
153 | /* see if it is ready for 1000 nsec */ |
154 | i = 0; | |
155 | ||
156 | /* see if it is ready for sec */ | |
d6c61aab | 157 | while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) { |
affae2bf WD |
158 | udelay (7); |
159 | if (i > 5) { | |
d6c61aab | 160 | #if 0 |
affae2bf | 161 | printf ("read err 1\n"); |
38a95195 | 162 | #endif |
affae2bf WD |
163 | return -1; |
164 | } | |
165 | i++; | |
166 | } | |
d6c61aab | 167 | sta_reg = reg; /* reg address */ |
affae2bf | 168 | /* set clock (50Mhz) and read flags */ |
d6c61aab SR |
169 | #if defined(CONFIG_440GX) |
170 | sta_reg |= EMAC_STACR_READ; | |
171 | #else | |
affae2bf | 172 | sta_reg = (sta_reg | EMAC_STACR_READ) & ~EMAC_STACR_CLK_100MHZ; |
d6c61aab SR |
173 | #endif |
174 | ||
175 | #if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX) | |
12f34241 | 176 | sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ; |
093ae273 | 177 | #endif |
affae2bf WD |
178 | sta_reg = sta_reg | (addr << 5); /* Phy address */ |
179 | ||
d6c61aab SR |
180 | out32 (EMAC_STACR + emac_reg, sta_reg); |
181 | #if 0 /* test-only */ | |
affae2bf WD |
182 | printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */ |
183 | #endif | |
184 | ||
d6c61aab | 185 | sta_reg = in32 (EMAC_STACR + emac_reg); |
affae2bf WD |
186 | i = 0; |
187 | while ((sta_reg & EMAC_STACR_OC) == 0) { | |
188 | udelay (7); | |
189 | if (i > 5) { | |
affae2bf WD |
190 | return -1; |
191 | } | |
192 | i++; | |
d6c61aab | 193 | sta_reg = in32 (EMAC_STACR + emac_reg); |
affae2bf WD |
194 | } |
195 | if ((sta_reg & EMAC_STACR_PHYE) != 0) { | |
affae2bf WD |
196 | return -1; |
197 | } | |
198 | ||
199 | *value = *(short *) (&sta_reg); | |
200 | return 0; | |
201 | ||
202 | ||
d6c61aab | 203 | } /* phy_read */ |
affae2bf WD |
204 | |
205 | ||
206 | /***********************************************************/ | |
d6c61aab | 207 | /* write a phy reg and return the value with a rc */ |
affae2bf WD |
208 | /***********************************************************/ |
209 | ||
d6c61aab | 210 | int miiphy_write (unsigned char addr, unsigned char reg, unsigned short value) |
affae2bf | 211 | { |
d6c61aab | 212 | unsigned long sta_reg; /* STA scratch area */ |
affae2bf | 213 | unsigned long i; |
d6c61aab | 214 | unsigned long emac_reg; |
affae2bf | 215 | |
d6c61aab | 216 | emac_reg = miiphy_getemac_offset (); |
affae2bf WD |
217 | /* see if it is ready for 1000 nsec */ |
218 | i = 0; | |
219 | ||
d6c61aab | 220 | while ((in32 (EMAC_STACR + emac_reg) & EMAC_STACR_OC) == 0) { |
affae2bf WD |
221 | if (i > 5) |
222 | return -1; | |
223 | udelay (7); | |
224 | i++; | |
225 | } | |
226 | sta_reg = 0; | |
d6c61aab | 227 | sta_reg = reg; /* reg address */ |
affae2bf | 228 | /* set clock (50Mhz) and read flags */ |
d6c61aab SR |
229 | #if defined(CONFIG_440GX) |
230 | sta_reg |= EMAC_STACR_WRITE; | |
231 | #else | |
affae2bf | 232 | sta_reg = (sta_reg | EMAC_STACR_WRITE) & ~EMAC_STACR_CLK_100MHZ; |
d6c61aab SR |
233 | #endif |
234 | ||
235 | #if defined(CONFIG_PHY_CLK_FREQ) && !defined(CONFIG_440GX) | |
236 | sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ; /* Set clock frequency (PLB freq. dependend) */ | |
093ae273 | 237 | #endif |
affae2bf WD |
238 | sta_reg = sta_reg | ((unsigned long) addr << 5); /* Phy address */ |
239 | memcpy (&sta_reg, &value, 2); /* put in data */ | |
240 | ||
d6c61aab | 241 | out32 (EMAC_STACR + emac_reg, sta_reg); |
affae2bf WD |
242 | |
243 | /* wait for completion */ | |
244 | i = 0; | |
d6c61aab | 245 | sta_reg = in32 (EMAC_STACR + emac_reg); |
affae2bf WD |
246 | while ((sta_reg & EMAC_STACR_OC) == 0) { |
247 | udelay (7); | |
248 | if (i > 5) | |
249 | return -1; | |
250 | i++; | |
d6c61aab | 251 | sta_reg = in32 (EMAC_STACR + emac_reg); |
affae2bf WD |
252 | } |
253 | ||
254 | if ((sta_reg & EMAC_STACR_PHYE) != 0) | |
255 | return -1; | |
256 | return 0; | |
257 | ||
d6c61aab | 258 | } /* phy_write */ |