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