xref: /openbmc/u-boot/drivers/net/pfe_eth/pfe_mdio.c (revision 27f622d56876f01e11a74b292e52a94451144cff)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a4a40437SCalvin Johnson /*
3a4a40437SCalvin Johnson  * Copyright 2015-2016 Freescale Semiconductor, Inc.
4a4a40437SCalvin Johnson  * Copyright 2017 NXP
5a4a40437SCalvin Johnson  */
6a4a40437SCalvin Johnson #include <common.h>
7a4a40437SCalvin Johnson #include <dm.h>
8a4a40437SCalvin Johnson #include <dm/platform_data/pfe_dm_eth.h>
9a4a40437SCalvin Johnson #include <net.h>
10a4a40437SCalvin Johnson #include <net/pfe_eth/pfe_eth.h>
11a4a40437SCalvin Johnson 
12a4a40437SCalvin Johnson extern struct gemac_s gem_info[];
13a4a40437SCalvin Johnson #if defined(CONFIG_PHYLIB)
14a4a40437SCalvin Johnson 
15a4a40437SCalvin Johnson #define MDIO_TIMEOUT    5000
pfe_write_addr(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr)16a4a40437SCalvin Johnson static int pfe_write_addr(struct mii_dev *bus, int phy_addr, int dev_addr,
17a4a40437SCalvin Johnson 			  int reg_addr)
18a4a40437SCalvin Johnson {
19a4a40437SCalvin Johnson 	void *reg_base = bus->priv;
20a4a40437SCalvin Johnson 	u32 devadr;
21a4a40437SCalvin Johnson 	u32 phy;
22a4a40437SCalvin Johnson 	u32 reg_data;
23a4a40437SCalvin Johnson 	int timeout = MDIO_TIMEOUT;
24a4a40437SCalvin Johnson 
25a4a40437SCalvin Johnson 	devadr = ((dev_addr & EMAC_MII_DATA_RA_MASK) << EMAC_MII_DATA_RA_SHIFT);
26a4a40437SCalvin Johnson 	phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
27a4a40437SCalvin Johnson 
28a4a40437SCalvin Johnson 	reg_data = (EMAC_MII_DATA_TA | phy | devadr | reg_addr);
29a4a40437SCalvin Johnson 
30a4a40437SCalvin Johnson 	writel(reg_data, reg_base + EMAC_MII_DATA_REG);
31a4a40437SCalvin Johnson 
32a4a40437SCalvin Johnson 	/*
33a4a40437SCalvin Johnson 	 * wait for the MII interrupt
34a4a40437SCalvin Johnson 	 */
35a4a40437SCalvin Johnson 	while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
36a4a40437SCalvin Johnson 		if (timeout-- <= 0) {
37a4a40437SCalvin Johnson 			printf("Phy MDIO read/write timeout\n");
38a4a40437SCalvin Johnson 			return -1;
39a4a40437SCalvin Johnson 		}
40a4a40437SCalvin Johnson 	}
41a4a40437SCalvin Johnson 
42a4a40437SCalvin Johnson 	/*
43a4a40437SCalvin Johnson 	 * clear MII interrupt
44a4a40437SCalvin Johnson 	 */
45a4a40437SCalvin Johnson 	writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
46a4a40437SCalvin Johnson 
47a4a40437SCalvin Johnson 	return 0;
48a4a40437SCalvin Johnson }
49a4a40437SCalvin Johnson 
pfe_phy_read(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr)50a4a40437SCalvin Johnson static int pfe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
51a4a40437SCalvin Johnson 			int reg_addr)
52a4a40437SCalvin Johnson {
53a4a40437SCalvin Johnson 	void *reg_base = bus->priv;
54a4a40437SCalvin Johnson 	u32 reg;
55a4a40437SCalvin Johnson 	u32 phy;
56a4a40437SCalvin Johnson 	u32 reg_data;
57a4a40437SCalvin Johnson 	u16 val;
58a4a40437SCalvin Johnson 	int timeout = MDIO_TIMEOUT;
59a4a40437SCalvin Johnson 
60a4a40437SCalvin Johnson 	if (dev_addr == MDIO_DEVAD_NONE) {
61a4a40437SCalvin Johnson 		reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
62a4a40437SCalvin Johnson 			EMAC_MII_DATA_RA_SHIFT);
63a4a40437SCalvin Johnson 	} else {
64a4a40437SCalvin Johnson 		pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
65a4a40437SCalvin Johnson 		reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
66a4a40437SCalvin Johnson 		       EMAC_MII_DATA_RA_SHIFT);
67a4a40437SCalvin Johnson 	}
68a4a40437SCalvin Johnson 
69a4a40437SCalvin Johnson 	phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
70a4a40437SCalvin Johnson 
71a4a40437SCalvin Johnson 	if (dev_addr == MDIO_DEVAD_NONE)
72a4a40437SCalvin Johnson 		reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
73a4a40437SCalvin Johnson 			    EMAC_MII_DATA_TA | phy | reg);
74a4a40437SCalvin Johnson 	else
75a4a40437SCalvin Johnson 		reg_data = (EMAC_MII_DATA_OP_CL45_RD | EMAC_MII_DATA_TA |
76a4a40437SCalvin Johnson 			    phy | reg);
77a4a40437SCalvin Johnson 
78a4a40437SCalvin Johnson 	writel(reg_data, reg_base + EMAC_MII_DATA_REG);
79a4a40437SCalvin Johnson 
80a4a40437SCalvin Johnson 	/*
81a4a40437SCalvin Johnson 	 * wait for the MII interrupt
82a4a40437SCalvin Johnson 	 */
83a4a40437SCalvin Johnson 	while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
84a4a40437SCalvin Johnson 		if (timeout-- <= 0) {
85a4a40437SCalvin Johnson 			printf("Phy MDIO read/write timeout\n");
86a4a40437SCalvin Johnson 			return -1;
87a4a40437SCalvin Johnson 		}
88a4a40437SCalvin Johnson 	}
89a4a40437SCalvin Johnson 
90a4a40437SCalvin Johnson 	/*
91a4a40437SCalvin Johnson 	 * clear MII interrupt
92a4a40437SCalvin Johnson 	 */
93a4a40437SCalvin Johnson 	writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
94a4a40437SCalvin Johnson 
95a4a40437SCalvin Johnson 	/*
96a4a40437SCalvin Johnson 	 * it's now safe to read the PHY's register
97a4a40437SCalvin Johnson 	 */
98a4a40437SCalvin Johnson 	val = (u16)readl(reg_base + EMAC_MII_DATA_REG);
99a4a40437SCalvin Johnson 	debug("%s: %p phy: 0x%x reg:0x%08x val:%#x\n", __func__, reg_base,
100a4a40437SCalvin Johnson 	      phy_addr, reg_addr, val);
101a4a40437SCalvin Johnson 
102a4a40437SCalvin Johnson 	return val;
103a4a40437SCalvin Johnson }
104a4a40437SCalvin Johnson 
pfe_phy_write(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr,u16 data)105a4a40437SCalvin Johnson static int pfe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
106a4a40437SCalvin Johnson 			 int reg_addr, u16 data)
107a4a40437SCalvin Johnson {
108a4a40437SCalvin Johnson 	void *reg_base = bus->priv;
109a4a40437SCalvin Johnson 	u32 reg;
110a4a40437SCalvin Johnson 	u32 phy;
111a4a40437SCalvin Johnson 	u32 reg_data;
112a4a40437SCalvin Johnson 	int timeout = MDIO_TIMEOUT;
113a4a40437SCalvin Johnson 	int val;
114a4a40437SCalvin Johnson 
115a4a40437SCalvin Johnson 	if (dev_addr == MDIO_DEVAD_NONE) {
116a4a40437SCalvin Johnson 		reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
117a4a40437SCalvin Johnson 		       EMAC_MII_DATA_RA_SHIFT);
118a4a40437SCalvin Johnson 	} else {
119a4a40437SCalvin Johnson 		pfe_write_addr(bus, phy_addr, dev_addr, reg_addr);
120a4a40437SCalvin Johnson 		reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
121a4a40437SCalvin Johnson 		       EMAC_MII_DATA_RA_SHIFT);
122a4a40437SCalvin Johnson 	}
123a4a40437SCalvin Johnson 
124a4a40437SCalvin Johnson 	phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
125a4a40437SCalvin Johnson 
126a4a40437SCalvin Johnson 	if (dev_addr == MDIO_DEVAD_NONE)
127a4a40437SCalvin Johnson 		reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
128a4a40437SCalvin Johnson 			    EMAC_MII_DATA_TA | phy | reg | data);
129a4a40437SCalvin Johnson 	else
130a4a40437SCalvin Johnson 		reg_data = (EMAC_MII_DATA_OP_CL45_WR | EMAC_MII_DATA_TA |
131a4a40437SCalvin Johnson 			    phy | reg | data);
132a4a40437SCalvin Johnson 
133a4a40437SCalvin Johnson 	writel(reg_data, reg_base + EMAC_MII_DATA_REG);
134a4a40437SCalvin Johnson 
135a4a40437SCalvin Johnson 	/*
136a4a40437SCalvin Johnson 	 * wait for the MII interrupt
137a4a40437SCalvin Johnson 	 */
138a4a40437SCalvin Johnson 	while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
139a4a40437SCalvin Johnson 		if (timeout-- <= 0) {
140a4a40437SCalvin Johnson 			printf("Phy MDIO read/write timeout\n");
141a4a40437SCalvin Johnson 			return -1;
142a4a40437SCalvin Johnson 		}
143a4a40437SCalvin Johnson 	}
144a4a40437SCalvin Johnson 
145a4a40437SCalvin Johnson 	/*
146a4a40437SCalvin Johnson 	 * clear MII interrupt
147a4a40437SCalvin Johnson 	 */
148a4a40437SCalvin Johnson 	writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
149a4a40437SCalvin Johnson 
150a4a40437SCalvin Johnson 	debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phy_addr,
151a4a40437SCalvin Johnson 	      reg_addr, data);
152a4a40437SCalvin Johnson 
153a4a40437SCalvin Johnson 	return val;
154a4a40437SCalvin Johnson }
155a4a40437SCalvin Johnson 
pfe_configure_serdes(struct pfe_eth_dev * priv)156a4a40437SCalvin Johnson static void pfe_configure_serdes(struct pfe_eth_dev *priv)
157a4a40437SCalvin Johnson {
158a4a40437SCalvin Johnson 	struct mii_dev bus;
159a4a40437SCalvin Johnson 	int value, sgmii_2500 = 0;
160a4a40437SCalvin Johnson 	struct gemac_s *gem = priv->gem;
161a4a40437SCalvin Johnson 
162a4a40437SCalvin Johnson 	if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500)
163a4a40437SCalvin Johnson 		sgmii_2500 = 1;
164a4a40437SCalvin Johnson 
165a4a40437SCalvin Johnson 
166a4a40437SCalvin Johnson 	/* PCS configuration done with corresponding GEMAC */
167a4a40437SCalvin Johnson 	bus.priv = gem_info[priv->gemac_port].gemac_base;
168a4a40437SCalvin Johnson 
169a4a40437SCalvin Johnson 	pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x0);
170a4a40437SCalvin Johnson 	pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x1);
171a4a40437SCalvin Johnson 	pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x2);
172a4a40437SCalvin Johnson 	pfe_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x3);
173a4a40437SCalvin Johnson 
174a4a40437SCalvin Johnson 	/* Reset serdes */
175a4a40437SCalvin Johnson 	pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x0, 0x8000);
176a4a40437SCalvin Johnson 
177a4a40437SCalvin Johnson 	/* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
178a4a40437SCalvin Johnson 	value = PHY_SGMII_IF_MODE_SGMII;
179a4a40437SCalvin Johnson 	if (!sgmii_2500)
180a4a40437SCalvin Johnson 		value |= PHY_SGMII_IF_MODE_AN;
181a4a40437SCalvin Johnson 	else
182a4a40437SCalvin Johnson 		value |= PHY_SGMII_IF_MODE_SGMII_GBT;
183a4a40437SCalvin Johnson 
184a4a40437SCalvin Johnson 	pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
185a4a40437SCalvin Johnson 
186a4a40437SCalvin Johnson 	/* Dev ability according to SGMII specification */
187a4a40437SCalvin Johnson 	value = PHY_SGMII_DEV_ABILITY_SGMII;
188a4a40437SCalvin Johnson 	pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
189a4a40437SCalvin Johnson 
190a4a40437SCalvin Johnson 	/* These values taken from validation team */
191a4a40437SCalvin Johnson 	if (!sgmii_2500) {
192a4a40437SCalvin Johnson 		pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x0);
193a4a40437SCalvin Johnson 		pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0x400);
194a4a40437SCalvin Johnson 	} else {
195a4a40437SCalvin Johnson 		pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x7);
196a4a40437SCalvin Johnson 		pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xa120);
197a4a40437SCalvin Johnson 	}
198a4a40437SCalvin Johnson 
199a4a40437SCalvin Johnson 	/* Restart AN */
200a4a40437SCalvin Johnson 	value = PHY_SGMII_CR_DEF_VAL;
201a4a40437SCalvin Johnson 	if (!sgmii_2500)
202a4a40437SCalvin Johnson 		value |= PHY_SGMII_CR_RESET_AN;
203a4a40437SCalvin Johnson 	/* Disable Auto neg for 2.5G SGMII as it doesn't support auto neg*/
204a4a40437SCalvin Johnson 	if (sgmii_2500)
205a4a40437SCalvin Johnson 		value &= ~PHY_SGMII_ENABLE_AN;
206a4a40437SCalvin Johnson 	pfe_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
207a4a40437SCalvin Johnson }
208a4a40437SCalvin Johnson 
pfe_phy_configure(struct pfe_eth_dev * priv,int dev_id,int phy_id)209a4a40437SCalvin Johnson int pfe_phy_configure(struct pfe_eth_dev *priv, int dev_id, int phy_id)
210a4a40437SCalvin Johnson {
211a4a40437SCalvin Johnson 	struct phy_device *phydev = NULL;
212a4a40437SCalvin Johnson 	struct udevice *dev = priv->dev;
213a4a40437SCalvin Johnson 	struct gemac_s *gem = priv->gem;
214a4a40437SCalvin Johnson 	struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
215a4a40437SCalvin Johnson 
216a4a40437SCalvin Johnson 	if (!gem->bus)
217a4a40437SCalvin Johnson 		return -1;
218a4a40437SCalvin Johnson 
219a4a40437SCalvin Johnson 	/* Configure SGMII  PCS */
220a4a40437SCalvin Johnson 	if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII ||
221a4a40437SCalvin Johnson 	    gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500) {
222a4a40437SCalvin Johnson 		out_be32(&scfg->mdioselcr, 0x00000000);
223a4a40437SCalvin Johnson 		pfe_configure_serdes(priv);
224a4a40437SCalvin Johnson 	}
225a4a40437SCalvin Johnson 
226a4a40437SCalvin Johnson 	mdelay(100);
227a4a40437SCalvin Johnson 
228a4a40437SCalvin Johnson 	/* By this time on-chip SGMII initialization is done
229a4a40437SCalvin Johnson 	 * we can switch mdio interface to external PHYs
230a4a40437SCalvin Johnson 	 */
231a4a40437SCalvin Johnson 	out_be32(&scfg->mdioselcr, 0x80000000);
232a4a40437SCalvin Johnson 
233a4a40437SCalvin Johnson 	phydev = phy_connect(gem->bus, phy_id, dev, gem->phy_mode);
234a4a40437SCalvin Johnson 	if (!phydev) {
235a4a40437SCalvin Johnson 		printf("phy_connect failed\n");
236a4a40437SCalvin Johnson 		return -ENODEV;
237a4a40437SCalvin Johnson 	}
238a4a40437SCalvin Johnson 
239a4a40437SCalvin Johnson 	phy_config(phydev);
240a4a40437SCalvin Johnson 
241a4a40437SCalvin Johnson 	priv->phydev = phydev;
242a4a40437SCalvin Johnson 
243a4a40437SCalvin Johnson 	return 0;
244a4a40437SCalvin Johnson }
245a4a40437SCalvin Johnson #endif
246a4a40437SCalvin Johnson 
pfe_mdio_init(struct pfe_mdio_info * mdio_info)247a4a40437SCalvin Johnson struct mii_dev *pfe_mdio_init(struct pfe_mdio_info *mdio_info)
248a4a40437SCalvin Johnson {
249a4a40437SCalvin Johnson 	struct mii_dev *bus;
250a4a40437SCalvin Johnson 	int ret;
251a4a40437SCalvin Johnson 	u32 mdio_speed;
252a4a40437SCalvin Johnson 	u32 pclk = 250000000;
253a4a40437SCalvin Johnson 
254a4a40437SCalvin Johnson 	bus = mdio_alloc();
255a4a40437SCalvin Johnson 	if (!bus) {
256a4a40437SCalvin Johnson 		printf("mdio_alloc failed\n");
257a4a40437SCalvin Johnson 		return NULL;
258a4a40437SCalvin Johnson 	}
259a4a40437SCalvin Johnson 	bus->read = pfe_phy_read;
260a4a40437SCalvin Johnson 	bus->write = pfe_phy_write;
261a4a40437SCalvin Johnson 
262a4a40437SCalvin Johnson 	/* MAC1 MDIO used to communicate with external PHYS */
263a4a40437SCalvin Johnson 	bus->priv = mdio_info->reg_base;
264a4a40437SCalvin Johnson 	sprintf(bus->name, mdio_info->name);
265a4a40437SCalvin Johnson 
266a4a40437SCalvin Johnson 	/* configure mdio speed */
267a4a40437SCalvin Johnson 	mdio_speed = (DIV_ROUND_UP(pclk, 4000000) << EMAC_MII_SPEED_SHIFT);
268a4a40437SCalvin Johnson 	mdio_speed |= EMAC_HOLDTIME(0x5);
269a4a40437SCalvin Johnson 	writel(mdio_speed, mdio_info->reg_base + EMAC_MII_CTRL_REG);
270a4a40437SCalvin Johnson 
271a4a40437SCalvin Johnson 	ret = mdio_register(bus);
272a4a40437SCalvin Johnson 	if (ret) {
273a4a40437SCalvin Johnson 		printf("mdio_register failed\n");
274a4a40437SCalvin Johnson 		free(bus);
275a4a40437SCalvin Johnson 		return NULL;
276a4a40437SCalvin Johnson 	}
277a4a40437SCalvin Johnson 	return bus;
278a4a40437SCalvin Johnson }
279a4a40437SCalvin Johnson 
pfe_set_mdio(int dev_id,struct mii_dev * bus)280a4a40437SCalvin Johnson void pfe_set_mdio(int dev_id, struct mii_dev *bus)
281a4a40437SCalvin Johnson {
282a4a40437SCalvin Johnson 	gem_info[dev_id].bus = bus;
283a4a40437SCalvin Johnson }
284a4a40437SCalvin Johnson 
pfe_set_phy_address_mode(int dev_id,int phy_id,int phy_mode)285a4a40437SCalvin Johnson void pfe_set_phy_address_mode(int dev_id, int phy_id, int phy_mode)
286a4a40437SCalvin Johnson {
287a4a40437SCalvin Johnson 	gem_info[dev_id].phy_address = phy_id;
288a4a40437SCalvin Johnson 	gem_info[dev_id].phy_mode  = phy_mode;
289a4a40437SCalvin Johnson }
290