1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 Marvell International Ltd. 4 * Author: Ken Ma<make@marvell.com> 5 */ 6 7 #include <common.h> 8 #include <fdtdec.h> 9 #include <errno.h> 10 #include <dm.h> 11 #include <dm/uclass.h> 12 #include <dm/uclass-internal.h> 13 #include <miiphy.h> 14 #include <net/mdio.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 int mdio_mii_bus_get(struct udevice *mdio_dev, struct mii_dev **busp) 19 { 20 *busp = (struct mii_dev *)dev_get_uclass_platdata(mdio_dev); 21 22 return 0; 23 } 24 25 int mdio_device_get_from_phy(ofnode phy_node, struct udevice **devp) 26 { 27 ofnode mdio_node; 28 29 mdio_node = ofnode_get_parent(phy_node); 30 return uclass_get_device_by_ofnode(UCLASS_MDIO, mdio_node, devp); 31 } 32 33 int mdio_mii_bus_get_from_phy(ofnode phy_node, struct mii_dev **busp) 34 { 35 struct udevice *mdio_dev; 36 int ret; 37 38 ret = mdio_device_get_from_phy(phy_node, &mdio_dev); 39 if (ret) 40 return ret; 41 42 *busp = (struct mii_dev *)dev_get_uclass_platdata(mdio_dev); 43 44 return 0; 45 } 46 47 int mdio_device_get_from_eth(struct udevice *eth, struct udevice **devp) 48 { 49 struct ofnode_phandle_args phy_args; 50 int ret; 51 52 ret = dev_read_phandle_with_args(eth, "phy", NULL, 0, 0, &phy_args); 53 if (!ret) 54 return mdio_device_get_from_phy(phy_args.node, devp); 55 56 /* 57 * If there is no phy reference under the ethernet fdt node, 58 * it is not an error since the ethernet device may do not use 59 * mode; so in this case, the output mdio device pointer is set 60 * as NULL. 61 */ 62 *devp = NULL; 63 return 0; 64 } 65 66 int mdio_mii_bus_get_from_eth(struct udevice *eth, struct mii_dev **busp) 67 { 68 struct udevice *mdio_dev; 69 int ret; 70 71 ret = mdio_device_get_from_eth(eth, &mdio_dev); 72 if (ret) 73 return ret; 74 75 if (mdio_dev) 76 *busp = (struct mii_dev *)dev_get_uclass_platdata(mdio_dev); 77 else 78 *busp = NULL; 79 80 return 0; 81 } 82 83 static int mdio_uclass_pre_probe(struct udevice *dev) 84 { 85 struct mii_dev *bus = (struct mii_dev *)dev_get_uclass_platdata(dev); 86 const char *name; 87 88 /* initialize mii_dev struct fields, implement mdio_alloc() setup */ 89 INIT_LIST_HEAD(&bus->link); 90 91 name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), 92 "mdio-name", NULL); 93 if (name) 94 strncpy(bus->name, name, MDIO_NAME_LEN); 95 96 return 0; 97 } 98 99 static int mdio_uclass_post_probe(struct udevice *dev) 100 { 101 struct mii_dev *bus = (struct mii_dev *)dev_get_uclass_platdata(dev); 102 103 return mdio_register(bus); 104 } 105 106 UCLASS_DRIVER(mdio) = { 107 .id = UCLASS_MDIO, 108 .name = "mdio", 109 .pre_probe = mdio_uclass_pre_probe, 110 .post_probe = mdio_uclass_post_probe, 111 .per_device_platdata_auto_alloc_size = sizeof(struct mii_dev), 112 }; 113