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
mdio_mii_bus_get(struct udevice * mdio_dev,struct mii_dev ** busp)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
mdio_device_get_from_phy(ofnode phy_node,struct udevice ** devp)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
mdio_mii_bus_get_from_phy(ofnode phy_node,struct mii_dev ** busp)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
mdio_device_get_from_eth(struct udevice * eth,struct udevice ** devp)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
mdio_mii_bus_get_from_eth(struct udevice * eth,struct mii_dev ** busp)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
mdio_uclass_pre_probe(struct udevice * dev)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
mdio_uclass_post_probe(struct udevice * dev)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