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