]> Git Repo - J-u-boot.git/blob - drivers/net/phy/adin.c
Merge tag 'u-boot-imx-master-20250127' of https://gitlab.denx.de/u-boot/custodians...
[J-u-boot.git] / drivers / net / phy / adin.c
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 <[email protected]>
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
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
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  */
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
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
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
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
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
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
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
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 };
This page took 0.042943 seconds and 4 git commands to generate.