1 // 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.
7 * Copyright 2022 Josua Mayer <josua@solid-run.com>
8 */
9 #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
16
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
26 #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 */
49 struct adin_cfg_reg_map {
50 int cfg;
51 int reg;
52 };
53
54 static 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
adin_lookup_reg_value(const struct adin_cfg_reg_map * tbl,int cfg)63 static 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
adin_get_reg_value(struct phy_device * phydev,const char * prop_name,const struct adin_cfg_reg_map * tbl,u32 dflt)75 static 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 */
adin_get_phy_mode_override(struct phy_device * phydev)113 phy_interface_t adin_get_phy_mode_override(struct phy_device *phydev)
114 {
115 ofnode node = phy_get_ofnode(phydev);
116 const char *phy_mode_override;
117 const char *prop_phy_mode_override = "adi,phy-mode-override";
118 int i;
119
120 phy_mode_override = ofnode_read_string(node, prop_phy_mode_override);
121 if (!phy_mode_override)
122 return PHY_INTERFACE_MODE_NA;
123
124 debug("%s: %s = '%s'\n",
125 __func__, prop_phy_mode_override, phy_mode_override);
126
127 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;
130
131 printf("%s: Invalid PHY interface '%s'\n", __func__, phy_mode_override);
132
133 return PHY_INTERFACE_MODE_NA;
134 }
135
adin_ext_read(struct phy_device * phydev,const u32 regnum)136 static 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
adin_ext_write(struct phy_device * phydev,const u32 regnum,const u16 val)148 static 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
adin_extread(struct phy_device * phydev,int addr,int devaddr,int regnum)157 static int adin_extread(struct phy_device *phydev, int addr, int devaddr,
158 int regnum)
159 {
160 return adin_ext_read(phydev, regnum);
161 }
162
adin_extwrite(struct phy_device * phydev,int addr,int devaddr,int regnum,u16 val)163 static 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
adin_config_clk_out(struct phy_device * phydev)169 static 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
adin_config_rgmii_mode(struct phy_device * phydev)196 static int adin_config_rgmii_mode(struct phy_device *phydev)
197 {
198 u16 reg_val;
199 u32 val;
200 phy_interface_t phy_mode_override = adin_get_phy_mode_override(phydev);
201
202 if (phy_mode_override != PHY_INTERFACE_MODE_NA) {
203 phydev->interface = phy_mode_override;
204 }
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
adin1300_config(struct phy_device * phydev)248 static int adin1300_config(struct phy_device *phydev)
249 {
250 int ret;
251
252 printf("ADIN1300 PHY detected at addr %d\n", phydev->addr);
253
254 ret = adin_config_clk_out(phydev);
255 if (ret < 0)
256 return ret;
257
258 ret = adin_config_rgmii_mode(phydev);
259
260 if (ret < 0)
261 return ret;
262
263 return genphy_config(phydev);
264 }
265
266 U_BOOT_PHY_DRIVER(ADIN1300) = {
267 .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,
274 .readext = adin_extread,
275 .writeext = adin_extwrite,
276 };
277