1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2019 4 * Alex Marginean, NXP 5 */ 6 7#include <common.h> 8#include <dm.h> 9#include <dm/lists.h> 10#include <eth_phy.h> 11#include <log.h> 12#include <malloc.h> 13#include <miiphy.h> 14#include <dm/device-internal.h> 15#include <dm/device_compat.h> 16#include <dm/of_extra.h> 17#include <dm/uclass-internal.h> 18#include <linux/compat.h> 19#include <linux/delay.h> 20 21#define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */ 22 23void dm_mdio_probe_devices(void) 24{ 25 struct udevice *it; 26 struct uclass *uc; 27 28 uclass_get(UCLASS_MDIO, &uc); 29 uclass_foreach_dev(it, uc) { 30 device_probe(it); 31 } 32} 33 34static int dm_mdio_post_bind(struct udevice *dev) 35{ 36 const char *dt_name; 37 38 /* set a custom name for the MDIO device, if present in DT */ 39 if (dev_has_ofnode(dev)) { 40 dt_name = dev_read_string(dev, "device-name"); 41 if (dt_name) { 42 debug("renaming dev %s to %s\n", dev->name, dt_name); 43 device_set_name(dev, dt_name); 44 } 45 } 46 47 /* 48 * MDIO command doesn't like spaces in names, don't allow them to keep 49 * it happy 50 */ 51 if (strchr(dev->name, ' ')) { 52 debug("\nError: MDIO device name \"%s\" has a space!\n", 53 dev->name); 54 return -EINVAL; 55 } 56 57#if CONFIG_IS_ENABLED(OF_REAL) 58 return dm_scan_fdt_dev(dev); 59#else 60 return 0; 61#endif 62} 63 64int dm_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg) 65{ 66 struct mdio_ops *ops = mdio_get_ops(mdio_dev); 67 68 if (!ops->read) 69 return -ENOSYS; 70 71 return ops->read(mdio_dev, addr, devad, reg); 72} 73 74int dm_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, 75 u16 val) 76{ 77 struct mdio_ops *ops = mdio_get_ops(mdio_dev); 78 79 if (!ops->write) 80 return -ENOSYS; 81 82 return ops->write(mdio_dev, addr, devad, reg, val); 83} 84 85int dm_mdio_reset(struct udevice *mdio_dev) 86{ 87 struct mdio_ops *ops = mdio_get_ops(mdio_dev); 88 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev); 89 struct mii_dev *mii_bus = pdata->mii_bus; 90 91 if (CONFIG_IS_ENABLED(DM_GPIO) && dm_gpio_is_valid(&mii_bus->reset_gpiod)) { 92 dm_gpio_set_value(&mii_bus->reset_gpiod, 1); 93 udelay(mii_bus->reset_delay_us); 94 dm_gpio_set_value(&mii_bus->reset_gpiod, 0); 95 if (mii_bus->reset_post_delay_us > 0) 96 udelay(mii_bus->reset_post_delay_us); 97 } 98 99 if (!ops->reset) 100 return 0; 101 102 return ops->reset(mdio_dev); 103} 104 105/* 106 * Following read/write/reset functions are registered with legacy MII code. 107 * These are called for PHY operations by upper layers and we further call the 108 * DM MDIO driver functions. 109 */ 110static int mdio_read(struct mii_dev *mii_bus, int addr, int devad, int reg) 111{ 112 return dm_mdio_read(mii_bus->priv, addr, devad, reg); 113} 114 115static int mdio_write(struct mii_dev *mii_bus, int addr, int devad, int reg, 116 u16 val) 117{ 118 return dm_mdio_write(mii_bus->priv, addr, devad, reg, val); 119} 120 121static int mdio_reset(struct mii_dev *mii_bus) 122{ 123 return dm_mdio_reset(mii_bus->priv); 124} 125 126static int mdio_bind_phy_nodes(struct udevice *mdio_dev) 127{ 128 ofnode mdio_node, phy_node; 129 struct udevice *phy_dev; 130 const char *node_name; 131 int ret; 132 133 mdio_node = dev_ofnode(mdio_dev); 134 if (!ofnode_valid(mdio_node)) { 135 dev_dbg(mdio_dev, "invalid ofnode for mdio_dev\n"); 136 return -ENXIO; 137 } 138 139 ofnode_for_each_subnode(phy_node, mdio_node) { 140 node_name = ofnode_get_name(phy_node); 141 dev_dbg(mdio_dev, "* Found child node: '%s'\n", node_name); 142 ret = device_bind_driver_to_node(mdio_dev, 143 "eth_phy_generic_drv", 144 node_name, phy_node, &phy_dev); 145 if (ret) { 146 dev_dbg(mdio_dev, " - Eth phy binding error: %d\n", ret); 147 continue; 148 } 149 150 dev_dbg(mdio_dev, " - bound phy device: '%s'\n", node_name); 151 ret = device_probe(phy_dev); 152 if (ret) { 153 dev_dbg(mdio_dev, "Device '%s' probe failed\n", phy_dev->name); 154 device_unbind(phy_dev); 155 continue; 156 } 157 } 158 159 return 0; 160} 161 162static int dm_mdio_post_probe(struct udevice *dev) 163{ 164 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); 165 struct mii_dev *mii_bus; 166 int ret; 167 168 mii_bus = mdio_alloc(); 169 if (!mii_bus) { 170 dev_err(dev, "couldn't allocate mii_bus\n"); 171 return -ENOMEM; 172 } 173 pdata->mii_bus = mii_bus; 174 pdata->mii_bus->read = mdio_read; 175 pdata->mii_bus->write = mdio_write; 176 pdata->mii_bus->reset = mdio_reset; 177 pdata->mii_bus->priv = dev; 178 strlcpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN); 179 180 if (IS_ENABLED(CONFIG_DM_GPIO)) { 181 /* Get bus level PHY reset GPIO details */ 182 mii_bus->reset_delay_us = dev_read_u32_default(dev, "reset-delay-us", 183 DEFAULT_GPIO_RESET_DELAY); 184 mii_bus->reset_post_delay_us = dev_read_u32_default(dev, 185 "reset-post-delay-us", 186 0); 187 ret = gpio_request_by_name(dev, "reset-gpios", 0, &mii_bus->reset_gpiod, 188 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 189 if (ret && ret != -ENOENT) { 190 dev_err(dev, "couldn't get reset-gpios: %d\n", ret); 191 return ret; 192 } 193 } 194 195 if (CONFIG_IS_ENABLED(DM_ETH_PHY)) 196 mdio_bind_phy_nodes(dev); 197 198 return mdio_register(pdata->mii_bus); 199} 200 201static int dm_mdio_pre_remove(struct udevice *dev) 202{ 203 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); 204 205 dm_mdio_reset(dev); 206 mdio_unregister(pdata->mii_bus); 207 mdio_free(pdata->mii_bus); 208 209 return 0; 210} 211 212struct phy_device *dm_phy_find_by_ofnode(ofnode phynode) 213{ 214 struct mdio_perdev_priv *pdata; 215 struct udevice *mdiodev; 216 u32 phy_addr; 217 218 if (ofnode_read_u32(phynode, "reg", &phy_addr)) 219 return NULL; 220 221 if (uclass_get_device_by_ofnode(UCLASS_MDIO, 222 ofnode_get_parent(phynode), 223 &mdiodev)) 224 return NULL; 225 226 if (device_probe(mdiodev)) 227 return NULL; 228 229 pdata = dev_get_uclass_priv(mdiodev); 230 231 return phy_find_by_mask(pdata->mii_bus, BIT(phy_addr)); 232} 233 234struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, 235 struct udevice *ethdev, 236 phy_interface_t interface) 237{ 238 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdiodev); 239 240 if (device_probe(mdiodev)) 241 return NULL; 242 243 return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); 244} 245 246static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, 247 phy_interface_t interface) 248{ 249 u32 phy_addr; 250 struct udevice *mdiodev; 251 struct phy_device *phy; 252 ofnode phynode; 253 254 if (IS_ENABLED(CONFIG_PHY_FIXED) && 255 ofnode_phy_is_fixed_link(dev_ofnode(ethdev), &phynode)) { 256 phy = phy_connect(NULL, 0, ethdev, interface); 257 goto out; 258 } 259 260 phynode = dev_get_phy_node(ethdev); 261 if (!ofnode_valid(phynode)) { 262 dev_dbg(ethdev, "can't find PHY node\n"); 263 return NULL; 264 } 265 266 /* 267 * reading 'reg' directly should be fine. This is a PHY node, the 268 * address is always size 1 and requires no translation 269 */ 270 if (ofnode_read_u32(phynode, "reg", &phy_addr)) { 271 dev_dbg(ethdev, "missing reg property in phy node\n"); 272 return NULL; 273 } 274 275 if (uclass_get_device_by_ofnode(UCLASS_MDIO, 276 ofnode_get_parent(phynode), 277 &mdiodev)) { 278 dev_dbg(ethdev, "can't find MDIO bus for node %s\n", 279 ofnode_get_name(ofnode_get_parent(phynode))); 280 return NULL; 281 } 282 283 phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface); 284 285out: 286 if (phy) 287 phy->node = phynode; 288 289 return phy; 290} 291 292/* Connect to a PHY linked in eth DT node */ 293struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) 294{ 295 phy_interface_t interface; 296 struct phy_device *phy; 297 298 if (!dev_has_ofnode(ethdev)) { 299 debug("%s: supplied eth dev has no DT node!\n", ethdev->name); 300 return NULL; 301 } 302 303 interface = dev_read_phy_mode(ethdev); 304 if (interface == PHY_INTERFACE_MODE_NA) 305 dev_dbg(ethdev, "can't find interface mode, default to NA\n"); 306 307 phy = dm_eth_connect_phy_handle(ethdev, interface); 308 309 if (!phy) 310 return NULL; 311 312 phy->interface = interface; 313 314 return phy; 315} 316 317UCLASS_DRIVER(mdio) = { 318 .id = UCLASS_MDIO, 319 .name = "mdio", 320 .post_bind = dm_mdio_post_bind, 321 .post_probe = dm_mdio_post_probe, 322 .pre_remove = dm_mdio_pre_remove, 323 .per_device_auto = sizeof(struct mdio_perdev_priv), 324}; 325