xref: /openbmc/u-boot/drivers/net/mdio/mdio-uclass.c (revision 3ba98ed8)
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