Merge tag 'efi-2022-07-rc1-2' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/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  */
8 #include <common.h>
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 #define ADIN1300_GE_RGMII_CFG                   0xff23
17 #define ADIN1300_GE_RGMII_RX_MSK                GENMASK(8, 6)
18 #define ADIN1300_GE_RGMII_RX_SEL(x)             \
19                 FIELD_PREP(ADIN1300_GE_RGMII_RX_MSK, x)
20 #define ADIN1300_GE_RGMII_GTX_MSK               GENMASK(5, 3)
21 #define ADIN1300_GE_RGMII_GTX_SEL(x)            \
22                 FIELD_PREP(ADIN1300_GE_RGMII_GTX_MSK, x)
23 #define ADIN1300_GE_RGMII_RXID_EN               BIT(2)
24 #define ADIN1300_GE_RGMII_TXID_EN               BIT(1)
25 #define ADIN1300_GE_RGMII_EN                    BIT(0)
26
27 /* RGMII internal delay settings for rx and tx for ADIN1300 */
28 #define ADIN1300_RGMII_1_60_NS                  0x0001
29 #define ADIN1300_RGMII_1_80_NS                  0x0002
30 #define ADIN1300_RGMII_2_00_NS                  0x0000
31 #define ADIN1300_RGMII_2_20_NS                  0x0006
32 #define ADIN1300_RGMII_2_40_NS                  0x0007
33
34 /**
35  * struct adin_cfg_reg_map - map a config value to aregister value
36  * @cfg         value in device configuration
37  * @reg         value in the register
38  */
39 struct adin_cfg_reg_map {
40         int cfg;
41         int reg;
42 };
43
44 static const struct adin_cfg_reg_map adin_rgmii_delays[] = {
45         { 1600, ADIN1300_RGMII_1_60_NS },
46         { 1800, ADIN1300_RGMII_1_80_NS },
47         { 2000, ADIN1300_RGMII_2_00_NS },
48         { 2200, ADIN1300_RGMII_2_20_NS },
49         { 2400, ADIN1300_RGMII_2_40_NS },
50         { },
51 };
52
53 static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg)
54 {
55         size_t i;
56
57         for (i = 0; tbl[i].cfg; i++) {
58                 if (tbl[i].cfg == cfg)
59                         return tbl[i].reg;
60         }
61
62         return -EINVAL;
63 }
64
65 static u32 adin_get_reg_value(struct phy_device *phydev,
66                               const char *prop_name,
67                               const struct adin_cfg_reg_map *tbl,
68                               u32 dflt)
69 {
70         u32 val;
71         int rc;
72
73         ofnode node = phy_get_ofnode(phydev);
74         if (!ofnode_valid(node)) {
75                 printf("%s: failed to get node\n", __func__);
76                 return -EINVAL;
77         }
78
79         if (ofnode_read_u32(node, prop_name, &val)) {
80                 printf("%s: failed to find %s, using default %d\n",
81                        __func__, prop_name, dflt);
82                 return dflt;
83         }
84
85         debug("%s: %s = '%d'\n", __func__, prop_name, val);
86
87         rc = adin_lookup_reg_value(tbl, val);
88         if (rc < 0) {
89                 printf("%s: Unsupported value %u for %s using default (%u)\n",
90                       __func__, val, prop_name, dflt);
91                 return dflt;
92         }
93
94         return rc;
95 }
96
97 /**
98  * adin_get_phy_mode_override - Get phy-mode override for adin PHY
99  *
100  * The function gets phy-mode string from property 'adi,phy-mode-override'
101  * and return its index in phy_interface_strings table, or -1 in error case.
102  */
103 int adin_get_phy_mode_override(struct phy_device *phydev)
104 {
105         ofnode node = phy_get_ofnode(phydev);
106         const char *phy_mode_override;
107         const char *prop_phy_mode_override = "adi,phy-mode-override";
108         int override_interface;
109
110         phy_mode_override = ofnode_read_string(node, prop_phy_mode_override);
111         if (!phy_mode_override)
112                 return -ENODEV;
113
114         debug("%s: %s = '%s'\n",
115               __func__, prop_phy_mode_override, phy_mode_override);
116
117         override_interface = phy_get_interface_by_name(phy_mode_override);
118
119         if (override_interface < 0)
120                 printf("%s: %s = '%s' is not valid\n",
121                        __func__, prop_phy_mode_override, phy_mode_override);
122
123         return override_interface;
124 }
125
126 static u16 adin_ext_read(struct phy_device *phydev, const u32 regnum)
127 {
128         u16 val;
129
130         phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
131         val = phy_read(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA);
132
133         debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
134
135         return val;
136 }
137
138 static int adin_ext_write(struct phy_device *phydev, const u32 regnum, const u16 val)
139 {
140         debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
141
142         phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
143
144         return phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA, val);
145 }
146
147 static int adin_config_rgmii_mode(struct phy_device *phydev)
148 {
149         u16 reg_val;
150         u32 val;
151         int phy_mode_override = adin_get_phy_mode_override(phydev);
152
153         if (phy_mode_override >= 0) {
154                 phydev->interface = (phy_interface_t) phy_mode_override;
155         }
156
157         reg_val = adin_ext_read(phydev, ADIN1300_GE_RGMII_CFG);
158
159         if (!phy_interface_is_rgmii(phydev)) {
160                 /* Disable RGMII */
161                 reg_val &= ~ADIN1300_GE_RGMII_EN;
162                 return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
163         }
164
165         /* Enable RGMII */
166         reg_val |= ADIN1300_GE_RGMII_EN;
167
168         /* Enable / Disable RGMII RX Delay */
169         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
170             phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
171                 reg_val |= ADIN1300_GE_RGMII_RXID_EN;
172
173                 val = adin_get_reg_value(phydev, "adi,rx-internal-delay-ps",
174                                          adin_rgmii_delays,
175                                          ADIN1300_RGMII_2_00_NS);
176                 reg_val &= ~ADIN1300_GE_RGMII_RX_MSK;
177                 reg_val |= ADIN1300_GE_RGMII_RX_SEL(val);
178         } else {
179                 reg_val &= ~ADIN1300_GE_RGMII_RXID_EN;
180         }
181
182         /* Enable / Disable RGMII RX Delay */
183         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
184             phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
185                 reg_val |= ADIN1300_GE_RGMII_TXID_EN;
186
187                 val = adin_get_reg_value(phydev, "adi,tx-internal-delay-ps",
188                                          adin_rgmii_delays,
189                                          ADIN1300_RGMII_2_00_NS);
190                 reg_val &= ~ADIN1300_GE_RGMII_GTX_MSK;
191                 reg_val |= ADIN1300_GE_RGMII_GTX_SEL(val);
192         } else {
193                 reg_val &= ~ADIN1300_GE_RGMII_TXID_EN;
194         }
195
196         return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
197 }
198
199 static int adin1300_config(struct phy_device *phydev)
200 {
201         int ret;
202
203         printf("ADIN1300 PHY detected at addr %d\n", phydev->addr);
204
205         ret = adin_config_rgmii_mode(phydev);
206
207         if (ret < 0)
208                 return ret;
209
210         return genphy_config(phydev);
211 }
212
213 static struct phy_driver ADIN1300_driver =  {
214         .name = "ADIN1300",
215         .uid = PHY_ID_ADIN1300,
216         .mask = 0xffffffff,
217         .features = PHY_GBIT_FEATURES,
218         .config = adin1300_config,
219         .startup = genphy_startup,
220         .shutdown = genphy_shutdown,
221 };
222
223 int phy_adin_init(void)
224 {
225         phy_register(&ADIN1300_driver);
226
227         return 0;
228 }