blob: 2ef3b3ab27045bd4f3e439fad508f6f056f4c297 [file] [log] [blame]
Dirk Eibachfb605942017-02-22 16:07:23 +01001#include <common.h>
2#include <dm.h>
3#include <miiphy.h>
4#include <asm-generic/gpio.h>
Simon Glassdbd79542020-05-10 11:40:11 -06005#include <linux/delay.h>
Dirk Eibachfb605942017-02-22 16:07:23 +01006
7#include "ihs_phys.h"
8#include "dt_helpers.h"
9
10enum {
11 PORTTYPE_MAIN_CAT,
12 PORTTYPE_TOP_CAT,
13 PORTTYPE_16C_16F,
14 PORTTYPE_UNKNOWN
15};
16
17static struct porttype {
18 bool phy_invert_in_pol;
19 bool phy_invert_out_pol;
20} porttypes[] = {
21 { true, false },
22 { false, true },
23 { false, false },
24};
25
26static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn)
27{
28 u16 reg;
29
30 phy_config(phydev);
31
32 /* enable QSGMII autonegotiation with flow control */
33 phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004);
34 reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
35 reg |= (3 << 6);
36 phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
37
38 /*
39 * invert QSGMII Q_INP/N and Q_OUTP/N if required
40 * and perform global reset
41 */
42 reg = phy_read(phydev, MDIO_DEVAD_NONE, 26);
43 if (qinpn)
44 reg |= (1 << 13);
45 if (qoutpn)
46 reg |= (1 << 12);
47 reg |= (1 << 15);
48 phy_write(phydev, MDIO_DEVAD_NONE, 26, reg);
49
50 /* advertise 1000BASE-T full-duplex only */
51 phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
52 reg = phy_read(phydev, MDIO_DEVAD_NONE, 4);
53 reg &= ~0x1e0;
54 phy_write(phydev, MDIO_DEVAD_NONE, 4, reg);
55 reg = phy_read(phydev, MDIO_DEVAD_NONE, 9);
56 reg = (reg & ~0x300) | 0x200;
57 phy_write(phydev, MDIO_DEVAD_NONE, 9, reg);
58
59 /* copper power up */
60 reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
61 reg &= ~0x0004;
62 phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
63}
64
65uint calculate_octo_phy_mask(void)
66{
67 uint k;
68 uint octo_phy_mask = 0;
69 struct gpio_desc gpio = {};
70 char gpio_name[64];
71 static const char * const dev_name[] = {"pca9698@23", "pca9698@21",
72 "pca9698@24", "pca9698@25",
73 "pca9698@26"};
74
75 /* mark all octo phys that should be present */
76 for (k = 0; k < 5; ++k) {
77 snprintf(gpio_name, 64, "cat-gpio-%u", k);
78
79 if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name))
80 continue;
81
82 /* check CAT flag */
83 if (dm_gpio_get_value(&gpio))
84 octo_phy_mask |= (1 << (k * 2));
85 else
86 /* If CAT == 0, there's no second octo phy -> skip */
87 continue;
88
89 snprintf(gpio_name, 64, "second-octo-gpio-%u", k);
90
91 if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) {
92 /* default: second octo phy is present */
93 octo_phy_mask |= (1 << (k * 2 + 1));
94 continue;
95 }
96
97 if (dm_gpio_get_value(&gpio) == 0)
98 octo_phy_mask |= (1 << (k * 2 + 1));
99 }
100
101 return octo_phy_mask;
102}
103
104int register_miiphy_bus(uint k, struct mii_dev **bus)
105{
106 int retval;
107 struct mii_dev *mdiodev = mdio_alloc();
108 char *name = bb_miiphy_buses[k].name;
109
110 if (!mdiodev)
111 return -ENOMEM;
112 strncpy(mdiodev->name,
113 name,
114 MDIO_NAME_LEN);
115 mdiodev->read = bb_miiphy_read;
116 mdiodev->write = bb_miiphy_write;
117
118 retval = mdio_register(mdiodev);
119 if (retval < 0)
120 return retval;
121 *bus = miiphy_get_dev_by_name(name);
122
123 return 0;
124}
125
126struct porttype *get_porttype(uint octo_phy_mask, uint k)
127{
128 uint octo_index = k * 4;
129
130 if (!k) {
131 if (octo_phy_mask & 0x01)
132 return &porttypes[PORTTYPE_MAIN_CAT];
133 else if (!(octo_phy_mask & 0x03))
134 return &porttypes[PORTTYPE_16C_16F];
135 } else {
136 if (octo_phy_mask & (1 << octo_index))
137 return &porttypes[PORTTYPE_TOP_CAT];
138 }
139
140 return NULL;
141}
142
143int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
144 uint bus_idx, uint m, uint phy_idx)
145{
146 struct phy_device *phydev = phy_find_by_mask(
147 bus, 1 << (m * 8 + phy_idx),
148 PHY_INTERFACE_MODE_MII);
149
150 printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
151
152 if (!phydev)
153 puts("!");
154 else
155 ihs_phy_config(phydev, porttype->phy_invert_in_pol,
156 porttype->phy_invert_out_pol);
157
158 return 0;
159}
160
161int init_octo_phys(uint octo_phy_mask)
162{
163 uint bus_idx;
164
165 /* there are up to four octo-phys on each mdio bus */
166 for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) {
167 uint m;
168 uint octo_index = bus_idx * 4;
169 struct mii_dev *bus = NULL;
170 struct porttype *porttype = NULL;
171 int ret;
172
173 porttype = get_porttype(octo_phy_mask, bus_idx);
174
175 if (!porttype)
176 continue;
177
178 for (m = 0; m < 4; ++m) {
179 uint phy_idx;
180
181 /**
182 * Register a bus device if there is at least one phy
183 * on the current bus
184 */
185 if (!m && octo_phy_mask & (0xf << octo_index)) {
186 ret = register_miiphy_bus(bus_idx, &bus);
187 if (ret)
188 return ret;
189 }
190
191 if (!(octo_phy_mask & BIT(octo_index + m)))
192 continue;
193
194 for (phy_idx = 0; phy_idx < 8; ++phy_idx)
195 init_single_phy(porttype, bus, bus_idx, m,
196 phy_idx);
197 }
198 }
199
200 return 0;
201}
202
203/*
204 * MII GPIO bitbang implementation
205 * MDC MDIO bus
206 * 13 14 PHY1-4
207 * 25 45 PHY5-8
208 * 46 24 PHY9-10
209 */
210
211struct gpio_mii {
212 int index;
213 struct gpio_desc mdc_gpio;
214 struct gpio_desc mdio_gpio;
215 int mdc_num;
216 int mdio_num;
217 int mdio_value;
218} gpio_mii_set[] = {
219 { 0, {}, {}, 13, 14, 1 },
220 { 1, {}, {}, 25, 45, 1 },
221 { 2, {}, {}, 46, 24, 1 },
222};
223
224static int mii_mdio_init(struct bb_miiphy_bus *bus)
225{
226 struct gpio_mii *gpio_mii = bus->priv;
227 char name[32] = {};
228 struct udevice *gpio_dev1 = NULL;
229 struct udevice *gpio_dev2 = NULL;
230
231 if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
232 uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
233 printf("Could not get GPIO device.\n");
234 return 1;
235 }
236
237 if (gpio_mii->mdc_num > 31) {
238 gpio_mii->mdc_gpio.dev = gpio_dev2;
239 gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
240 } else {
241 gpio_mii->mdc_gpio.dev = gpio_dev1;
242 gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
243 }
244 gpio_mii->mdc_gpio.flags = 0;
245 snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
246 dm_gpio_request(&gpio_mii->mdc_gpio, name);
247
248 if (gpio_mii->mdio_num > 31) {
249 gpio_mii->mdio_gpio.dev = gpio_dev2;
250 gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
251 } else {
252 gpio_mii->mdio_gpio.dev = gpio_dev1;
253 gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
254 }
255 gpio_mii->mdio_gpio.flags = 0;
256 snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
257 dm_gpio_request(&gpio_mii->mdio_gpio, name);
258
259 dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
260 dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
261
262 return 0;
263}
264
265static int mii_mdio_active(struct bb_miiphy_bus *bus)
266{
267 struct gpio_mii *gpio_mii = bus->priv;
268
269 dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
270
271 return 0;
272}
273
274static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
275{
276 struct gpio_mii *gpio_mii = bus->priv;
277
278 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
279
280 return 0;
281}
282
283static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
284{
285 struct gpio_mii *gpio_mii = bus->priv;
286
287 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
288 dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
289 gpio_mii->mdio_value = v;
290
291 return 0;
292}
293
294static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
295{
296 struct gpio_mii *gpio_mii = bus->priv;
297
298 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
299 *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
300
301 return 0;
302}
303
304static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
305{
306 struct gpio_mii *gpio_mii = bus->priv;
307
308 dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
309
310 return 0;
311}
312
313static int mii_delay(struct bb_miiphy_bus *bus)
314{
315 udelay(1);
316
317 return 0;
318}
319
320struct bb_miiphy_bus bb_miiphy_buses[] = {
321 {
322 .name = "ihs0",
323 .init = mii_mdio_init,
324 .mdio_active = mii_mdio_active,
325 .mdio_tristate = mii_mdio_tristate,
326 .set_mdio = mii_set_mdio,
327 .get_mdio = mii_get_mdio,
328 .set_mdc = mii_set_mdc,
329 .delay = mii_delay,
330 .priv = &gpio_mii_set[0],
331 },
332 {
333 .name = "ihs1",
334 .init = mii_mdio_init,
335 .mdio_active = mii_mdio_active,
336 .mdio_tristate = mii_mdio_tristate,
337 .set_mdio = mii_set_mdio,
338 .get_mdio = mii_get_mdio,
339 .set_mdc = mii_set_mdc,
340 .delay = mii_delay,
341 .priv = &gpio_mii_set[1],
342 },
343 {
344 .name = "ihs2",
345 .init = mii_mdio_init,
346 .mdio_active = mii_mdio_active,
347 .mdio_tristate = mii_mdio_tristate,
348 .set_mdio = mii_set_mdio,
349 .get_mdio = mii_get_mdio,
350 .set_mdc = mii_set_mdc,
351 .delay = mii_delay,
352 .priv = &gpio_mii_set[2],
353 },
354};
355
356int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);