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