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	phydev->interface = PHY_INTERFACE_MODE_MII;
32	phy_config(phydev);
33
34	/* enable QSGMII autonegotiation with flow control */
35	phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004);
36	reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
37	reg |= (3 << 6);
38	phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
39
40	/*
41	 * invert QSGMII Q_INP/N and Q_OUTP/N if required
42	 * and perform global reset
43	 */
44	reg = phy_read(phydev, MDIO_DEVAD_NONE, 26);
45	if (qinpn)
46		reg |= (1 << 13);
47	if (qoutpn)
48		reg |= (1 << 12);
49	reg |= (1 << 15);
50	phy_write(phydev, MDIO_DEVAD_NONE, 26, reg);
51
52	/* advertise 1000BASE-T full-duplex only  */
53	phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
54	reg = phy_read(phydev, MDIO_DEVAD_NONE, 4);
55	reg &= ~0x1e0;
56	phy_write(phydev, MDIO_DEVAD_NONE, 4, reg);
57	reg = phy_read(phydev, MDIO_DEVAD_NONE, 9);
58	reg = (reg & ~0x300) | 0x200;
59	phy_write(phydev, MDIO_DEVAD_NONE, 9, reg);
60
61	/* copper power up */
62	reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
63	reg &= ~0x0004;
64	phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
65}
66
67uint calculate_octo_phy_mask(void)
68{
69	uint k;
70	uint octo_phy_mask = 0;
71	struct gpio_desc gpio = {};
72	char gpio_name[64];
73	static const char * const dev_name[] = {"pca9698@23", "pca9698@21",
74						"pca9698@24", "pca9698@25",
75						"pca9698@26"};
76
77	/* mark all octo phys that should be present */
78	for (k = 0; k < 5; ++k) {
79		snprintf(gpio_name, 64, "cat-gpio-%u", k);
80
81		if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name))
82			continue;
83
84		/* check CAT flag */
85		if (dm_gpio_get_value(&gpio))
86			octo_phy_mask |= (1 << (k * 2));
87		else
88			/* If CAT == 0, there's no second octo phy -> skip */
89			continue;
90
91		snprintf(gpio_name, 64, "second-octo-gpio-%u", k);
92
93		if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) {
94			/* default: second octo phy is present */
95			octo_phy_mask |= (1 << (k * 2 + 1));
96			continue;
97		}
98
99		if (dm_gpio_get_value(&gpio) == 0)
100			octo_phy_mask |= (1 << (k * 2 + 1));
101	}
102
103	return octo_phy_mask;
104}
105
106int register_miiphy_bus(uint k, struct mii_dev **bus)
107{
108	int retval;
109	struct mii_dev *mdiodev = mdio_alloc();
110	char *name = bb_miiphy_buses[k].name;
111
112	if (!mdiodev)
113		return -ENOMEM;
114	strlcpy(mdiodev->name, name, 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;
147
148	phydev = phy_find_by_mask(bus, BIT(m * 8 + phy_idx));
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);
356