blob: fa1fe08518f4baa1f7d97bc9dc36601cea6fc0e1 [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>
Simon Glass4dcacfc2020-05-10 11:40:13 -060013#include <linux/bitops.h>
Michael Walle5d0ea112020-05-07 00:11:57 +020014#include <dt-bindings/net/qca-ar803x.h>
Andy Fleming60ca78b2011-04-07 21:56:05 -050015
Mugunthan V N3e4537d2016-10-13 19:33:36 +053016#define AR803x_PHY_DEBUG_ADDR_REG 0x1d
17#define AR803x_PHY_DEBUG_DATA_REG 0x1e
18
Michael Walle5d0ea112020-05-07 00:11:57 +020019/* Debug registers */
20#define AR803x_DEBUG_REG_0 0x0
21#define AR803x_RGMII_RX_CLK_DLY BIT(15)
22
Mugunthan V N3e4537d2016-10-13 19:33:36 +053023#define AR803x_DEBUG_REG_5 0x5
Vladimir Oltean23d8b892020-05-07 00:11:49 +020024#define AR803x_RGMII_TX_CLK_DLY BIT(8)
Mugunthan V N3e4537d2016-10-13 19:33:36 +053025
Michael Walle5d0ea112020-05-07 00:11:57 +020026#define AR803x_DEBUG_REG_1F 0x1f
27#define AR803x_PLL_ON BIT(2)
28#define AR803x_RGMII_1V8 BIT(3)
Vladimir Oltean23d8b892020-05-07 00:11:49 +020029
Vladimir Oltean3e7330e2020-05-07 00:11:50 +020030/* CLK_25M register is at MMD 7, address 0x8016 */
31#define AR803x_CLK_25M_SEL_REG 0x8016
Michael Walle5d0ea112020-05-07 00:11:57 +020032
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
Vladimir Oltean3e7330e2020-05-07 00:11:50 +020042#define AR8035_CLK_25M_MASK GENMASK(4, 3)
43
Michael Walle5d0ea112020-05-07 00:11:57 +020044#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
Michael Walle69a107e2020-05-07 00:11:54 +020049#define AR8021_PHY_ID 0x004dd040
50#define AR8031_PHY_ID 0x004dd074
51#define AR8035_PHY_ID 0x004dd072
52
Michael Walle5d0ea112020-05-07 00:11:57 +020053struct 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
Michael Wallefb4a4652020-05-07 00:11:55 +020061static int ar803x_debug_reg_read(struct phy_device *phydev, u16 reg)
Vladimir Oltean23d8b892020-05-07 00:11:49 +020062{
Michael Wallefb4a4652020-05-07 00:11:55 +020063 int ret;
Vladimir Oltean23d8b892020-05-07 00:11:49 +020064
Michael Wallefb4a4652020-05-07 00:11:55 +020065 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
73static 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
90static int ar803x_enable_rx_delay(struct phy_device *phydev, bool on)
91{
92 u16 clear = 0, set = 0;
93
Vladimir Oltean23d8b892020-05-07 00:11:49 +020094 if (on)
Michael Wallefb4a4652020-05-07 00:11:55 +020095 set = AR803x_RGMII_RX_CLK_DLY;
Vladimir Oltean23d8b892020-05-07 00:11:49 +020096 else
Michael Wallefb4a4652020-05-07 00:11:55 +020097 clear = AR803x_RGMII_RX_CLK_DLY;
98
99 return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_0, clear, set);
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200100}
101
Michael Wallefb4a4652020-05-07 00:11:55 +0200102static int ar803x_enable_tx_delay(struct phy_device *phydev, bool on)
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200103{
Michael Wallefb4a4652020-05-07 00:11:55 +0200104 u16 clear = 0, set = 0;
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200105
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200106 if (on)
Michael Wallefb4a4652020-05-07 00:11:55 +0200107 set = AR803x_RGMII_TX_CLK_DLY;
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200108 else
Michael Wallefb4a4652020-05-07 00:11:55 +0200109 clear = AR803x_RGMII_TX_CLK_DLY;
110
111 return ar803x_debug_reg_mask(phydev, AR803x_DEBUG_REG_5, clear, set);
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200112}
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530113
Andy Fleming60ca78b2011-04-07 21:56:05 -0500114static int ar8021_config(struct phy_device *phydev)
115{
Vladimir Oltean1e37f752020-05-07 00:11:52 +0200116 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR,
117 BMCR_ANENABLE | BMCR_ANRESTART);
118
119 ar803x_enable_tx_delay(phydev, true);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500120
Zhao Qiang04f2ba42013-12-23 15:51:33 +0800121 phydev->supported = phydev->drv->features;
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530122 return 0;
123}
124
Michael Walle376019a2020-05-07 00:11:56 +0200125static int ar803x_delay_config(struct phy_device *phydev)
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530126{
Michael Walle376019a2020-05-07 00:11:56 +0200127 int ret;
128
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530129 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200130 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Michael Walle376019a2020-05-07 00:11:56 +0200131 ret = ar803x_enable_tx_delay(phydev, true);
Vladimir Oltean3ccbb4b2020-05-07 00:11:51 +0200132 else
Michael Walle376019a2020-05-07 00:11:56 +0200133 ret = ar803x_enable_tx_delay(phydev, false);
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530134
135 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
Vladimir Oltean23d8b892020-05-07 00:11:49 +0200136 phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
Michael Walle376019a2020-05-07 00:11:56 +0200137 ret = ar803x_enable_rx_delay(phydev, true);
Vladimir Oltean3ccbb4b2020-05-07 00:11:51 +0200138 else
Michael Walle376019a2020-05-07 00:11:56 +0200139 ret = ar803x_enable_rx_delay(phydev, false);
140
141 return ret;
142}
143
Michael Walle5d0ea112020-05-07 00:11:57 +0200144static 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
192static int ar803x_of_init(struct phy_device *phydev)
193{
194#if defined(CONFIG_DM_ETH)
195 struct ar803x_priv *priv;
196 ofnode node, vddio_reg_node;
197 u32 strength, freq, min_uV, max_uV;
198 int sel;
199
200 node = phy_get_ofnode(phydev);
201 if (!ofnode_valid(node))
Vladimir Oltean6903d4b2022-02-23 15:20:56 +0200202 return 0;
Michael Walle5d0ea112020-05-07 00:11:57 +0200203
204 priv = malloc(sizeof(*priv));
205 if (!priv)
206 return -ENOMEM;
207 memset(priv, 0, sizeof(*priv));
208
209 phydev->priv = priv;
210
211 debug("%s: found PHY node: %s\n", __func__, ofnode_get_name(node));
212
213 if (ofnode_read_bool(node, "qca,keep-pll-enabled"))
214 priv->flags |= AR803x_FLAG_KEEP_PLL_ENABLED;
215
216 /*
217 * We can't use the regulator framework because the regulator is
218 * a subnode of the PHY. So just read the two properties we are
219 * interested in.
220 */
221 vddio_reg_node = ofnode_find_subnode(node, "vddio-regulator");
222 if (ofnode_valid(vddio_reg_node)) {
223 min_uV = ofnode_read_u32_default(vddio_reg_node,
224 "regulator-min-microvolt", 0);
225 max_uV = ofnode_read_u32_default(vddio_reg_node,
226 "regulator-max-microvolt", 0);
227
228 if (min_uV != max_uV) {
229 free(priv);
230 return -EINVAL;
231 }
232
233 switch (min_uV) {
234 case 1500000:
235 break;
236 case 1800000:
237 priv->flags |= AR803x_FLAG_RGMII_1V8;
238 break;
239 default:
240 free(priv);
241 return -EINVAL;
242 }
243 }
244
245 /*
246 * Get the CLK_25M frequency from the device tree. Only XTAL and PLL
247 * sources are supported right now. There is also the possibilty to use
248 * the DSP as frequency reference, this is used for synchronous
249 * ethernet.
250 */
251 if (!ofnode_read_u32(node, "qca,clk-out-frequency", &freq)) {
252 switch (freq) {
253 case 25000000:
254 sel = AR803x_CLK_25M_25MHZ_XTAL;
255 break;
256 case 50000000:
257 sel = AR803x_CLK_25M_50MHZ_PLL;
258 break;
259 case 62500000:
260 sel = AR803x_CLK_25M_62_5MHZ_PLL;
261 break;
262 case 125000000:
263 sel = AR803x_CLK_25M_125MHZ_PLL;
264 break;
265 default:
266 dev_err(phydev->dev,
267 "invalid qca,clk-out-frequency\n");
268 free(priv);
269 return -EINVAL;
270 }
271
272 priv->clk_25m_mask |= AR803x_CLK_25M_MASK;
273 priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_MASK, sel);
274 /*
275 * Fixup for the AR8035 which only has two bits. The two
276 * remaining bits map to the same frequencies.
277 */
Michael Walle5d0ea112020-05-07 00:11:57 +0200278
Fabio Estevam8b10c002020-06-18 20:21:17 -0300279 if (phydev->drv->uid == AR8035_PHY_ID) {
280 priv->clk_25m_reg &= AR8035_CLK_25M_MASK;
281 priv->clk_25m_mask &= AR8035_CLK_25M_MASK;
Michael Walle5d0ea112020-05-07 00:11:57 +0200282 }
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 Walleb032d892020-05-07 00:11:59 +0200314static int ar803x_config(struct phy_device *phydev)
Michael Walle376019a2020-05-07 00:11:56 +0200315{
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
Kim Phillips40c2c032012-10-29 13:34:33 +0000338static struct phy_driver AR8021_driver = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500339 .name = "AR8021",
Michael Walle69a107e2020-05-07 00:11:54 +0200340 .uid = AR8021_PHY_ID,
Michael Wallea5eb6592020-05-07 00:11:53 +0200341 .mask = 0xfffffff0,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500342 .features = PHY_GBIT_FEATURES,
343 .config = ar8021_config,
344 .startup = genphy_startup,
345 .shutdown = genphy_shutdown,
346};
347
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200348static struct phy_driver AR8031_driver = {
Shengzhou Liu76f57c32013-08-08 16:33:35 +0800349 .name = "AR8031/AR8033",
Michael Walle69a107e2020-05-07 00:11:54 +0200350 .uid = AR8031_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200351 .mask = 0xffffffef,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200352 .features = PHY_GBIT_FEATURES,
Michael Walleb032d892020-05-07 00:11:59 +0200353 .config = ar803x_config,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200354 .startup = genphy_startup,
355 .shutdown = genphy_shutdown,
356};
357
358static struct phy_driver AR8035_driver = {
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800359 .name = "AR8035",
Michael Walle69a107e2020-05-07 00:11:54 +0200360 .uid = AR8035_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200361 .mask = 0xffffffef,
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800362 .features = PHY_GBIT_FEATURES,
Michael Walleb032d892020-05-07 00:11:59 +0200363 .config = ar803x_config,
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800364 .startup = genphy_startup,
365 .shutdown = genphy_shutdown,
366};
367
Andy Fleming60ca78b2011-04-07 21:56:05 -0500368int phy_atheros_init(void)
369{
370 phy_register(&AR8021_driver);
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200371 phy_register(&AR8031_driver);
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800372 phy_register(&AR8035_driver);
Andy Fleming60ca78b2011-04-07 21:56:05 -0500373
374 return 0;
375}