]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/cpu/ppc4xx/miiphy.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / arch / powerpc / cpu / ppc4xx / miiphy.c
1 /*
2  * SPDX-License-Identifier:     GPL-2.0 ibm-pibs
3  */
4 /*-----------------------------------------------------------------------------+
5   |
6   |  File Name:  miiphy.c
7   |
8   |  Function:   This module has utilities for accessing the MII PHY through
9   |            the EMAC3 macro.
10   |
11   |  Author:     Mark Wisner
12   |
13   +-----------------------------------------------------------------------------*/
14
15 /* define DEBUG for debugging output (obviously ;-)) */
16 #if 0
17 #define DEBUG
18 #endif
19
20 #include <common.h>
21 #include <asm/processor.h>
22 #include <asm/io.h>
23 #include <ppc_asm.tmpl>
24 #include <commproc.h>
25 #include <asm/ppc4xx-emac.h>
26 #include <asm/ppc4xx-mal.h>
27 #include <miiphy.h>
28
29 #if !defined(CONFIG_PHY_CLK_FREQ)
30 #define CONFIG_PHY_CLK_FREQ     0
31 #endif
32
33 /***********************************************************/
34 /* Dump out to the screen PHY regs                         */
35 /***********************************************************/
36
37 void miiphy_dump (char *devname, unsigned char addr)
38 {
39         unsigned long i;
40         unsigned short data;
41
42         for (i = 0; i < 0x1A; i++) {
43                 if (miiphy_read (devname, addr, i, &data)) {
44                         printf ("read error for reg %lx\n", i);
45                         return;
46                 }
47                 printf ("Phy reg %lx ==> %4x\n", i, data);
48
49                 /* jump to the next set of regs */
50                 if (i == 0x07)
51                         i = 0x0f;
52
53         }                       /* end for loop */
54 }                               /* end dump */
55
56 /***********************************************************/
57 /* (Re)start autonegotiation                               */
58 /***********************************************************/
59 int phy_setup_aneg (char *devname, unsigned char addr)
60 {
61         u16 bmcr;
62
63 #if defined(CONFIG_PHY_DYNAMIC_ANEG)
64         /*
65          * Set up advertisement based on capablilities reported by the PHY.
66          * This should work for both copper and fiber.
67          */
68         u16 bmsr;
69 #if defined(CONFIG_PHY_GIGE)
70         u16 exsr = 0x0000;
71 #endif
72
73         miiphy_read (devname, addr, MII_BMSR, &bmsr);
74
75 #if defined(CONFIG_PHY_GIGE)
76         if (bmsr & BMSR_ESTATEN)
77                 miiphy_read (devname, addr, MII_ESTATUS, &exsr);
78
79         if (exsr & (ESTATUS_1000XF | ESTATUS_1000XH)) {
80                 /* 1000BASE-X */
81                 u16 anar = 0x0000;
82
83                 if (exsr & ESTATUS_1000XF)
84                         anar |= ADVERTISE_1000XFULL;
85
86                 if (exsr & ESTATUS_1000XH)
87                         anar |= ADVERTISE_1000XHALF;
88
89                 miiphy_write (devname, addr, MII_ADVERTISE, anar);
90         } else
91 #endif
92         {
93                 u16 anar, btcr;
94
95                 miiphy_read (devname, addr, MII_ADVERTISE, &anar);
96                 anar &= ~(0x5000 | LPA_100BASE4 | LPA_100FULL |
97                           LPA_100HALF | LPA_10FULL | LPA_10HALF);
98
99                 miiphy_read (devname, addr, MII_CTRL1000, &btcr);
100                 btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
101
102                 if (bmsr & BMSR_100BASE4)
103                         anar |= LPA_100BASE4;
104
105                 if (bmsr & BMSR_100FULL)
106                         anar |= LPA_100FULL;
107
108                 if (bmsr & BMSR_100HALF)
109                         anar |= LPA_100HALF;
110
111                 if (bmsr & BMSR_10FULL)
112                         anar |= LPA_10FULL;
113
114                 if (bmsr & BMSR_10HALF)
115                         anar |= LPA_10HALF;
116
117                 miiphy_write (devname, addr, MII_ADVERTISE, anar);
118
119 #if defined(CONFIG_PHY_GIGE)
120                 if (exsr & ESTATUS_1000_TFULL)
121                         btcr |= PHY_1000BTCR_1000FD;
122
123                 if (exsr & ESTATUS_1000_THALF)
124                         btcr |= PHY_1000BTCR_1000HD;
125
126                 miiphy_write (devname, addr, MII_CTRL1000, btcr);
127 #endif
128         }
129
130 #else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
131         /*
132          * Set up standard advertisement
133          */
134         u16 adv;
135
136         miiphy_read (devname, addr, MII_ADVERTISE, &adv);
137         adv |= (LPA_LPACK  | LPA_100FULL | LPA_100HALF |
138                 LPA_10FULL | LPA_10HALF);
139         miiphy_write (devname, addr, MII_ADVERTISE, adv);
140
141         miiphy_read (devname, addr, MII_CTRL1000, &adv);
142         adv |= (0x0300);
143         miiphy_write (devname, addr, MII_CTRL1000, adv);
144
145 #endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
146
147         /* Start/Restart aneg */
148         miiphy_read (devname, addr, MII_BMCR, &bmcr);
149         bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
150         miiphy_write (devname, addr, MII_BMCR, bmcr);
151
152         return 0;
153 }
154
155 /***********************************************************/
156 /* read a phy reg and return the value with a rc           */
157 /***********************************************************/
158 /* AMCC_TODO:
159  * Find out of the choice for the emac for MDIO is from the bridges,
160  * i.e. ZMII or RGMII as approporiate.  If the bridges are not used
161  * to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
162  * used?  If so, then this routine below does not apply to the 460EX/GT.
163  *
164  * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
165  * return EMAC0 offset here
166  * vg: For 460EX/460GT if internal GPCS PHY address is specified
167  * return appropriate EMAC offset
168  */
169 unsigned int miiphy_getemac_offset(u8 addr)
170 {
171 #if defined(CONFIG_440) && \
172     !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
173     !defined(CONFIG_460EX) && !defined(CONFIG_460GT)
174         unsigned long zmii;
175         unsigned long eoffset;
176
177         /* Need to find out which mdi port we're using */
178         zmii = in_be32((void *)ZMII0_FER);
179
180         if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
181                 /* using port 0 */
182                 eoffset = 0;
183
184         else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
185                 /* using port 1 */
186                 eoffset = 0x100;
187
188         else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
189                 /* using port 2 */
190                 eoffset = 0x400;
191
192         else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
193                 /* using port 3 */
194                 eoffset = 0x600;
195
196         else {
197                 /* None of the mdi ports are enabled! */
198                 /* enable port 0 */
199                 zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
200                 out_be32((void *)ZMII0_FER, zmii);
201                 eoffset = 0;
202                 /* need to soft reset port 0 */
203                 zmii = in_be32((void *)EMAC0_MR0);
204                 zmii |= EMAC_MR0_SRST;
205                 out_be32((void *)EMAC0_MR0, zmii);
206         }
207
208         return (eoffset);
209 #else
210
211 #if defined(CONFIG_405EX)
212         unsigned long rgmii;
213         int devnum = 1;
214
215         rgmii = in_be32((void *)RGMII_FER);
216         if (rgmii & (1 << (19 - devnum)))
217                 return 0x100;
218 #endif
219
220 #if defined(CONFIG_460EX) || defined(CONFIG_460GT)
221         u32 eoffset = 0;
222
223         switch (addr) {
224 #if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
225         case CONFIG_GPCS_PHY1_ADDR:
226                 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
227                         eoffset = 0x100;
228                 break;
229 #endif
230 #if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
231         case CONFIG_GPCS_PHY2_ADDR:
232                 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
233                         eoffset = 0x300;
234                 break;
235 #endif
236 #if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
237         case CONFIG_GPCS_PHY3_ADDR:
238                 if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
239                         eoffset = 0x400;
240                 break;
241 #endif
242         default:
243                 eoffset = 0;
244                 break;
245         }
246         return eoffset;
247 #endif
248
249         return 0;
250 #endif
251 }
252
253 static int emac_miiphy_wait(u32 emac_reg)
254 {
255         u32 sta_reg;
256         int i;
257
258         /* wait for completion */
259         i = 0;
260         do {
261                 sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
262                 if (i++ > 5) {
263                         debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
264                               __LINE__, sta_reg);
265                         return -1;
266                 }
267                 udelay(10);
268         } while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
269
270         return 0;
271 }
272
273 static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
274 {
275         u32 emac_reg;
276         u32 sta_reg;
277
278         emac_reg = miiphy_getemac_offset(addr);
279
280         /* wait for completion */
281         if (emac_miiphy_wait(emac_reg) != 0)
282                 return -1;
283
284         sta_reg = reg;          /* reg address */
285
286         /* set clock (50MHz) and read flags */
287 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
288     defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
289     defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
290     defined(CONFIG_405EX)
291 #if defined(CONFIG_IBM_EMAC4_V4)        /* EMAC4 V4 changed bit setting */
292         sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
293 #else
294         sta_reg |= cmd;
295 #endif
296 #else
297         sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
298 #endif
299
300         /* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
301         sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
302         sta_reg = sta_reg | ((u32)addr << 5);   /* Phy address */
303         sta_reg = sta_reg | EMAC_STACR_OC_MASK; /* new IBM emac v4 */
304         if (cmd == EMAC_STACR_WRITE)
305                 memcpy(&sta_reg, &value, 2);    /* put in data */
306
307         out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
308         debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
309
310         /* wait for completion */
311         if (emac_miiphy_wait(emac_reg) != 0)
312                 return -1;
313
314         debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
315         if ((sta_reg & EMAC_STACR_PHYE) != 0)
316                 return -1;
317
318         return 0;
319 }
320
321 int emac4xx_miiphy_read (const char *devname, unsigned char addr, unsigned char reg,
322                          unsigned short *value)
323 {
324         unsigned long sta_reg;
325         unsigned long emac_reg;
326
327         emac_reg = miiphy_getemac_offset(addr);
328
329         if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
330                 return -1;
331
332         sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
333         *value = sta_reg >> 16;
334
335         return 0;
336 }
337
338 /***********************************************************/
339 /* write a phy reg and return the value with a rc           */
340 /***********************************************************/
341
342 int emac4xx_miiphy_write (const char *devname, unsigned char addr, unsigned char reg,
343                           unsigned short value)
344 {
345         return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
346 }