blob: ce448810ff6db27b74f5de5adc89d233c349d56f [file] [log] [blame]
Nate Drudea9521ea2022-04-08 11:28:14 -05001// SPDX-License-Identifier: GPL-2.0+
2/**
3 * Driver for Analog Devices Industrial Ethernet PHYs
4 *
5 * Copyright 2019 Analog Devices Inc.
6 * Copyright 2022 Variscite Ltd.
Josua Mayerd671dcb2022-05-19 12:31:57 +03007 * Copyright 2022 Josua Mayer <josua@solid-run.com>
Nate Drudea9521ea2022-04-08 11:28:14 -05008 */
Nate Drudea9521ea2022-04-08 11:28:14 -05009#include <phy.h>
10#include <linux/bitops.h>
11#include <linux/bitfield.h>
12
13#define PHY_ID_ADIN1300 0x0283bc30
14#define ADIN1300_EXT_REG_PTR 0x10
15#define ADIN1300_EXT_REG_DATA 0x11
Josua Mayerd671dcb2022-05-19 12:31:57 +030016
17#define ADIN1300_GE_CLK_CFG_REG 0xff1f
18#define ADIN1300_GE_CLK_CFG_MASK GENMASK(5, 0)
19#define ADIN1300_GE_CLK_CFG_RCVR_125 BIT(5)
20#define ADIN1300_GE_CLK_CFG_FREE_125 BIT(4)
21#define ADIN1300_GE_CLK_CFG_REF_EN BIT(3)
22#define ADIN1300_GE_CLK_CFG_HRT_RCVR BIT(2)
23#define ADIN1300_GE_CLK_CFG_HRT_FREE BIT(1)
24#define ADIN1300_GE_CLK_CFG_25 BIT(0)
25
Nate Drudea9521ea2022-04-08 11:28:14 -050026#define ADIN1300_GE_RGMII_CFG 0xff23
27#define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6)
28#define ADIN1300_GE_RGMII_RX_SEL(x) \
29 FIELD_PREP(ADIN1300_GE_RGMII_RX_MSK, x)
30#define ADIN1300_GE_RGMII_GTX_MSK GENMASK(5, 3)
31#define ADIN1300_GE_RGMII_GTX_SEL(x) \
32 FIELD_PREP(ADIN1300_GE_RGMII_GTX_MSK, x)
33#define ADIN1300_GE_RGMII_RXID_EN BIT(2)
34#define ADIN1300_GE_RGMII_TXID_EN BIT(1)
35#define ADIN1300_GE_RGMII_EN BIT(0)
36
37/* RGMII internal delay settings for rx and tx for ADIN1300 */
38#define ADIN1300_RGMII_1_60_NS 0x0001
39#define ADIN1300_RGMII_1_80_NS 0x0002
40#define ADIN1300_RGMII_2_00_NS 0x0000
41#define ADIN1300_RGMII_2_20_NS 0x0006
42#define ADIN1300_RGMII_2_40_NS 0x0007
43
44/**
45 * struct adin_cfg_reg_map - map a config value to aregister value
46 * @cfg value in device configuration
47 * @reg value in the register
48 */
49struct adin_cfg_reg_map {
50 int cfg;
51 int reg;
52};
53
54static const struct adin_cfg_reg_map adin_rgmii_delays[] = {
55 { 1600, ADIN1300_RGMII_1_60_NS },
56 { 1800, ADIN1300_RGMII_1_80_NS },
57 { 2000, ADIN1300_RGMII_2_00_NS },
58 { 2200, ADIN1300_RGMII_2_20_NS },
59 { 2400, ADIN1300_RGMII_2_40_NS },
60 { },
61};
62
63static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg)
64{
65 size_t i;
66
67 for (i = 0; tbl[i].cfg; i++) {
68 if (tbl[i].cfg == cfg)
69 return tbl[i].reg;
70 }
71
72 return -EINVAL;
73}
74
75static u32 adin_get_reg_value(struct phy_device *phydev,
76 const char *prop_name,
77 const struct adin_cfg_reg_map *tbl,
78 u32 dflt)
79{
80 u32 val;
81 int rc;
82
83 ofnode node = phy_get_ofnode(phydev);
84 if (!ofnode_valid(node)) {
85 printf("%s: failed to get node\n", __func__);
86 return -EINVAL;
87 }
88
89 if (ofnode_read_u32(node, prop_name, &val)) {
90 printf("%s: failed to find %s, using default %d\n",
91 __func__, prop_name, dflt);
92 return dflt;
93 }
94
95 debug("%s: %s = '%d'\n", __func__, prop_name, val);
96
97 rc = adin_lookup_reg_value(tbl, val);
98 if (rc < 0) {
99 printf("%s: Unsupported value %u for %s using default (%u)\n",
100 __func__, val, prop_name, dflt);
101 return dflt;
102 }
103
104 return rc;
105}
106
107/**
108 * adin_get_phy_mode_override - Get phy-mode override for adin PHY
109 *
110 * The function gets phy-mode string from property 'adi,phy-mode-override'
111 * and return its index in phy_interface_strings table, or -1 in error case.
112 */
Nate Drude021dacc2022-05-19 12:31:56 +0300113phy_interface_t adin_get_phy_mode_override(struct phy_device *phydev)
Nate Drudea9521ea2022-04-08 11:28:14 -0500114{
115 ofnode node = phy_get_ofnode(phydev);
116 const char *phy_mode_override;
117 const char *prop_phy_mode_override = "adi,phy-mode-override";
Nate Drude021dacc2022-05-19 12:31:56 +0300118 int i;
Nate Drudea9521ea2022-04-08 11:28:14 -0500119
120 phy_mode_override = ofnode_read_string(node, prop_phy_mode_override);
121 if (!phy_mode_override)
Nate Drude021dacc2022-05-19 12:31:56 +0300122 return PHY_INTERFACE_MODE_NA;
Nate Drudea9521ea2022-04-08 11:28:14 -0500123
124 debug("%s: %s = '%s'\n",
125 __func__, prop_phy_mode_override, phy_mode_override);
126
Nate Drude021dacc2022-05-19 12:31:56 +0300127 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
128 if (!strcmp(phy_mode_override, phy_interface_strings[i]))
129 return (phy_interface_t) i;
Nate Drudea9521ea2022-04-08 11:28:14 -0500130
Nate Drude021dacc2022-05-19 12:31:56 +0300131 printf("%s: Invalid PHY interface '%s'\n", __func__, phy_mode_override);
Nate Drudea9521ea2022-04-08 11:28:14 -0500132
Nate Drude021dacc2022-05-19 12:31:56 +0300133 return PHY_INTERFACE_MODE_NA;
Nate Drudea9521ea2022-04-08 11:28:14 -0500134}
135
136static u16 adin_ext_read(struct phy_device *phydev, const u32 regnum)
137{
138 u16 val;
139
140 phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
141 val = phy_read(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA);
142
143 debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
144
145 return val;
146}
147
148static int adin_ext_write(struct phy_device *phydev, const u32 regnum, const u16 val)
149{
150 debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
151
152 phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
153
154 return phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA, val);
155}
156
Nate Drude8b26a692023-07-11 16:59:15 -0500157static int adin_extread(struct phy_device *phydev, int addr, int devaddr,
158 int regnum)
159{
160 return adin_ext_read(phydev, regnum);
161}
162
163static int adin_extwrite(struct phy_device *phydev, int addr,
164 int devaddr, int regnum, u16 val)
165{
166 return adin_ext_write(phydev, regnum, val);
167}
168
Josua Mayerd671dcb2022-05-19 12:31:57 +0300169static int adin_config_clk_out(struct phy_device *phydev)
170{
171 ofnode node = phy_get_ofnode(phydev);
172 const char *val = NULL;
173 u8 sel = 0;
174
175 val = ofnode_read_string(node, "adi,phy-output-clock");
176 if (!val) {
177 /* property not present, do not enable GP_CLK pin */
178 } else if (strcmp(val, "25mhz-reference") == 0) {
179 sel |= ADIN1300_GE_CLK_CFG_25;
180 } else if (strcmp(val, "125mhz-free-running") == 0) {
181 sel |= ADIN1300_GE_CLK_CFG_FREE_125;
182 } else if (strcmp(val, "adaptive-free-running") == 0) {
183 sel |= ADIN1300_GE_CLK_CFG_HRT_FREE;
184 } else {
185 pr_err("%s: invalid adi,phy-output-clock\n", __func__);
186 return -EINVAL;
187 }
188
189 if (ofnode_read_bool(node, "adi,phy-output-reference-clock"))
190 sel |= ADIN1300_GE_CLK_CFG_REF_EN;
191
192 return adin_ext_write(phydev, ADIN1300_GE_CLK_CFG_REG,
193 ADIN1300_GE_CLK_CFG_MASK & sel);
194}
195
Nate Drudea9521ea2022-04-08 11:28:14 -0500196static int adin_config_rgmii_mode(struct phy_device *phydev)
197{
198 u16 reg_val;
199 u32 val;
Nate Drude021dacc2022-05-19 12:31:56 +0300200 phy_interface_t phy_mode_override = adin_get_phy_mode_override(phydev);
Nate Drudea9521ea2022-04-08 11:28:14 -0500201
Nate Drude021dacc2022-05-19 12:31:56 +0300202 if (phy_mode_override != PHY_INTERFACE_MODE_NA) {
203 phydev->interface = phy_mode_override;
Nate Drudea9521ea2022-04-08 11:28:14 -0500204 }
205
206 reg_val = adin_ext_read(phydev, ADIN1300_GE_RGMII_CFG);
207
208 if (!phy_interface_is_rgmii(phydev)) {
209 /* Disable RGMII */
210 reg_val &= ~ADIN1300_GE_RGMII_EN;
211 return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
212 }
213
214 /* Enable RGMII */
215 reg_val |= ADIN1300_GE_RGMII_EN;
216
217 /* Enable / Disable RGMII RX Delay */
218 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
219 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
220 reg_val |= ADIN1300_GE_RGMII_RXID_EN;
221
222 val = adin_get_reg_value(phydev, "adi,rx-internal-delay-ps",
223 adin_rgmii_delays,
224 ADIN1300_RGMII_2_00_NS);
225 reg_val &= ~ADIN1300_GE_RGMII_RX_MSK;
226 reg_val |= ADIN1300_GE_RGMII_RX_SEL(val);
227 } else {
228 reg_val &= ~ADIN1300_GE_RGMII_RXID_EN;
229 }
230
231 /* Enable / Disable RGMII RX Delay */
232 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
233 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
234 reg_val |= ADIN1300_GE_RGMII_TXID_EN;
235
236 val = adin_get_reg_value(phydev, "adi,tx-internal-delay-ps",
237 adin_rgmii_delays,
238 ADIN1300_RGMII_2_00_NS);
239 reg_val &= ~ADIN1300_GE_RGMII_GTX_MSK;
240 reg_val |= ADIN1300_GE_RGMII_GTX_SEL(val);
241 } else {
242 reg_val &= ~ADIN1300_GE_RGMII_TXID_EN;
243 }
244
245 return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
246}
247
248static int adin1300_config(struct phy_device *phydev)
249{
250 int ret;
251
252 printf("ADIN1300 PHY detected at addr %d\n", phydev->addr);
253
Josua Mayerd671dcb2022-05-19 12:31:57 +0300254 ret = adin_config_clk_out(phydev);
255 if (ret < 0)
256 return ret;
257
Nate Drudea9521ea2022-04-08 11:28:14 -0500258 ret = adin_config_rgmii_mode(phydev);
259
260 if (ret < 0)
261 return ret;
262
263 return genphy_config(phydev);
264}
265
Marek Vasut09f1a012023-03-19 18:02:43 +0100266U_BOOT_PHY_DRIVER(ADIN1300) = {
Nate Drudea9521ea2022-04-08 11:28:14 -0500267 .name = "ADIN1300",
268 .uid = PHY_ID_ADIN1300,
269 .mask = 0xffffffff,
270 .features = PHY_GBIT_FEATURES,
271 .config = adin1300_config,
272 .startup = genphy_startup,
273 .shutdown = genphy_shutdown,
Nate Drude8b26a692023-07-11 16:59:15 -0500274 .readext = adin_extread,
275 .writeext = adin_extwrite,
Nate Drudea9521ea2022-04-08 11:28:14 -0500276};