blob: 314273310520ce6cb25b0eb53bb4fdbcc958a049 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Andy Fleming60ca78b2011-04-07 21:56:05 -05002/*
3 * Atheros PHY drivers
4 *
Xie Xiaobodcc307e2013-04-10 16:23:39 +08005 * Copyright 2011, 2013 Freescale Semiconductor, Inc.
Andy Fleming60ca78b2011-04-07 21:56:05 -05006 * author Andy Fleming
Michael Walle5d0ea112020-05-07 00:11:57 +02007 * Copyright (c) 2019 Michael Walle <michael@walle.cc>
Andy Fleming60ca78b2011-04-07 21:56:05 -05008 */
Joe Hershberger14b48122018-07-25 12:59:22 -05009#include <common.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050010#include <phy.h>
Michael Walle5d0ea112020-05-07 00:11:57 +020011#include <dm/device_compat.h>
12#include <linux/bitfield.h>
13#include <dt-bindings/net/qca-ar803x.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050014
Mugunthan V N3e4537d2016-10-13 19:33:36 +053015#define AR803x_PHY_DEBUG_ADDR_REG 0x1d
16#define AR803x_PHY_DEBUG_DATA_REG 0x1e
17
Michael Walle5d0ea112020-05-07 00:11:57 +020018/* Debug registers */
19#define AR803x_DEBUG_REG_0 0x0
20#define AR803x_RGMII_RX_CLK_DLY BIT(15)
21
Mugunthan V N3e4537d2016-10-13 19:33:36 +053022#define AR803x_DEBUG_REG_5 0x5
Vladimir Oltean23d8b892020-05-07 00:11:49 +020023#define AR803x_RGMII_TX_CLK_DLY BIT(8)
Mugunthan V N3e4537d2016-10-13 19:33:36 +053024
Michael Walle5d0ea112020-05-07 00:11:57 +020025#define AR803x_DEBUG_REG_1F 0x1f
26#define AR803x_PLL_ON BIT(2)
27#define AR803x_RGMII_1V8 BIT(3)
Vladimir Oltean23d8b892020-05-07 00:11:49 +020028
Vladimir Oltean3e7330e2020-05-07 00:11:50 +020029/* CLK_25M register is at MMD 7, address 0x8016 */
30#define AR803x_CLK_25M_SEL_REG 0x8016
Michael Walle5d0ea112020-05-07 00:11:57 +020031
32#define AR803x_CLK_25M_MASK GENMASK(4, 2)
33#define AR803x_CLK_25M_25MHZ_XTAL 0
34#define AR803x_CLK_25M_25MHZ_DSP 1
35#define AR803x_CLK_25M_50MHZ_PLL 2
36#define AR803x_CLK_25M_50MHZ_DSP 3
37#define AR803x_CLK_25M_62_5MHZ_PLL 4
38#define AR803x_CLK_25M_62_5MHZ_DSP 5
39#define AR803x_CLK_25M_125MHZ_PLL 6
40#define AR803x_CLK_25M_125MHZ_DSP 7
Vladimir Oltean3e7330e2020-05-07 00:11:50 +020041#define AR8035_CLK_25M_MASK GENMASK(4, 3)
42
Michael Walle5d0ea112020-05-07 00:11:57 +020043#define AR803x_CLK_25M_DR_MASK GENMASK(8, 7)
44#define AR803x_CLK_25M_DR_FULL 0
45#define AR803x_CLK_25M_DR_HALF 1
46#define AR803x_CLK_25M_DR_QUARTER 2
47
Michael Walle69a107e2020-05-07 00:11:54 +020048#define AR8021_PHY_ID 0x004dd040
49#define AR8031_PHY_ID 0x004dd074
50#define AR8035_PHY_ID 0x004dd072
51
Michael Walle5d0ea112020-05-07 00:11:57 +020052struct ar803x_priv {
53 int flags;
54#define AR803x_FLAG_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */
55#define AR803x_FLAG_RGMII_1V8 BIT(1) /* use 1.8V RGMII I/O voltage */
56 u16 clk_25m_reg;
57 u16 clk_25m_mask;
58};
59
Michael Wallefb4a4652020-05-07 00:11:55 +020060static int ar803x_debug_reg_read(struct phy_device *phydev, u16 reg)
Vladimir Oltean23d8b892020-05-07 00:11:49 +020061{
Michael Wallefb4a4652020-05-07 00:11:55 +020062 int ret;
Vladimir Oltean23d8b892020-05-07 00:11:49 +020063
Michael Wallefb4a4652020-05-07 00:11:55 +020064 ret = phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG,
65 reg);
66 if (ret < 0)
67 return ret;
68
69 return phy_read(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG);
70}
71
72static int ar803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
73 u16 clear, u16 set)
74{
75 int val;
76
77 val = ar803x_debug_reg_read(phydev, reg);
78 if (val < 0)
79 return val;
80
81 val &= 0xffff;
82 val &= ~clear;
83 val |= set;
84
85 return phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG,
86 val);
87}
88
89static int ar803x_enable_rx_delay(struct phy_device *phydev, bool on)
90{
91 u16 clear = 0, set = 0;
92
Vladimir Oltean23d8b892020-05-07 00:11:49 +020093 if (on)
Michael Wallefb4a4652020-05-07 00:11:55 +020094 set = AR803x_RGMII_RX_CLK_DLY;
Vladimir Oltean23d8b892020-05-07 00:11:49 +020095 else
Michael Wallefb4a4652020-05-07 00:11:55 +020096 clear = AR803x_RGMII_RX_CLK_DLY;
97
98 return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_0, clear, set);
Vladimir Oltean23d8b892020-05-07 00:11:49 +020099}
100
Michael Wallefb4a4652020-05-07 00:11:55 +0200101static int ar803x_enable_tx_delay(struct phy_device *phydev, bool on)
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200102{
Michael Wallefb4a4652020-05-07 00:11:55 +0200103 u16 clear = 0, set = 0;
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200104
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200105 if (on)
Michael Wallefb4a4652020-05-07 00:11:55 +0200106 set = AR803x_RGMII_TX_CLK_DLY;
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200107 else
Michael Wallefb4a4652020-05-07 00:11:55 +0200108 clear = AR803x_RGMII_TX_CLK_DLY;
109
110 return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_5, clear, set);
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200111}
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530112
Andy Fleming60ca78b2011-04-07 21:56:05 -0500113static int ar8021_config(struct phy_device *phydev)
114{
Vladimir Oltean1e37f752020-05-07 00:11:52 +0200115 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
116 BMCR_ANENABLE | BMCR_ANRESTART);
117
118 ar803x_enable_tx_delay(phydev, true);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500119
Zhao Qiang04f2ba42013-12-23 15:51:33 +0800120 phydev->supported = phydev->drv->features;
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530121 return 0;
122}
123
Michael Walle376019a2020-05-07 00:11:56 +0200124static int ar803x_delay_config(struct phy_device *phydev)
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530125{
Michael Walle376019a2020-05-07 00:11:56 +0200126 int ret;
127
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530128 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200129 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Michael Walle376019a2020-05-07 00:11:56 +0200130 ret = ar803x_enable_tx_delay(phydev, true);
Vladimir Oltean3ccbb4b2020-05-07 00:11:51 +0200131 else
Michael Walle376019a2020-05-07 00:11:56 +0200132 ret = ar803x_enable_tx_delay(phydev, false);
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530133
134 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200135 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Michael Walle376019a2020-05-07 00:11:56 +0200136 ret = ar803x_enable_rx_delay(phydev, true);
Vladimir Oltean3ccbb4b2020-05-07 00:11:51 +0200137 else
Michael Walle376019a2020-05-07 00:11:56 +0200138 ret = ar803x_enable_rx_delay(phydev, false);
139
140 return ret;
141}
142
Michael Walle5d0ea112020-05-07 00:11:57 +0200143static int ar803x_regs_config(struct phy_device *phydev)
144{
145 struct ar803x_priv *priv = phydev->priv;
146 u16 set = 0, clear = 0;
147 int val;
148 int ret;
149
150 /* no configuration available */
151 if (!priv)
152 return 0;
153
154 /*
155 * Only supported on the AR8031, AR8035 has strappings for the PLL mode
156 * as well as the RGMII voltage.
157 */
158 if (phydev->drv->uid == AR8031_PHY_ID) {
159 if (priv->flags & AR803x_FLAG_KEEP_PLL_ENABLED)
160 set |= AR803x_PLL_ON;
161 else
162 clear |= AR803x_PLL_ON;
163
164 if (priv->flags & AR803x_FLAG_RGMII_1V8)
165 set |= AR803x_RGMII_1V8;
166 else
167 clear |= AR803x_RGMII_1V8;
168
169 ret = ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_1F, clear,
170 set);
171 if (ret < 0)
172 return ret;
173 }
174
175 /* save the write access if the mask is empty */
176 if (priv->clk_25m_mask) {
177 val = phy_read_mmd(phydev, MDIO_MMD_AN, AR803x_CLK_25M_SEL_REG);
178 if (val < 0)
179 return val;
180 val &= ~priv->clk_25m_mask;
181 val |= priv->clk_25m_reg;
182 ret = phy_write_mmd(phydev, MDIO_MMD_AN,
183 AR803x_CLK_25M_SEL_REG, val);
184 if (ret < 0)
185 return ret;
186 }
187
188 return 0;
189}
190
191static int ar803x_of_init(struct phy_device *phydev)
192{
193#if defined(CONFIG_DM_ETH)
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))
201 return -EINVAL;
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 */
277 if (phydev->drv->uid == AR8035_PHY_ID) {
278 u16 clear = AR803x_CLK_25M_MASK & AR8035_CLK_25M_MASK;
279
280 priv->clk_25m_mask &= ~clear;
281 priv->clk_25m_reg &= ~clear;
282 }
283 }
284
285 if (phydev->drv->uid == AR8031_PHY_ID &&
286 !ofnode_read_u32(node, "qca,clk-out-strength", &strength)) {
287 switch (strength) {
288 case AR803X_STRENGTH_FULL:
289 sel = AR803x_CLK_25M_DR_FULL;
290 break;
291 case AR803X_STRENGTH_HALF:
292 sel = AR803x_CLK_25M_DR_HALF;
293 break;
294 case AR803X_STRENGTH_QUARTER:
295 sel = AR803x_CLK_25M_DR_QUARTER;
296 break;
297 default:
298 dev_err(phydev->dev,
299 "invalid qca,clk-out-strength\n");
300 free(priv);
301 return -EINVAL;
302 }
303 priv->clk_25m_mask |= AR803x_CLK_25M_DR_MASK;
304 priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_DR_MASK, sel);
305 }
306
307 debug("%s: flags=%x clk_25m_reg=%04x clk_25m_mask=%04x\n", __func__,
308 priv->flags, priv->clk_25m_reg, priv->clk_25m_mask);
309#endif
310
311 return 0;
312}
313
Michael Walle376019a2020-05-07 00:11:56 +0200314static int ar8031_config(struct phy_device *phydev)
315{
316 int ret;
317
Michael Walle5d0ea112020-05-07 00:11:57 +0200318 ret = ar803x_of_init(phydev);
319 if (ret < 0)
320 return ret;
321
Michael Walle376019a2020-05-07 00:11:56 +0200322 ret = ar803x_delay_config(phydev);
323 if (ret < 0)
324 return ret;
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530325
Michael Walle5d0ea112020-05-07 00:11:57 +0200326 ret = ar803x_regs_config(phydev);
327 if (ret < 0)
328 return ret;
329
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530330 phydev->supported = phydev->drv->features;
331
332 genphy_config_aneg(phydev);
333 genphy_restart_aneg(phydev);
334
Andy Fleming60ca78b2011-04-07 21:56:05 -0500335 return 0;
336}
337
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800338static int ar8035_config(struct phy_device *phydev)
339{
Michael Walle376019a2020-05-07 00:11:56 +0200340 int ret;
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800341
Michael Walle5d0ea112020-05-07 00:11:57 +0200342 ret = ar803x_of_init(phydev);
343 if (ret < 0)
344 return ret;
345
Michael Walle376019a2020-05-07 00:11:56 +0200346 ret = ar803x_delay_config(phydev);
347 if (ret < 0)
348 return ret;
Andrea Merello1e3e19f2016-05-26 18:24:28 +0200349
Michael Walle5d0ea112020-05-07 00:11:57 +0200350 ret = ar803x_regs_config(phydev);
351 if (ret < 0)
352 return ret;
353
Xiaobo Xieaa09e682014-04-11 16:03:11 +0800354 phydev->supported = phydev->drv->features;
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800355
Alison Wang5dc3af82016-02-19 15:52:28 +0800356 genphy_config_aneg(phydev);
357 genphy_restart_aneg(phydev);
358
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800359 return 0;
360}
361
Kim Phillips40c2c032012-10-29 13:34:33 +0000362static struct phy_driver AR8021_driver = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500363 .name = "AR8021",
Michael Walle69a107e2020-05-07 00:11:54 +0200364 .uid = AR8021_PHY_ID,
Michael Wallea5eb6592020-05-07 00:11:53 +0200365 .mask = 0xfffffff0,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500366 .features = PHY_GBIT_FEATURES,
367 .config = ar8021_config,
368 .startup = genphy_startup,
369 .shutdown = genphy_shutdown,
370};
371
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200372static struct phy_driver AR8031_driver = {
Shengzhou Liu76f57c32013-08-08 16:33:35 +0800373 .name = "AR8031/AR8033",
Michael Walle69a107e2020-05-07 00:11:54 +0200374 .uid = AR8031_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200375 .mask = 0xffffffef,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200376 .features = PHY_GBIT_FEATURES,
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530377 .config = ar8031_config,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200378 .startup = genphy_startup,
379 .shutdown = genphy_shutdown,
380};
381
382static struct phy_driver AR8035_driver = {
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800383 .name = "AR8035",
Michael Walle69a107e2020-05-07 00:11:54 +0200384 .uid = AR8035_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200385 .mask = 0xffffffef,
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800386 .features = PHY_GBIT_FEATURES,
387 .config = ar8035_config,
388 .startup = genphy_startup,
389 .shutdown = genphy_shutdown,
390};
391
Andy Fleming60ca78b2011-04-07 21:56:05 -0500392int phy_atheros_init(void)
393{
394 phy_register(&AR8021_driver);
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200395 phy_register(&AR8031_driver);
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800396 phy_register(&AR8035_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500397
398 return 0;
399}