blob: 61525f68c359eb43bbe31054a29033d98278c926 [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 */
9#include <phy.h>
Michael Walle5d0ea112020-05-07 00:11:57 +020010#include <dm/device_compat.h>
11#include <linux/bitfield.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060012#include <linux/bitops.h>
Michael Walle5d0ea112020-05-07 00:11:57 +020013#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{
Michael Walle5d0ea112020-05-07 00:11:57 +0200193 struct ar803x_priv *priv;
194 ofnode node, vddio_reg_node;
195 u32 strength, freq, min_uV, max_uV;
196 int sel;
197
198 node = phy_get_ofnode(phydev);
199 if (!ofnode_valid(node))
Vladimir Oltean6903d4b2022-02-23 15:20:56 +0200200 return 0;
Michael Walle5d0ea112020-05-07 00:11:57 +0200201
202 priv = malloc(sizeof(*priv));
203 if (!priv)
204 return -ENOMEM;
205 memset(priv, 0, sizeof(*priv));
206
207 phydev->priv = priv;
208
209 debug("%s: found PHY node: %s\n", __func__, ofnode_get_name(node));
210
211 if (ofnode_read_bool(node, "qca,keep-pll-enabled"))
212 priv->flags |= AR803x_FLAG_KEEP_PLL_ENABLED;
213
214 /*
215 * We can't use the regulator framework because the regulator is
216 * a subnode of the PHY. So just read the two properties we are
217 * interested in.
218 */
219 vddio_reg_node = ofnode_find_subnode(node, "vddio-regulator");
220 if (ofnode_valid(vddio_reg_node)) {
221 min_uV = ofnode_read_u32_default(vddio_reg_node,
222 "regulator-min-microvolt", 0);
223 max_uV = ofnode_read_u32_default(vddio_reg_node,
224 "regulator-max-microvolt", 0);
225
226 if (min_uV != max_uV) {
227 free(priv);
228 return -EINVAL;
229 }
230
231 switch (min_uV) {
232 case 1500000:
233 break;
234 case 1800000:
235 priv->flags |= AR803x_FLAG_RGMII_1V8;
236 break;
237 default:
238 free(priv);
239 return -EINVAL;
240 }
241 }
242
243 /*
244 * Get the CLK_25M frequency from the device tree. Only XTAL and PLL
245 * sources are supported right now. There is also the possibilty to use
246 * the DSP as frequency reference, this is used for synchronous
247 * ethernet.
248 */
249 if (!ofnode_read_u32(node, "qca,clk-out-frequency", &freq)) {
250 switch (freq) {
251 case 25000000:
252 sel = AR803x_CLK_25M_25MHZ_XTAL;
253 break;
254 case 50000000:
255 sel = AR803x_CLK_25M_50MHZ_PLL;
256 break;
257 case 62500000:
258 sel = AR803x_CLK_25M_62_5MHZ_PLL;
259 break;
260 case 125000000:
261 sel = AR803x_CLK_25M_125MHZ_PLL;
262 break;
263 default:
264 dev_err(phydev->dev,
265 "invalid qca,clk-out-frequency\n");
266 free(priv);
267 return -EINVAL;
268 }
269
270 priv->clk_25m_mask |= AR803x_CLK_25M_MASK;
271 priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_MASK, sel);
272 /*
273 * Fixup for the AR8035 which only has two bits. The two
274 * remaining bits map to the same frequencies.
275 */
Michael Walle5d0ea112020-05-07 00:11:57 +0200276
Fabio Estevam8b10c002020-06-18 20:21:17 -0300277 if (phydev->drv->uid == AR8035_PHY_ID) {
278 priv->clk_25m_reg &= AR8035_CLK_25M_MASK;
279 priv->clk_25m_mask &= AR8035_CLK_25M_MASK;
Michael Walle5d0ea112020-05-07 00:11:57 +0200280 }
281 }
282
283 if (phydev->drv->uid == AR8031_PHY_ID &&
284 !ofnode_read_u32(node, "qca,clk-out-strength", &strength)) {
285 switch (strength) {
286 case AR803X_STRENGTH_FULL:
287 sel = AR803x_CLK_25M_DR_FULL;
288 break;
289 case AR803X_STRENGTH_HALF:
290 sel = AR803x_CLK_25M_DR_HALF;
291 break;
292 case AR803X_STRENGTH_QUARTER:
293 sel = AR803x_CLK_25M_DR_QUARTER;
294 break;
295 default:
296 dev_err(phydev->dev,
297 "invalid qca,clk-out-strength\n");
298 free(priv);
299 return -EINVAL;
300 }
301 priv->clk_25m_mask |= AR803x_CLK_25M_DR_MASK;
302 priv->clk_25m_reg |= FIELD_PREP(AR803x_CLK_25M_DR_MASK, sel);
303 }
304
305 debug("%s: flags=%x clk_25m_reg=%04x clk_25m_mask=%04x\n", __func__,
306 priv->flags, priv->clk_25m_reg, priv->clk_25m_mask);
Michael Walle5d0ea112020-05-07 00:11:57 +0200307
308 return 0;
309}
310
Michael Walleb032d892020-05-07 00:11:59 +0200311static int ar803x_config(struct phy_device *phydev)
Michael Walle376019a2020-05-07 00:11:56 +0200312{
313 int ret;
314
Michael Walle5d0ea112020-05-07 00:11:57 +0200315 ret = ar803x_of_init(phydev);
316 if (ret < 0)
317 return ret;
318
Michael Walle376019a2020-05-07 00:11:56 +0200319 ret = ar803x_delay_config(phydev);
320 if (ret < 0)
321 return ret;
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530322
Michael Walle5d0ea112020-05-07 00:11:57 +0200323 ret = ar803x_regs_config(phydev);
324 if (ret < 0)
325 return ret;
326
Mugunthan V N3e4537d2016-10-13 19:33:36 +0530327 phydev->supported = phydev->drv->features;
328
329 genphy_config_aneg(phydev);
330 genphy_restart_aneg(phydev);
331
Andy Fleming60ca78b2011-04-07 21:56:05 -0500332 return 0;
333}
334
Marek Vasutcb637972023-03-19 18:02:45 +0100335U_BOOT_PHY_DRIVER(AR8021) = {
Andy Fleming60ca78b2011-04-07 21:56:05 -0500336 .name = "AR8021",
Michael Walle69a107e2020-05-07 00:11:54 +0200337 .uid = AR8021_PHY_ID,
Michael Wallea5eb6592020-05-07 00:11:53 +0200338 .mask = 0xfffffff0,
Andy Fleming60ca78b2011-04-07 21:56:05 -0500339 .features = PHY_GBIT_FEATURES,
340 .config = ar8021_config,
341 .startup = genphy_startup,
342 .shutdown = genphy_shutdown,
343};
344
Marek Vasutcb637972023-03-19 18:02:45 +0100345U_BOOT_PHY_DRIVER(AR8031) = {
Shengzhou Liu76f57c32013-08-08 16:33:35 +0800346 .name = "AR8031/AR8033",
Michael Walle69a107e2020-05-07 00:11:54 +0200347 .uid = AR8031_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200348 .mask = 0xffffffef,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200349 .features = PHY_GBIT_FEATURES,
Michael Walleb032d892020-05-07 00:11:59 +0200350 .config = ar803x_config,
Heiko Schocher93ac9b82013-06-04 10:58:00 +0200351 .startup = genphy_startup,
352 .shutdown = genphy_shutdown,
353};
354
Marek Vasutcb637972023-03-19 18:02:45 +0100355U_BOOT_PHY_DRIVER(AR8035) = {
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800356 .name = "AR8035",
Michael Walle69a107e2020-05-07 00:11:54 +0200357 .uid = AR8035_PHY_ID,
Fabio Estevam2edb6062014-01-03 15:55:59 -0200358 .mask = 0xffffffef,
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800359 .features = PHY_GBIT_FEATURES,
Michael Walleb032d892020-05-07 00:11:59 +0200360 .config = ar803x_config,
Xie Xiaobodcc307e2013-04-10 16:23:39 +0800361 .startup = genphy_startup,
362 .shutdown = genphy_shutdown,
363};