1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Analog Devices Industrial Ethernet PHYs
5 * Copyright 2019 Analog Devices Inc.
6 * Copyright 2022 Variscite Ltd.
10 #include <linux/bitops.h>
11 #include <linux/bitfield.h>
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)
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
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
39 struct adin_cfg_reg_map {
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 },
53 static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg)
57 for (i = 0; tbl[i].cfg; i++) {
58 if (tbl[i].cfg == cfg)
65 static u32 adin_get_reg_value(struct phy_device *phydev,
66 const char *prop_name,
67 const struct adin_cfg_reg_map *tbl,
73 ofnode node = phy_get_ofnode(phydev);
74 if (!ofnode_valid(node)) {
75 printf("%s: failed to get node\n", __func__);
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);
85 debug("%s: %s = '%d'\n", __func__, prop_name, val);
87 rc = adin_lookup_reg_value(tbl, val);
89 printf("%s: Unsupported value %u for %s using default (%u)\n",
90 __func__, val, prop_name, dflt);
98 * adin_get_phy_mode_override - Get phy-mode override for adin PHY
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.
103 int adin_get_phy_mode_override(struct phy_device *phydev)
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;
110 phy_mode_override = ofnode_read_string(node, prop_phy_mode_override);
111 if (!phy_mode_override)
114 debug("%s: %s = '%s'\n",
115 __func__, prop_phy_mode_override, phy_mode_override);
117 override_interface = phy_get_interface_by_name(phy_mode_override);
119 if (override_interface < 0)
120 printf("%s: %s = '%s' is not valid\n",
121 __func__, prop_phy_mode_override, phy_mode_override);
123 return override_interface;
126 static u16 adin_ext_read(struct phy_device *phydev, const u32 regnum)
130 phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
131 val = phy_read(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA);
133 debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
138 static int adin_ext_write(struct phy_device *phydev, const u32 regnum, const u16 val)
140 debug("%s: adin@0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
142 phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_PTR, regnum);
144 return phy_write(phydev, MDIO_DEVAD_NONE, ADIN1300_EXT_REG_DATA, val);
147 static int adin_config_rgmii_mode(struct phy_device *phydev)
151 int phy_mode_override = adin_get_phy_mode_override(phydev);
153 if (phy_mode_override >= 0) {
154 phydev->interface = (phy_interface_t) phy_mode_override;
157 reg_val = adin_ext_read(phydev, ADIN1300_GE_RGMII_CFG);
159 if (!phy_interface_is_rgmii(phydev)) {
161 reg_val &= ~ADIN1300_GE_RGMII_EN;
162 return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
166 reg_val |= ADIN1300_GE_RGMII_EN;
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;
173 val = adin_get_reg_value(phydev, "adi,rx-internal-delay-ps",
175 ADIN1300_RGMII_2_00_NS);
176 reg_val &= ~ADIN1300_GE_RGMII_RX_MSK;
177 reg_val |= ADIN1300_GE_RGMII_RX_SEL(val);
179 reg_val &= ~ADIN1300_GE_RGMII_RXID_EN;
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;
187 val = adin_get_reg_value(phydev, "adi,tx-internal-delay-ps",
189 ADIN1300_RGMII_2_00_NS);
190 reg_val &= ~ADIN1300_GE_RGMII_GTX_MSK;
191 reg_val |= ADIN1300_GE_RGMII_GTX_SEL(val);
193 reg_val &= ~ADIN1300_GE_RGMII_TXID_EN;
196 return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG, reg_val);
199 static int adin1300_config(struct phy_device *phydev)
203 printf("ADIN1300 PHY detected at addr %d\n", phydev->addr);
205 ret = adin_config_rgmii_mode(phydev);
210 return genphy_config(phydev);
213 static struct phy_driver ADIN1300_driver = {
215 .uid = PHY_ID_ADIN1300,
217 .features = PHY_GBIT_FEATURES,
218 .config = adin1300_config,
219 .startup = genphy_startup,
220 .shutdown = genphy_shutdown,
223 int phy_adin_init(void)
225 phy_register(&ADIN1300_driver);