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