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/mdio/eth_phy.h"
31#include "qemu/log.h"
32
33#ifndef ETH_PHY_DEBUG
34#define ETH_PHY_DEBUG 0
35#endif
36
37#define DPRINT(fmt, args...) \
38 do { \
39 if (ETH_PHY_DEBUG) { \
40 qemu_log("%s: " fmt, __func__, ## args); \
41 } \
42 } while (0)
43
44static void eth_phy_reset(DeviceState *dev)
45{
46 EthPhy *s = ETHPHY(dev);
47
48
49 if (s->part->autoneg) {
50
51 s->regs[PHY_STATUS] |= M(PHY_STAT_AUTONEG_CAP) |
52 M(PHY_STAT_AUTONEG_COMP) |
53 M(PHY_STAT_EXT_CAP);
54
55 s->regs[PHY_CTRL] |= M(PHY_CTRLREG_AUTONEG_EN);
56
57
58
59 s->regs[PHY_AUTONEG_ADV] |= 0x01E1;
60 s->regs[PHY_LP_ABILITY] |= 0xCDE1;
61
62 s->regs[PHY_1000T_CTRL] |= 0x0300;
63 s->regs[PHY_1000T_STATUS] |= 0x7C00;
64
65
66 if (s->part->gmii) {
67 s->regs[PHY_EXT_STATUS] |= M(PHY_EXT_STAT_1000BT_HD) |
68 M(PHY_EXT_STAT_1000BT_FD) |
69 M(PHY_EXT_STAT_1000BX_HD) |
70 M(PHY_EXT_STAT_1000BX_FD);
71 s->regs[PHY_STATUS] |= M(PHY_STAT_100BX_FD) |
72 M(PHY_STAT_100BX_HD) |
73 M(PHY_STAT_100B_T2_FD) |
74 M(PHY_STAT_100B_T2_HD) |
75 M(PHY_STAT_10MBPS_HD) |
76 M(PHY_STAT_10MBPS_FD);
77
78 s->regs[PHY_CTRL] |= M(PHY_CTRLREG_SPEED_SEL_MSB);
79
80
81 s->regs[PHY_STATUS] |= M(PHY_STAT_EXT_STAT_CAP);
82 s->regs[PHY_SPEC_STATUS] |= 0xBC00;
83 } else {
84 s->regs[PHY_STATUS] |= M(PHY_STAT_100BX_FD) |
85 M(PHY_STAT_100BX_HD) |
86 M(PHY_STAT_100B_T2_FD) |
87 M(PHY_STAT_100B_T2_HD) |
88 M(PHY_STAT_10MBPS_HD) |
89 M(PHY_STAT_10MBPS_FD);
90
91 s->regs[PHY_CTRL] |= M(PHY_CTRLREG_SPEED_SEL_LSB);
92 s->regs[PHY_SPEC_STATUS] |= 0x7C00;
93 }
94
95 }
96 s->link = true;
97 s->regs[PHY_STATUS] |= M(PHY_STAT_LINK_STAT);
98}
99
100static int eth_phy_read(MDIOSlave *slave, uint8_t req)
101{
102 EthPhy *phy = ETHPHY(slave);
103 int regnum;
104 unsigned r = 0;
105
106 regnum = req & 0x1f;
107
108 switch (regnum) {
109 case PHY_STATUS:
110 if (!phy->link) {
111 break;
112 }
113 r = phy->regs[PHY_STATUS];
114 break;
115 default:
116 r = phy->regs[regnum];
117 break;
118 }
119 DPRINT("%s %x = reg[%d]\r\n", __func__, r, regnum);
120 return r;
121}
122
123static int eth_phy_write(MDIOSlave *slave, uint8_t req, uint8_t data)
124{
125 EthPhy *phy = ETHPHY(slave);
126 int regnum = req & 0x1f;
127 uint16_t mask = phy->regs_readonly_mask[regnum];
128
129 DPRINT("%s reg[%d] = %x; mask=%x\n", __func__, regnum, data, mask);
130 switch (regnum) {
131 case PHY_CTRL:
132
133 if (data & PHY_CTRL_RST) {
134 eth_phy_reset(DEVICE(phy));
135 }
136 default:
137 phy->regs[regnum] = (phy->regs[regnum] & mask) | (data & ~mask);
138 break;
139 }
140 return 0;
141}
142
143static void eth_phy_init(Object *Obj)
144{
145 EthPhy *s = ETHPHY(Obj);
146 EthPhyClass *k = ETHPHY_GET_CLASS(Obj);
147
148 s->part = k->part;
149
150 s->regs[PHY_ID1] = s->part->phy_id1;
151 s->regs[PHY_ID2] = s->part->phy_id2;
152
153 s->regs_readonly_mask = default_readonly_mask;
154}
155
156static void eth_phy_class_init(ObjectClass *klass, void *data)
157{
158 MDIOSlaveClass *sc = MDIO_SLAVE_CLASS(klass);
159
160 sc->send = eth_phy_write;
161 sc->recv = eth_phy_read;
162}
163
164static void phy_class_init(ObjectClass *klass, void *data)
165{
166 DeviceClass *dc = DEVICE_CLASS(klass);
167 EthPhyClass *k = ETHPHY_CLASS(klass);
168
169 k->part = data;
170 dc->reset = eth_phy_reset;
171}
172
173static const TypeInfo eth_phy_info = {
174 .name = TYPE_ETH_PHY,
175 .parent = TYPE_MDIO_SLAVE,
176 .instance_size = sizeof(EthPhy),
177 .class_size = sizeof(EthPhyClass),
178 .instance_init = eth_phy_init,
179 .class_init = eth_phy_class_init,
180};
181
182static void eth_phy_register_types(void)
183{
184 int i;
185
186 type_register_static(ð_phy_info);
187
188 for (i = 0; i < ARRAY_SIZE(devices); i++) {
189 TypeInfo ti = {
190 .name = devices[i].partname,
191 .parent = TYPE_ETH_PHY,
192 .class_init = phy_class_init,
193 .class_data = (void *)&devices[i],
194 };
195 type_register(&ti);
196 }
197}
198
199type_init(eth_phy_register_types)
200