blob: 0c68087912af50eaf7b44cb9c780dbb143ebd765 [file] [log] [blame]
Dirk Eibachfb605942017-02-22 16:07:23 +01001#include <dm.h>
2#include <miiphy.h>
3#include <asm-generic/gpio.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -06004#include <linux/bitops.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
Marek BehĂșn3927efb2022-04-07 00:33:08 +020030 phydev->interface = PHY_INTERFACE_MODE_MII;
Dirk Eibachfb605942017-02-22 16:07:23 +010031 phy_config(phydev);
32
33 /* enable QSGMII autonegotiation with flow control */
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 * invert QSGMII Q_INP/N and Q_OUTP/N if required
41 * and perform global reset
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 /* advertise 1000BASE-T full-duplex only */
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 /* copper power up */
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 /* mark all octo phys that should be present */
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 /* check CAT flag */
84 if (dm_gpio_get_value(&gpio))
85 octo_phy_mask |= (1 << (k * 2));
86 else
87 /* If CAT == 0, there's no second octo phy -> skip */
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 /* default: second octo phy is present */
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
Dirk Eibachfb605942017-02-22 16:07:23 +0100105/*
106 * MII GPIO bitbang implementation
107 * MDC MDIO bus
108 * 13 14 PHY1-4
109 * 25 45 PHY5-8
110 * 46 24 PHY9-10
111 */
112
113struct gpio_mii {
114 int index;
115 struct gpio_desc mdc_gpio;
116 struct gpio_desc mdio_gpio;
117 int mdc_num;
118 int mdio_num;
119 int mdio_value;
120} gpio_mii_set[] = {
121 { 0, {}, {}, 13, 14, 1 },
122 { 1, {}, {}, 25, 45, 1 },
123 { 2, {}, {}, 46, 24, 1 },
124};
125
126static int mii_mdio_init(struct bb_miiphy_bus *bus)
127{
128 struct gpio_mii *gpio_mii = bus->priv;
129 char name[32] = {};
130 struct udevice *gpio_dev1 = NULL;
131 struct udevice *gpio_dev2 = NULL;
132
133 if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
134 uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
135 printf("Could not get GPIO device.\n");
136 return 1;
137 }
138
139 if (gpio_mii->mdc_num > 31) {
140 gpio_mii->mdc_gpio.dev = gpio_dev2;
141 gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
142 } else {
143 gpio_mii->mdc_gpio.dev = gpio_dev1;
144 gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
145 }
146 gpio_mii->mdc_gpio.flags = 0;
147 snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
148 dm_gpio_request(&gpio_mii->mdc_gpio, name);
149
150 if (gpio_mii->mdio_num > 31) {
151 gpio_mii->mdio_gpio.dev = gpio_dev2;
152 gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
153 } else {
154 gpio_mii->mdio_gpio.dev = gpio_dev1;
155 gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
156 }
157 gpio_mii->mdio_gpio.flags = 0;
158 snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
159 dm_gpio_request(&gpio_mii->mdio_gpio, name);
160
161 dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
162 dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
163
164 return 0;
165}
166
167static int mii_mdio_active(struct bb_miiphy_bus *bus)
168{
169 struct gpio_mii *gpio_mii = bus->priv;
170
171 dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
172
173 return 0;
174}
175
176static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
177{
178 struct gpio_mii *gpio_mii = bus->priv;
179
180 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
181
182 return 0;
183}
184
185static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
186{
187 struct gpio_mii *gpio_mii = bus->priv;
188
189 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
190 dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
191 gpio_mii->mdio_value = v;
192
193 return 0;
194}
195
196static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
197{
198 struct gpio_mii *gpio_mii = bus->priv;
199
200 dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
201 *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
202
203 return 0;
204}
205
206static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
207{
208 struct gpio_mii *gpio_mii = bus->priv;
209
210 dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
211
212 return 0;
213}
214
215static int mii_delay(struct bb_miiphy_bus *bus)
216{
217 udelay(1);
218
219 return 0;
220}
221
Marek Vasut694f04d2025-02-22 21:33:16 +0100222int register_miiphy_bus(uint k, struct mii_dev **bus)
223{
Marek Vasut5b3f8772025-02-22 21:33:24 +0100224 struct bb_miiphy_bus *bb_miiphy = bb_miiphy_alloc();
225 struct mii_dev *mdiodev;
Marek Vasut5b3f8772025-02-22 21:33:24 +0100226 int retval;
Marek Vasut694f04d2025-02-22 21:33:16 +0100227
Marek Vasut5b3f8772025-02-22 21:33:24 +0100228 if (!bb_miiphy)
Marek Vasut694f04d2025-02-22 21:33:16 +0100229 return -ENOMEM;
Marek Vasut5b3f8772025-02-22 21:33:24 +0100230
231 mdiodev = &bb_miiphy->mii;
Marek Vasutd1dddbf2025-02-22 21:33:29 +0100232 snprintf(mdiodev->name, MDIO_NAME_LEN, "ihs%d", k);
Marek Vasut694f04d2025-02-22 21:33:16 +0100233 mdiodev->read = bb_miiphy_read;
234 mdiodev->write = bb_miiphy_write;
235
Marek Vasutd1dddbf2025-02-22 21:33:29 +0100236 /* Copy the bus accessors and private data */
Marek Vasut5b3f8772025-02-22 21:33:24 +0100237 bb_miiphy->mdio_active = mii_mdio_active;
238 bb_miiphy->mdio_tristate = mii_mdio_tristate;
239 bb_miiphy->set_mdio = mii_set_mdio;
240 bb_miiphy->get_mdio = mii_get_mdio;
241 bb_miiphy->set_mdc = mii_set_mdc;
242 bb_miiphy->delay = mii_delay;
Marek Vasut5b3f8772025-02-22 21:33:24 +0100243 bb_miiphy->priv = &gpio_mii_set[k];
244
Marek Vasut694f04d2025-02-22 21:33:16 +0100245 retval = mdio_register(mdiodev);
246 if (retval < 0)
247 return retval;
Marek Vasut25b2d5c2025-02-22 21:33:30 +0100248 *bus = &bb_miiphy->mii;
Marek Vasut694f04d2025-02-22 21:33:16 +0100249
Marek Vasut5b3f8772025-02-22 21:33:24 +0100250 return mii_mdio_init(bb_miiphy);
Marek Vasut694f04d2025-02-22 21:33:16 +0100251}
252
253struct porttype *get_porttype(uint octo_phy_mask, uint k)
254{
255 uint octo_index = k * 4;
256
257 if (!k) {
258 if (octo_phy_mask & 0x01)
259 return &porttypes[PORTTYPE_MAIN_CAT];
260 else if (!(octo_phy_mask & 0x03))
261 return &porttypes[PORTTYPE_16C_16F];
262 } else {
263 if (octo_phy_mask & (1 << octo_index))
264 return &porttypes[PORTTYPE_TOP_CAT];
265 }
266
267 return NULL;
268}
269
270int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
271 uint bus_idx, uint m, uint phy_idx)
272{
273 struct phy_device *phydev;
274
275 phydev = phy_find_by_mask(bus, BIT(m * 8 + phy_idx));
276 printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
277
278 if (!phydev)
279 puts("!");
280 else
281 ihs_phy_config(phydev, porttype->phy_invert_in_pol,
282 porttype->phy_invert_out_pol);
283
284 return 0;
285}
286
287int init_octo_phys(uint octo_phy_mask)
288{
289 uint bus_idx;
290
291 /* there are up to four octo-phys on each mdio bus */
Marek Vasut1b5fcca2025-02-22 21:33:33 +0100292 for (bus_idx = 0; bus_idx < ARRAY_SIZE(gpio_mii_set); ++bus_idx) {
Marek Vasut694f04d2025-02-22 21:33:16 +0100293 uint m;
294 uint octo_index = bus_idx * 4;
295 struct mii_dev *bus = NULL;
296 struct porttype *porttype = NULL;
297 int ret;
298
299 porttype = get_porttype(octo_phy_mask, bus_idx);
300
301 if (!porttype)
302 continue;
303
304 for (m = 0; m < 4; ++m) {
305 uint phy_idx;
306
307 /**
308 * Register a bus device if there is at least one phy
309 * on the current bus
310 */
311 if (!m && octo_phy_mask & (0xf << octo_index)) {
312 ret = register_miiphy_bus(bus_idx, &bus);
313 if (ret)
314 return ret;
315 }
316
317 if (!(octo_phy_mask & BIT(octo_index + m)))
318 continue;
319
320 for (phy_idx = 0; phy_idx < 8; ++phy_idx)
321 init_single_phy(porttype, bus, bus_idx, m,
322 phy_idx);
323 }
324 }
325
326 return 0;
327}