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