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