]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
9082eeac AF |
2 | /* |
3 | * Atheros PHY drivers | |
4 | * | |
6027384a | 5 | * Copyright 2011, 2013 Freescale Semiconductor, Inc. |
9082eeac | 6 | * author Andy Fleming |
fe6293a8 | 7 | * Copyright (c) 2019 Michael Walle <michael@walle.cc> |
9082eeac | 8 | */ |
d678a59d | 9 | #include <common.h> |
9082eeac | 10 | #include <phy.h> |
fe6293a8 MW |
11 | #include <dm/device_compat.h> |
12 | #include <linux/bitfield.h> | |
cd93d625 | 13 | #include <linux/bitops.h> |
fe6293a8 | 14 | #include <dt-bindings/net/qca-ar803x.h> |
9082eeac | 15 | |
ce412b79 M |
16 | #define AR803x_PHY_DEBUG_ADDR_REG 0x1d |
17 | #define AR803x_PHY_DEBUG_DATA_REG 0x1e | |
18 | ||
fe6293a8 MW |
19 | /* Debug registers */ |
20 | #define AR803x_DEBUG_REG_0 0x0 | |
21 | #define AR803x_RGMII_RX_CLK_DLY BIT(15) | |
22 | ||
ce412b79 | 23 | #define AR803x_DEBUG_REG_5 0x5 |
29602f9c | 24 | #define AR803x_RGMII_TX_CLK_DLY BIT(8) |
ce412b79 | 25 | |
fe6293a8 MW |
26 | #define AR803x_DEBUG_REG_1F 0x1f |
27 | #define AR803x_PLL_ON BIT(2) | |
28 | #define AR803x_RGMII_1V8 BIT(3) | |
29602f9c | 29 | |
a234ae86 VO |
30 | /* CLK_25M register is at MMD 7, address 0x8016 */ |
31 | #define AR803x_CLK_25M_SEL_REG 0x8016 | |
fe6293a8 MW |
32 | |
33 | #define AR803x_CLK_25M_MASK GENMASK(4, 2) | |
34 | #define AR803x_CLK_25M_25MHZ_XTAL 0 | |
35 | #define AR803x_CLK_25M_25MHZ_DSP 1 | |
36 | #define AR803x_CLK_25M_50MHZ_PLL 2 | |
37 | #define AR803x_CLK_25M_50MHZ_DSP 3 | |
38 | #define AR803x_CLK_25M_62_5MHZ_PLL 4 | |
39 | #define AR803x_CLK_25M_62_5MHZ_DSP 5 | |
40 | #define AR803x_CLK_25M_125MHZ_PLL 6 | |
41 | #define AR803x_CLK_25M_125MHZ_DSP 7 | |
a234ae86 VO |
42 | #define AR8035_CLK_25M_MASK GENMASK(4, 3) |
43 | ||
fe6293a8 MW |
44 | #define AR803x_CLK_25M_DR_MASK GENMASK(8, 7) |
45 | #define AR803x_CLK_25M_DR_FULL 0 | |
46 | #define AR803x_CLK_25M_DR_HALF 1 | |
47 | #define AR803x_CLK_25M_DR_QUARTER 2 | |
48 | ||
30e31931 MW |
49 | #define AR8021_PHY_ID 0x004dd040 |
50 | #define AR8031_PHY_ID 0x004dd074 | |
51 | #define AR8035_PHY_ID 0x004dd072 | |
52 | ||
fe6293a8 MW |
53 | struct ar803x_priv { |
54 | int flags; | |
55 | #define AR803x_FLAG_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */ | |
56 | #define AR803x_FLAG_RGMII_1V8 BIT(1) /* use 1.8V RGMII I/O voltage */ | |
57 | u16 clk_25m_reg; | |
58 | u16 clk_25m_mask; | |
59 | }; | |
60 | ||
f6ae47be | 61 | static int ar803x_debug_reg_read(struct phy_device *phydev, u16 reg) |
29602f9c | 62 | { |
f6ae47be MW |
63 | int ret; |
64 | ||
65 | ret = phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, | |
66 | reg); | |
67 | if (ret < 0) | |
68 | return ret; | |
69 | ||
70 | return phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG); | |
71 | } | |
72 | ||
73 | static int ar803x_debug_reg_mask(struct phy_device *phydev, u16 reg, | |
74 | u16 clear, u16 set) | |
75 | { | |
76 | int val; | |
77 | ||
78 | val = ar803x_debug_reg_read(phydev, reg); | |
79 | if (val < 0) | |
80 | return val; | |
81 | ||
82 | val &= 0xffff; | |
83 | val &= ~clear; | |
84 | val |= set; | |
85 | ||
86 | return phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, | |
87 | val); | |
88 | } | |
89 | ||
90 | static int ar803x_enable_rx_delay(struct phy_device *phydev, bool on) | |
91 | { | |
92 | u16 clear = 0, set = 0; | |
29602f9c | 93 | |
29602f9c | 94 | if (on) |
f6ae47be | 95 | set = AR803x_RGMII_RX_CLK_DLY; |
29602f9c | 96 | else |
f6ae47be MW |
97 | clear = AR803x_RGMII_RX_CLK_DLY; |
98 | ||
99 | return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_0, clear, set); | |
29602f9c VO |
100 | } |
101 | ||
f6ae47be | 102 | static int ar803x_enable_tx_delay(struct phy_device *phydev, bool on) |
29602f9c | 103 | { |
f6ae47be | 104 | u16 clear = 0, set = 0; |
29602f9c | 105 | |
29602f9c | 106 | if (on) |
f6ae47be | 107 | set = AR803x_RGMII_TX_CLK_DLY; |
29602f9c | 108 | else |
f6ae47be MW |
109 | clear = AR803x_RGMII_TX_CLK_DLY; |
110 | ||
111 | return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_5, clear, set); | |
29602f9c | 112 | } |
ce412b79 | 113 | |
9082eeac AF |
114 | static int ar8021_config(struct phy_device *phydev) |
115 | { | |
4d4e4cf7 VO |
116 | phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, |
117 | BMCR_ANENABLE | BMCR_ANRESTART); | |
118 | ||
119 | ar803x_enable_tx_delay(phydev, true); | |
9082eeac | 120 | |
e0d80964 | 121 | phydev->supported = phydev->drv->features; |
9082eeac AF |
122 | return 0; |
123 | } | |
124 | ||
2b772155 | 125 | static int ar803x_delay_config(struct phy_device *phydev) |
ce412b79 | 126 | { |
2b772155 MW |
127 | int ret; |
128 | ||
ce412b79 | 129 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || |
29602f9c | 130 | phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) |
2b772155 | 131 | ret = ar803x_enable_tx_delay(phydev, true); |
13114f38 | 132 | else |
2b772155 | 133 | ret = ar803x_enable_tx_delay(phydev, false); |
ce412b79 M |
134 | |
135 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || | |
29602f9c | 136 | phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) |
2b772155 | 137 | ret = ar803x_enable_rx_delay(phydev, true); |
13114f38 | 138 | else |
2b772155 MW |
139 | ret = ar803x_enable_rx_delay(phydev, false); |
140 | ||
141 | return ret; | |
142 | } | |
143 | ||
fe6293a8 MW |
144 | static int ar803x_regs_config(struct phy_device *phydev) |
145 | { | |
146 | struct ar803x_priv *priv = phydev->priv; | |
147 | u16 set = 0, clear = 0; | |
148 | int val; | |
149 | int ret; | |
150 | ||
151 | /* no configuration available */ | |
152 | if (!priv) | |
153 | return 0; | |
154 | ||
155 | /* | |
156 | * Only supported on the AR8031, AR8035 has strappings for the PLL mode | |
157 | * as well as the RGMII voltage. | |
158 | */ | |
159 | if (phydev->drv->uid == AR8031_PHY_ID) { | |
160 | if (priv->flags & AR803x_FLAG_KEEP_PLL_ENABLED) | |
161 | set |= AR803x_PLL_ON; | |
162 | else | |
163 | clear |= AR803x_PLL_ON; | |
164 | ||
165 | if (priv->flags & AR803x_FLAG_RGMII_1V8) | |
166 | set |= AR803x_RGMII_1V8; | |
167 | else | |
168 | clear |= AR803x_RGMII_1V8; | |
169 | ||
170 | ret = ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_1F, clear, | |
171 | set); | |
172 | if (ret < 0) | |
173 | return ret; | |
174 | } | |
175 | ||
176 | /* save the write access if the mask is empty */ | |
177 | if (priv->clk_25m_mask) { | |
178 | val = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG); | |
179 | if (val < 0) | |
180 | return val; | |
181 | val &= ~priv->clk_25m_mask; | |
182 | val |= priv->clk_25m_reg; | |
183 | ret = phy_write_mmd(phydev, MDIO_MMD_AN, | |
184 | AR803x_CLK_25M_SEL_REG, val); | |
185 | if (ret < 0) | |
186 | return ret; | |
187 | } | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
192 | static int ar803x_of_init(struct phy_device *phydev) | |
193 | { | |
fe6293a8 MW |
194 | struct ar803x_priv *priv; |
195 | ofnode node, vddio_reg_node; | |
196 | u32 strength, freq, min_uV, max_uV; | |
197 | int sel; | |
198 | ||
199 | node = phy_get_ofnode(phydev); | |
200 | if (!ofnode_valid(node)) | |
5faf161d | 201 | return 0; |
fe6293a8 MW |
202 | |
203 | priv = malloc(sizeof(*priv)); | |
204 | if (!priv) | |
205 | return -ENOMEM; | |
206 | memset(priv, 0, sizeof(*priv)); | |
207 | ||
208 | phydev->priv = priv; | |
209 | ||
210 | debug("%s: found PHY node: %s\n", __func__, ofnode_get_name(node)); | |
211 | ||
212 | if (ofnode_read_bool(node, "qca,keep-pll-enabled")) | |
213 | priv->flags |= AR803x_FLAG_KEEP_PLL_ENABLED; | |
214 | ||
215 | /* | |
216 | * We can't use the regulator framework because the regulator is | |
217 | * a subnode of the PHY. So just read the two properties we are | |
218 | * interested in. | |
219 | */ | |
220 | vddio_reg_node = ofnode_find_subnode(node, "vddio-regulator"); | |
221 | if (ofnode_valid(vddio_reg_node)) { | |
222 | min_uV = ofnode_read_u32_default(vddio_reg_node, | |
223 | "regulator-min-microvolt", 0); | |
224 | max_uV = ofnode_read_u32_default(vddio_reg_node, | |
225 | "regulator-max-microvolt", 0); | |
226 | ||
227 | if (min_uV != max_uV) { | |
228 | free(priv); | |
229 | return -EINVAL; | |
230 | } | |
231 | ||
232 | switch (min_uV) { | |
233 | case 1500000: | |
234 | break; | |
235 | case 1800000: | |
236 | priv->flags |= AR803x_FLAG_RGMII_1V8; | |
237 | break; | |
238 | default: | |
239 | free(priv); | |
240 | return -EINVAL; | |
241 | } | |
242 | } | |
243 | ||
244 | /* | |
245 | * Get the CLK_25M frequency from the device tree. Only XTAL and PLL | |
246 | * sources are supported right now. There is also the possibilty to use | |
247 | * the DSP as frequency reference, this is used for synchronous | |
248 | * ethernet. | |
249 | */ | |
250 | if (!ofnode_read_u32(node, "qca,clk-out-frequency", &freq)) { | |
251 | switch (freq) { | |
252 | case 25000000: | |
253 | sel = AR803x_CLK_25M_25MHZ_XTAL; | |
254 | break; | |
255 | case 50000000: | |
256 | sel = AR803x_CLK_25M_50MHZ_PLL; | |
257 | break; | |
258 | case 62500000: | |
259 | sel = AR803x_CLK_25M_62_5MHZ_PLL; | |
260 | break; | |
261 | case 125000000: | |
262 | sel = AR803x_CLK_25M_125MHZ_PLL; | |
263 | break; | |
264 | default: | |
265 | dev_err(phydev->dev, | |
266 | "invalid qca,clk-out-frequency\n"); | |
267 | free(priv); | |
268 | return -EINVAL; | |
269 | } | |
270 | ||
271 | priv->clk_25m_mask |= AR803x_CLK_25M_MASK; | |
272 | priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_MASK, sel); | |
273 | /* | |
274 | * Fixup for the AR8035 which only has two bits. The two | |
275 | * remaining bits map to the same frequencies. | |
276 | */ | |
fe6293a8 | 277 | |
338d9b03 FE |
278 | if (phydev->drv->uid == AR8035_PHY_ID) { |
279 | priv->clk_25m_reg &= AR8035_CLK_25M_MASK; | |
280 | priv->clk_25m_mask &= AR8035_CLK_25M_MASK; | |
fe6293a8 MW |
281 | } |
282 | } | |
283 | ||
284 | if (phydev->drv->uid == AR8031_PHY_ID && | |
285 | !ofnode_read_u32(node, "qca,clk-out-strength", &strength)) { | |
286 | switch (strength) { | |
287 | case AR803X_STRENGTH_FULL: | |
288 | sel = AR803x_CLK_25M_DR_FULL; | |
289 | break; | |
290 | case AR803X_STRENGTH_HALF: | |
291 | sel = AR803x_CLK_25M_DR_HALF; | |
292 | break; | |
293 | case AR803X_STRENGTH_QUARTER: | |
294 | sel = AR803x_CLK_25M_DR_QUARTER; | |
295 | break; | |
296 | default: | |
297 | dev_err(phydev->dev, | |
298 | "invalid qca,clk-out-strength\n"); | |
299 | free(priv); | |
300 | return -EINVAL; | |
301 | } | |
302 | priv->clk_25m_mask |= AR803x_CLK_25M_DR_MASK; | |
303 | priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_DR_MASK, sel); | |
304 | } | |
305 | ||
306 | debug("%s: flags=%x clk_25m_reg=%04x clk_25m_mask=%04x\n", __func__, | |
307 | priv->flags, priv->clk_25m_reg, priv->clk_25m_mask); | |
fe6293a8 MW |
308 | |
309 | return 0; | |
310 | } | |
311 | ||
8737c65f | 312 | static int ar803x_config(struct phy_device *phydev) |
6027384a | 313 | { |
2b772155 | 314 | int ret; |
6027384a | 315 | |
fe6293a8 MW |
316 | ret = ar803x_of_init(phydev); |
317 | if (ret < 0) | |
318 | return ret; | |
319 | ||
2b772155 MW |
320 | ret = ar803x_delay_config(phydev); |
321 | if (ret < 0) | |
322 | return ret; | |
2ec4d10b | 323 | |
fe6293a8 MW |
324 | ret = ar803x_regs_config(phydev); |
325 | if (ret < 0) | |
326 | return ret; | |
327 | ||
02aa4c53 | 328 | phydev->supported = phydev->drv->features; |
6027384a | 329 | |
903d384d AW |
330 | genphy_config_aneg(phydev); |
331 | genphy_restart_aneg(phydev); | |
332 | ||
6027384a XX |
333 | return 0; |
334 | } | |
335 | ||
fba31ab9 | 336 | U_BOOT_PHY_DRIVER(AR8021) = { |
9082eeac | 337 | .name = "AR8021", |
30e31931 | 338 | .uid = AR8021_PHY_ID, |
f4d48f43 | 339 | .mask = 0xfffffff0, |
9082eeac AF |
340 | .features = PHY_GBIT_FEATURES, |
341 | .config = ar8021_config, | |
342 | .startup = genphy_startup, | |
343 | .shutdown = genphy_shutdown, | |
344 | }; | |
345 | ||
fba31ab9 | 346 | U_BOOT_PHY_DRIVER(AR8031) = { |
626ee1e3 | 347 | .name = "AR8031/AR8033", |
30e31931 | 348 | .uid = AR8031_PHY_ID, |
f66e3ded | 349 | .mask = 0xffffffef, |
433a2c53 | 350 | .features = PHY_GBIT_FEATURES, |
8737c65f | 351 | .config = ar803x_config, |
433a2c53 HS |
352 | .startup = genphy_startup, |
353 | .shutdown = genphy_shutdown, | |
354 | }; | |
355 | ||
fba31ab9 | 356 | U_BOOT_PHY_DRIVER(AR8035) = { |
6027384a | 357 | .name = "AR8035", |
30e31931 | 358 | .uid = AR8035_PHY_ID, |
f66e3ded | 359 | .mask = 0xffffffef, |
6027384a | 360 | .features = PHY_GBIT_FEATURES, |
8737c65f | 361 | .config = ar803x_config, |
6027384a XX |
362 | .startup = genphy_startup, |
363 | .shutdown = genphy_shutdown, | |
364 | }; |