1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include "qemu/osdep.h"
29#include "qapi/error.h"
30#include "migration/vmstate.h"
31#include "hw/qdev-properties.h"
32#include "hw/mdio/mdio_slave.h"
33#include "hw/fdt_generic_util.h"
34
35struct MDIOBus *mdio_init_bus(DeviceState *parent, const char *name)
36{
37 struct MDIOBus *bus;
38
39 bus = MDIO_BUS(qbus_new(TYPE_MDIO_BUS, parent, name));
40 return bus;
41}
42
43void mdio_set_slave_addr(MDIOSlave *s, uint8_t addr)
44{
45 s->addr = addr;
46}
47
48static MDIOSlave *mdio_find_slave(struct MDIOBus *bus, uint8_t addr)
49{
50 MDIOSlave *slave = NULL;
51 BusChild *kid;
52
53 QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
54 DeviceState *qdev = kid->child;
55 MDIOSlave *candidate = MDIO_SLAVE(qdev);
56
57 if (candidate->addr == 0) {
58 candidate->addr = addr;
59 }
60 if (addr == candidate->addr) {
61 slave = candidate;
62 break;
63 }
64 }
65 return slave;
66}
67
68int mdio_send(struct MDIOBus *bus, uint8_t addr, uint8_t reg, uint8_t data)
69{
70 MDIOSlave *slave = NULL;
71 MDIOSlaveClass *sc;
72
73 if ((bus->cur_addr != addr) || !bus->cur_slave) {
74 slave = mdio_find_slave(bus, addr);
75 if (slave) {
76 bus->cur_slave = slave;
77 bus->cur_addr = addr;
78 } else {
79 return -1;
80 }
81 } else {
82 slave = bus->cur_slave;
83 }
84
85 sc = MDIO_SLAVE_GET_CLASS(slave);
86 if (sc->send) {
87 return sc->send(slave, reg, data);
88 }
89 return -1;
90}
91
92int mdio_recv(struct MDIOBus *bus, uint8_t addr, uint8_t reg)
93{
94 MDIOSlave *slave = NULL;
95 MDIOSlaveClass *sc;
96
97 if ((bus->cur_addr != addr) || !bus->cur_slave) {
98 slave = mdio_find_slave(bus, addr);
99 if (slave) {
100 bus->cur_slave = slave;
101 bus->cur_addr = addr;
102 } else {
103 return -1;
104 }
105 } else {
106 slave = bus->cur_slave;
107 }
108
109 sc = MDIO_SLAVE_GET_CLASS(slave);
110 if (sc->recv) {
111 return sc->recv(slave, reg);
112 }
113 return -1;
114}
115
116static Property mdio_props[] = {
117 DEFINE_PROP_UINT8("reg", MDIOSlave, addr, 0),
118 DEFINE_PROP_END_OF_LIST(),
119};
120
121static bool mdio_slave_parse_reg(FDTGenericMMap *obj, FDTGenericRegPropInfo reg,
122 Error **errp)
123{
124 DeviceState *parent;
125
126 parent = (DeviceState *)object_dynamic_cast(reg.parents[0], TYPE_DEVICE);
127
128 if (!parent) {
129 return false;
130 }
131
132 if (!parent->realized) {
133 return true;
134 }
135
136 qdev_set_parent_bus(DEVICE(obj), qdev_get_child_bus(parent, "mdio-bus"),
137 &error_abort);
138
139 return false;
140}
141
142static void mdio_slave_class_init(ObjectClass *klass, void *data)
143{
144 DeviceClass *k = DEVICE_CLASS(klass);
145 FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_CLASS(klass);
146
147 set_bit(DEVICE_CATEGORY_MISC, k->categories);
148 k->bus_type = TYPE_MDIO_BUS;
149 device_class_set_props(k, mdio_props);
150 fmc->parse_reg = mdio_slave_parse_reg;
151}
152
153static const TypeInfo mdio_slave_info = {
154 .name = TYPE_MDIO_SLAVE,
155 .parent = TYPE_DEVICE,
156 .instance_size = sizeof(MDIOSlave),
157 .class_size = sizeof(MDIOSlaveClass),
158 .class_init = mdio_slave_class_init,
159 .interfaces = (InterfaceInfo []) {
160 {TYPE_FDT_GENERIC_MMAP},
161 { },
162 },
163};
164
165static const TypeInfo mdio_bus_info = {
166 .name = TYPE_MDIO_BUS,
167 .parent = TYPE_BUS,
168 .instance_size = sizeof(struct MDIOBus),
169};
170
171static void mdio_slave_register_type(void)
172{
173 type_register_static(&mdio_bus_info);
174 type_register_static(&mdio_slave_info);
175}
176
177type_init(mdio_slave_register_type)
178