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