]> git.sur5r.net Git - u-boot/blob - board/gdsys/common/phy.c
45d2b81f37c17aeec62771f13570a36f89a2f978
[u-boot] / board / gdsys / common / phy.c
1 /*
2  * (C) Copyright 2014
3  * Dirk Eibach,  Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9
10 #include <miiphy.h>
11
12 enum {
13         MIICMD_SET,
14         MIICMD_MODIFY,
15         MIICMD_VERIFY_VALUE,
16         MIICMD_WAIT_FOR_VALUE,
17 };
18
19 struct mii_setupcmd {
20         u8 token;
21         u8 reg;
22         u16 data;
23         u16 mask;
24         u32 timeout;
25 };
26
27 /*
28  * verify we are talking to a 88e1518
29  */
30 struct mii_setupcmd verify_88e1518[] = {
31         { MIICMD_SET, 22, 0x0000 },
32         { MIICMD_VERIFY_VALUE, 2, 0x0141, 0xffff },
33         { MIICMD_VERIFY_VALUE, 3, 0x0dd0, 0xfff0 },
34 };
35
36 /*
37  * workaround for erratum mentioned in 88E1518 release notes
38  */
39 struct mii_setupcmd fixup_88e1518[] = {
40         { MIICMD_SET, 22, 0x00ff },
41         { MIICMD_SET, 17, 0x214b },
42         { MIICMD_SET, 16, 0x2144 },
43         { MIICMD_SET, 17, 0x0c28 },
44         { MIICMD_SET, 16, 0x2146 },
45         { MIICMD_SET, 17, 0xb233 },
46         { MIICMD_SET, 16, 0x214d },
47         { MIICMD_SET, 17, 0xcc0c },
48         { MIICMD_SET, 16, 0x2159 },
49         { MIICMD_SET, 22, 0x00fb },
50         { MIICMD_SET,  7, 0xc00d },
51         { MIICMD_SET, 22, 0x0000 },
52 };
53
54 /*
55  * default initialization:
56  * - set RGMII receive timing to "receive clock transition when data stable"
57  * - set RGMII transmit timing to "transmit clock internally delayed"
58  * - set RGMII output impedance target to 78,8 Ohm
59  * - run output impedance calibration
60  * - set autonegotiation advertise to 1000FD only
61  */
62 struct mii_setupcmd default_88e1518[] = {
63         { MIICMD_SET, 22, 0x0002 },
64         { MIICMD_MODIFY, 21, 0x0030, 0x0030 },
65         { MIICMD_MODIFY, 25, 0x0000, 0x0003 },
66         { MIICMD_MODIFY, 24, 0x8000, 0x8000 },
67         { MIICMD_WAIT_FOR_VALUE, 24, 0x4000, 0x4000, 2000 },
68         { MIICMD_SET, 22, 0x0000 },
69         { MIICMD_MODIFY, 4, 0x0000, 0x01e0 },
70         { MIICMD_MODIFY, 9, 0x0200, 0x0300 },
71 };
72
73 /*
74  * turn off CLK125 for PHY daughterboard
75  */
76 struct mii_setupcmd ch1fix_88e1518[] = {
77         { MIICMD_SET, 22, 0x0002 },
78         { MIICMD_MODIFY, 16, 0x0006, 0x0006 },
79         { MIICMD_SET, 22, 0x0000 },
80 };
81
82 /*
83  * perform copper software reset
84  */
85 struct mii_setupcmd swreset_88e1518[] = {
86         { MIICMD_SET, 22, 0x0000 },
87         { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
88         { MIICMD_WAIT_FOR_VALUE, 0, 0x0000, 0x8000, 2000 },
89 };
90
91 /*
92  * special one for 88E1514:
93  * Force SGMII to Copper mode
94  */
95 struct mii_setupcmd mii_to_copper_88e1514[] = {
96         { MIICMD_SET, 22, 0x0012 },
97         { MIICMD_MODIFY, 20, 0x0001, 0x0007 },
98         { MIICMD_MODIFY, 20, 0x8000, 0x8000 },
99         { MIICMD_SET, 22, 0x0000 },
100 };
101
102 /*
103  * turn off SGMII auto-negotiation
104  */
105 struct mii_setupcmd sgmii_autoneg_off_88e1518[] = {
106         { MIICMD_SET, 22, 0x0001 },
107         { MIICMD_MODIFY, 0, 0x0000, 0x1000 },
108         { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
109         { MIICMD_SET, 22, 0x0000 },
110 };
111
112 /*
113  * invert LED2 polarity
114  */
115 struct mii_setupcmd invert_led2_88e1514[] = {
116         { MIICMD_SET, 22, 0x0003 },
117         { MIICMD_MODIFY, 17, 0x0030, 0x0010 },
118         { MIICMD_SET, 22, 0x0000 },
119 };
120
121 static int process_setupcmd(const char *bus, unsigned char addr,
122                             struct mii_setupcmd *setupcmd)
123 {
124         int res;
125         u8 reg = setupcmd->reg;
126         u16 data = setupcmd->data;
127         u16 mask = setupcmd->mask;
128         u32 timeout = setupcmd->timeout;
129         u16 orig_data;
130         unsigned long start;
131
132         debug("mii %s:%u reg %2u ", bus, addr, reg);
133
134         switch (setupcmd->token) {
135         case MIICMD_MODIFY:
136                 res = miiphy_read(bus, addr, reg, &orig_data);
137                 if (res)
138                         break;
139                 debug("is %04x. (value %04x mask %04x) ", orig_data, data,
140                       mask);
141                 data = (orig_data & ~mask) | (data & mask);
142                 /* fallthrough */
143         case MIICMD_SET:
144                 debug("=> %04x\n", data);
145                 res = miiphy_write(bus, addr, reg, data);
146                 break;
147         case MIICMD_VERIFY_VALUE:
148                 res = miiphy_read(bus, addr, reg, &orig_data);
149                 if (res)
150                         break;
151                 if ((orig_data & mask) != (data & mask))
152                         res = -1;
153                 debug("(value %04x mask %04x) == %04x? %s\n", data, mask,
154                       orig_data, res ? "FAIL" : "PASS");
155                 break;
156         case MIICMD_WAIT_FOR_VALUE:
157                 res = -1;
158                 start = get_timer(0);
159                 while ((res != 0) && (get_timer(start) < timeout)) {
160                         res = miiphy_read(bus, addr, reg, &orig_data);
161                         if (res)
162                                 continue;
163                         if ((orig_data & mask) != (data & mask))
164                                 res = -1;
165                 }
166                 debug("(value %04x mask %04x) == %04x? %s after %lu ms\n", data,
167                       mask, orig_data, res ? "FAIL" : "PASS",
168                       get_timer(start));
169                 break;
170         default:
171                 res = -1;
172                 break;
173         }
174
175         return res;
176 }
177
178 static int process_setup(const char *bus, unsigned char addr,
179                             struct mii_setupcmd *setupcmd, unsigned int count)
180 {
181         int res = 0;
182         unsigned int k;
183
184         for (k = 0; k < count; ++k) {
185                 res = process_setupcmd(bus, addr, &setupcmd[k]);
186                 if (res) {
187                         printf("mii cmd %u on bus %s addr %u failed, aborting setup\n",
188                                setupcmd[k].token, bus, addr);
189                         break;
190                 }
191         }
192
193         return res;
194 }
195
196 int setup_88e1518(const char *bus, unsigned char addr)
197 {
198         int res;
199
200         res = process_setup(bus, addr,
201                             verify_88e1518, ARRAY_SIZE(verify_88e1518));
202         if (res)
203                 return res;
204
205         res = process_setup(bus, addr,
206                             fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
207         if (res)
208                 return res;
209
210         res = process_setup(bus, addr,
211                             default_88e1518, ARRAY_SIZE(default_88e1518));
212         if (res)
213                 return res;
214
215         if (addr) {
216                 res = process_setup(bus, addr,
217                                     ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
218                 if (res)
219                         return res;
220         }
221
222         res = process_setup(bus, addr,
223                             swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
224         if (res)
225                 return res;
226
227         return 0;
228 }
229
230 int setup_88e1514(const char *bus, unsigned char addr)
231 {
232         int res;
233
234         res = process_setup(bus, addr,
235                             verify_88e1518, ARRAY_SIZE(verify_88e1518));
236         if (res)
237                 return res;
238
239         res = process_setup(bus, addr,
240                             fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
241         if (res)
242                 return res;
243
244         res = process_setup(bus, addr,
245                             mii_to_copper_88e1514,
246                             ARRAY_SIZE(mii_to_copper_88e1514));
247         if (res)
248                 return res;
249
250         res = process_setup(bus, addr,
251                             sgmii_autoneg_off_88e1518,
252                             ARRAY_SIZE(sgmii_autoneg_off_88e1518));
253         if (res)
254                 return res;
255
256         res = process_setup(bus, addr,
257                             invert_led2_88e1514,
258                             ARRAY_SIZE(invert_led2_88e1514));
259         if (res)
260                 return res;
261
262         res = process_setup(bus, addr,
263                             default_88e1518, ARRAY_SIZE(default_88e1518));
264         if (res)
265                 return res;
266
267         if (addr) {
268                 res = process_setup(bus, addr,
269                                     ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
270                 if (res)
271                         return res;
272         }
273
274         res = process_setup(bus, addr,
275                             swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
276         if (res)
277                 return res;
278
279         return 0;
280 }