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