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