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