]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
111fd19e RZ |
2 | /* |
3 | * Copyright 2012 Freescale Semiconductor, Inc. | |
b21f87a3 | 4 | * Andy Fleming <[email protected]> |
111fd19e | 5 | * Roy Zang <[email protected]> |
111fd19e RZ |
6 | * Some part is taken from tsec.c |
7 | */ | |
8 | #include <common.h> | |
9 | #include <miiphy.h> | |
10 | #include <phy.h> | |
11 | #include <asm/io.h> | |
cd348efa | 12 | #include <fsl_memac.h> |
111fd19e RZ |
13 | #include <fm_eth.h> |
14 | ||
cd348efa SX |
15 | #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN |
16 | #define memac_out_32(a, v) out_le32(a, v) | |
17 | #define memac_clrbits_32(a, v) clrbits_le32(a, v) | |
18 | #define memac_setbits_32(a, v) setbits_le32(a, v) | |
19 | #else | |
20 | #define memac_out_32(a, v) out_be32(a, v) | |
21 | #define memac_clrbits_32(a, v) clrbits_be32(a, v) | |
22 | #define memac_setbits_32(a, v) setbits_be32(a, v) | |
23 | #endif | |
24 | ||
20e0f629 MB |
25 | #ifdef CONFIG_DM_ETH |
26 | struct fm_mdio_priv { | |
27 | struct memac_mdio_controller *regs; | |
28 | }; | |
29 | #endif | |
30 | ||
cd348efa SX |
31 | static u32 memac_in_32(u32 *reg) |
32 | { | |
33 | #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN | |
34 | return in_le32(reg); | |
35 | #else | |
36 | return in_be32(reg); | |
37 | #endif | |
38 | } | |
39 | ||
111fd19e RZ |
40 | /* |
41 | * Write value to the PHY for this device to the register at regnum, waiting | |
42 | * until the write is done before it returns. All PHY configuration has to be | |
43 | * done through the TSEC1 MIIM regs | |
44 | */ | |
45 | int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr, | |
46 | int regnum, u16 value) | |
47 | { | |
20e0f629 | 48 | struct memac_mdio_controller *regs; |
111fd19e | 49 | u32 mdio_ctl; |
111fd19e RZ |
50 | u32 c45 = 1; /* Default to 10G interface */ |
51 | ||
20e0f629 MB |
52 | #ifndef CONFIG_DM_ETH |
53 | regs = bus->priv; | |
54 | #else | |
55 | struct fm_mdio_priv *priv; | |
56 | ||
57 | if (!bus->priv) | |
58 | return -EINVAL; | |
59 | priv = dev_get_priv(bus->priv); | |
60 | regs = priv->regs; | |
61 | debug("memac_mdio_write(regs %p, port %d, dev %d, reg %d, val %#x)\n", | |
62 | regs, port_addr, dev_addr, regnum, value); | |
63 | #endif | |
64 | ||
111fd19e RZ |
65 | if (dev_addr == MDIO_DEVAD_NONE) { |
66 | c45 = 0; /* clause 22 */ | |
67 | dev_addr = regnum & 0x1f; | |
cd348efa | 68 | memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
3a7ed5aa | 69 | } else |
cd348efa | 70 | memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
111fd19e RZ |
71 | |
72 | /* Wait till the bus is free */ | |
cd348efa | 73 | while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) |
111fd19e RZ |
74 | ; |
75 | ||
76 | /* Set the port and dev addr */ | |
77 | mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); | |
cd348efa | 78 | memac_out_32(®s->mdio_ctl, mdio_ctl); |
111fd19e RZ |
79 | |
80 | /* Set the register address */ | |
81 | if (c45) | |
cd348efa | 82 | memac_out_32(®s->mdio_addr, regnum & 0xffff); |
111fd19e RZ |
83 | |
84 | /* Wait till the bus is free */ | |
cd348efa | 85 | while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) |
111fd19e RZ |
86 | ; |
87 | ||
88 | /* Write the value to the register */ | |
cd348efa | 89 | memac_out_32(®s->mdio_data, MDIO_DATA(value)); |
111fd19e RZ |
90 | |
91 | /* Wait till the MDIO write is complete */ | |
cd348efa | 92 | while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) |
111fd19e RZ |
93 | ; |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | /* | |
99 | * Reads from register regnum in the PHY for device dev, returning the value. | |
100 | * Clears miimcom first. All PHY configuration has to be done through the | |
101 | * TSEC1 MIIM regs | |
102 | */ | |
103 | int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr, | |
104 | int regnum) | |
105 | { | |
20e0f629 | 106 | struct memac_mdio_controller *regs; |
111fd19e | 107 | u32 mdio_ctl; |
111fd19e RZ |
108 | u32 c45 = 1; |
109 | ||
20e0f629 MB |
110 | #ifndef CONFIG_DM_ETH |
111 | regs = bus->priv; | |
112 | #else | |
113 | struct fm_mdio_priv *priv; | |
114 | ||
115 | if (!bus->priv) | |
116 | return -EINVAL; | |
117 | priv = dev_get_priv(bus->priv); | |
118 | regs = priv->regs; | |
119 | #endif | |
120 | ||
111fd19e | 121 | if (dev_addr == MDIO_DEVAD_NONE) { |
20e0f629 | 122 | #ifndef CONFIG_DM_ETH |
ff5fb2a3 SX |
123 | if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME)) |
124 | return 0xffff; | |
20e0f629 | 125 | #endif |
111fd19e RZ |
126 | c45 = 0; /* clause 22 */ |
127 | dev_addr = regnum & 0x1f; | |
cd348efa | 128 | memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
3a7ed5aa | 129 | } else |
cd348efa | 130 | memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
111fd19e RZ |
131 | |
132 | /* Wait till the bus is free */ | |
cd348efa | 133 | while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) |
111fd19e RZ |
134 | ; |
135 | ||
136 | /* Set the Port and Device Addrs */ | |
137 | mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); | |
cd348efa | 138 | memac_out_32(®s->mdio_ctl, mdio_ctl); |
111fd19e RZ |
139 | |
140 | /* Set the register address */ | |
141 | if (c45) | |
cd348efa | 142 | memac_out_32(®s->mdio_addr, regnum & 0xffff); |
111fd19e RZ |
143 | |
144 | /* Wait till the bus is free */ | |
cd348efa | 145 | while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) |
111fd19e RZ |
146 | ; |
147 | ||
148 | /* Initiate the read */ | |
149 | mdio_ctl |= MDIO_CTL_READ; | |
cd348efa | 150 | memac_out_32(®s->mdio_ctl, mdio_ctl); |
111fd19e RZ |
151 | |
152 | /* Wait till the MDIO write is complete */ | |
cd348efa | 153 | while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) |
111fd19e RZ |
154 | ; |
155 | ||
156 | /* Return all Fs if nothing was there */ | |
cd348efa | 157 | if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) |
111fd19e RZ |
158 | return 0xffff; |
159 | ||
cd348efa | 160 | return memac_in_32(®s->mdio_data) & 0xffff; |
111fd19e RZ |
161 | } |
162 | ||
163 | int memac_mdio_reset(struct mii_dev *bus) | |
164 | { | |
165 | return 0; | |
166 | } | |
167 | ||
20e0f629 | 168 | #ifndef CONFIG_DM_ETH |
111fd19e RZ |
169 | int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info) |
170 | { | |
171 | struct mii_dev *bus = mdio_alloc(); | |
172 | ||
173 | if (!bus) { | |
174 | printf("Failed to allocate FM TGEC MDIO bus\n"); | |
175 | return -1; | |
176 | } | |
177 | ||
178 | bus->read = memac_mdio_read; | |
179 | bus->write = memac_mdio_write; | |
180 | bus->reset = memac_mdio_reset; | |
192bc694 | 181 | strcpy(bus->name, info->name); |
111fd19e RZ |
182 | |
183 | bus->priv = info->regs; | |
184 | ||
2ee6c52e PJ |
185 | /* |
186 | * On some platforms like B4860, default value of MDIO_CLK_DIV bits | |
187 | * in mdio_stat(mdio_cfg) register generates MDIO clock too high | |
188 | * (much higher than 2.5MHz), violating the IEEE specs. | |
189 | * On other platforms like T1040, default value of MDIO_CLK_DIV bits | |
190 | * is zero, so MDIO clock is disabled. | |
191 | * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to | |
192 | * be properly initialized. | |
ae6b4583 SX |
193 | * NEG bit default should be '1' as per FMAN-v3 RM, but on platform |
194 | * like T2080QDS, this bit default is '0', which leads to MDIO failure | |
195 | * on XAUI PHY, so set this bit definitely. | |
2ee6c52e | 196 | */ |
cd348efa SX |
197 | memac_setbits_32( |
198 | &((struct memac_mdio_controller *)info->regs)->mdio_stat, | |
199 | MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); | |
2ee6c52e | 200 | |
111fd19e RZ |
201 | return mdio_register(bus); |
202 | } | |
20e0f629 MB |
203 | |
204 | #else /* CONFIG_DM_ETH */ | |
205 | #if defined(CONFIG_PHYLIB) && defined(CONFIG_DM_MDIO) | |
206 | static int fm_mdio_read(struct udevice *dev, int addr, int devad, int reg) | |
207 | { | |
208 | struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : | |
209 | NULL; | |
210 | ||
211 | if (pdata && pdata->mii_bus) | |
212 | return memac_mdio_read(pdata->mii_bus, addr, devad, reg); | |
213 | ||
214 | return -1; | |
215 | } | |
216 | ||
217 | static int fm_mdio_write(struct udevice *dev, int addr, int devad, int reg, | |
218 | u16 val) | |
219 | { | |
220 | struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : | |
221 | NULL; | |
222 | ||
223 | if (pdata && pdata->mii_bus) | |
224 | return memac_mdio_write(pdata->mii_bus, addr, devad, reg, val); | |
225 | ||
226 | return -1; | |
227 | } | |
228 | ||
229 | static int fm_mdio_reset(struct udevice *dev) | |
230 | { | |
231 | struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : | |
232 | NULL; | |
233 | ||
234 | if (pdata && pdata->mii_bus) | |
235 | return memac_mdio_reset(pdata->mii_bus); | |
236 | ||
237 | return -1; | |
238 | } | |
239 | ||
240 | static const struct mdio_ops fm_mdio_ops = { | |
241 | .read = fm_mdio_read, | |
242 | .write = fm_mdio_write, | |
243 | .reset = fm_mdio_reset, | |
244 | }; | |
245 | ||
246 | static const struct udevice_id fm_mdio_ids[] = { | |
247 | { .compatible = "fsl,fman-memac-mdio" }, | |
248 | {} | |
249 | }; | |
250 | ||
251 | static int fm_mdio_probe(struct udevice *dev) | |
252 | { | |
253 | struct fm_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL; | |
254 | struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) : | |
255 | NULL; | |
256 | ||
257 | if (!dev) { | |
258 | printf("%s dev = NULL\n", __func__); | |
259 | return -1; | |
260 | } | |
261 | if (!priv) { | |
262 | printf("dev_get_priv(dev %p) = NULL\n", dev); | |
263 | return -1; | |
264 | } | |
265 | priv->regs = (void *)(uintptr_t)dev_read_addr(dev); | |
266 | debug("%s priv %p @ regs %p, pdata %p\n", __func__, | |
267 | priv, priv->regs, pdata); | |
268 | ||
269 | /* | |
270 | * On some platforms like B4860, default value of MDIO_CLK_DIV bits | |
271 | * in mdio_stat(mdio_cfg) register generates MDIO clock too high | |
272 | * (much higher than 2.5MHz), violating the IEEE specs. | |
273 | * On other platforms like T1040, default value of MDIO_CLK_DIV bits | |
274 | * is zero, so MDIO clock is disabled. | |
275 | * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to | |
276 | * be properly initialized. | |
277 | * The default NEG bit should be '1' as per FMANv3 RM, but on platforms | |
278 | * like T2080QDS, this bit default is '0', which leads to MDIO failure | |
279 | * on XAUI PHY, so set this bit definitely. | |
280 | */ | |
281 | if (priv && priv->regs && priv->regs->mdio_stat) | |
282 | memac_setbits_32(&priv->regs->mdio_stat, | |
283 | MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); | |
284 | ||
285 | return 0; | |
286 | } | |
287 | ||
288 | static int fm_mdio_remove(struct udevice *dev) | |
289 | { | |
290 | return 0; | |
291 | } | |
292 | ||
293 | U_BOOT_DRIVER(fman_mdio) = { | |
294 | .name = "fman_mdio", | |
295 | .id = UCLASS_MDIO, | |
296 | .of_match = fm_mdio_ids, | |
297 | .probe = fm_mdio_probe, | |
298 | .remove = fm_mdio_remove, | |
299 | .ops = &fm_mdio_ops, | |
300 | .priv_auto_alloc_size = sizeof(struct fm_mdio_priv), | |
301 | .platdata_auto_alloc_size = sizeof(struct mdio_perdev_priv), | |
302 | }; | |
303 | #endif /* CONFIG_PHYLIB && CONFIG_DM_MDIO */ | |
304 | #endif /* CONFIG_DM_ETH */ |