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