2 * QEMU Ethernet Physical Layer (PHY) support
4 * Copyright (c) 2007 Stefan Weil
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /* This code emulates a National Semiconductor DP83840A PHY. */
26 PHY_BMCR
= 0x00, /* Basic Mode Control Register */
27 PHY_BMSR
= 0x01, /* Basic Mode Status */
28 PHY_PHYIDR1
= 0x02, /* PHY Identifier 1 */
29 PHY_PHYIDR2
= 0x03, /* PHY Identifier 2 */
30 PHY_ANAR
= 0x04, /* Auto-Negotiation Advertisement */
31 PHY_ANLPAR
= 0x05, /* Auto-Negotiation Link Partner Ability */
32 PHY_ANER
= 0x06, /* Auto-Negotiation Expansion */
33 PHY_DCR
= 0x12, /* Disconnect Counter */
34 PHY_FCSCR
= 0x13, /* False Carrier Sense Counter */
35 PHY_RECR
= 0x15, /* Receive Error Counter */
36 PHY_SRR
= 0x16, /* Silicon Revision */
37 PHY_PCR
= 0x17, /* PCS Sublayer Configuration */
38 PHY_LBREMR
= 0x18, /* Loopback, Bypass and Receiver Error Mask */
39 PHY_PAR
= 0x19, /* PHY Address */
40 PHY_10BTSR
= 0x1b, /* 10Base-T Status */
41 PHY_10BTCR
= 0x1c, /* 10Base-T Configuration */
48 AUTO_NEGOTIATE_EN
= BIT(12),
50 PHY_ISOLATE
= BIT(10),
53 PHY_COLLISION_TEST
= BIT(7),
57 PHY_100BASE_T4
= BIT(15),
58 PHY_100BASE_TX_FD
= BIT(14),
59 PHY_100BASE_TX_HD
= BIT(13),
60 PHY_10BASE_T_FD
= BIT(12),
61 PHY_10BASE_T_HD
= BIT(11),
62 NWAY_COMPLETE
= BIT(5),
63 NWAY_CAPABLE
= BIT(3),
65 PHY_EXTENDED_CAPABILITY
= BIT(0),
81 NWAY_SEL
= BITS(4, 0),
85 #define PHY_AUTO_NEG_EXPANSION 6
86 #define PHY_GENERIC_CONFIG_REG 0x10
87 #define PHY_IFSEL (3<<14)
88 #define PHY_LBKMD (3<<12)
89 /*--- #define PHY_ (3<<10) ---*/
90 #define PHY_FLTLED (1<<9)
91 #define PHY_CONV (1<<8)
92 /*--- #define PHY_ (1<<5) ---*/
93 #define PHY_XOVEN (1<<4)
94 /*--- #define PHY_ (3<<2) ---*/
95 #define PHY_ENREG8 (1<<1)
96 #define PHY_DISPMG (1<<0)
97 #define PHY_GENERIC_STATUS_REG 0x16
98 #define PHY_STATUS_MD (1<<10)
99 #define PHY_SPECIFIC_STATUS_REG 0x17
100 #define PHY_STATUS_LINK (1<<4)
101 #define PHY_INTERRUPT_STATUS 0x19
102 #define PHY_INT_XOVCHG (1<<9)
103 #define PHY_INT_SPDCHG (1<<8)
104 #define PHY_INT_DUPCHG (1<<7)
105 #define PHY_INT_PGRCHG (1<<6)
106 #define PHY_INT_LNKCHG (1<<5)
107 #define PHY_INT_SYMERR (1<<4)
108 #define PHY_INT_FCAR (1<<3)
109 #define PHY_INT_TJABINT (1<<2)
110 #define PHY_INT_RJABINT (1<<1)
111 #define PHY_INT_ESDERR (1<<0)
112 #define PHY_RXERR_COUNT 0x1D
115 /* Hardware registers for physical layer emulation. */
122 #if defined(DEBUG_PHY)
124 static int trace_phy
;
126 #define PHY trace_phy
129 #define SET_TRACEFLAG(name) \
131 char *substring = strstr(env, #name); \
133 name = ((substring > env && substring[-1] == '-') ? 0 : 1); \
135 TRACE_PHY(logout("Logging enabled for " #name "\n")); \
138 #define TRACE_PHY(statement) ((PHY) ? (statement) : (void)0)
140 static void set_phy_traceflags(const char *envname
)
142 const char *env
= getenv(envname
);
144 unsigned long ul
= strtoul(env
, 0, 0);
145 if ((ul
== 0) && strstr(env
, "ALL")) ul
= 0xffffffff;
153 #define TRACE_PHY(statement) ((void)0)
155 #endif /* DEBUG_PHY */
157 static void phy_reset(void)
160 //~ 0xA8611E80 09 78 3F 20
161 //~ 0xA8611E80 2D 78 3F 20
164 //~ 0xA8611E80 01 00 BF 20
165 //~ 0xA8611E80 E1 85 BF 20
166 const int linked
= 1;
167 TRACE_PHY(logout("\n"));
168 phy
.reg
[PHY_BMCR
] = PHY_100
| AUTO_NEGOTIATE_EN
| PHY_FD
;
169 //~ phy.reg[PHY_BMCR] |= PHY_ISOLATE;
170 phy
.reg
[PHY_BMSR
] = PHY_100BASE_TX_FD
| PHY_100BASE_TX_HD
;
171 phy
.reg
[PHY_BMSR
] |= PHY_10BASE_T_FD
| PHY_10BASE_T_HD
;
172 //~ phy.reg[PHY_BMSR] |= BIT(6);
173 phy
.reg
[PHY_BMSR
] |= NWAY_CAPABLE
;
174 phy
.reg
[PHY_BMSR
] |= PHY_EXTENDED_CAPABILITY
;
176 phy
.reg
[PHY_BMSR
] |= NWAY_COMPLETE
+ PHY_LINKED
;
178 phy
.reg
[PHY_PHYIDR1
] = 0x0000;
179 //~ phy.reg[PHY_PHYIDR1] = OUI Bits 3...18;
180 phy
.reg
[PHY_PHYIDR2
] = 0x0000;
181 //~ phy.reg[PHY_PHYIDR2] = OUI Bits 19...24 + vendor + revision;
182 phy
.reg
[PHY_ANAR
] = NWAY_FD100
+ NWAY_HD100
+ NWAY_FD10
+ NWAY_HD10
+ NWAY_AUTO
;
183 phy
.reg
[PHY_ANLPAR
] = NWAY_AUTO
;
185 phy
.reg
[PHY_ANLPAR
] |= 0x8400 + (phy
.reg
[4] & BITS(8, 5));
187 //~ phy.reg[PHY_ANLPAR] = 0;
190 static void phy_autoneg(void)
192 TRACE_PHY(logout("\n"));
194 phy
.reg
[PHY_BMSR
] |= NWAY_COMPLETE
+ PHY_LINKED
;
197 static void phy_enable(void)
199 static int first
= 1;
200 TRACE_PHY(logout("\n"));
208 static void phy_disable(void)
210 TRACE_PHY(logout("\n"));
214 static uint16_t phy_read(unsigned addr
)
216 uint16_t val
= phy
.reg
[addr
];
217 TRACE_PHY(logout("\n"));
218 if (!phy
.enabled
) return 0;
220 if (addr
== PHY_BMCR
) {
221 if (val
& PHY_RESET
) {
223 ((val
& ~PHY_RESET
) | AUTO_NEGOTIATE_EN
);
224 } else if (val
& RENEGOTIATE
) {
227 //~ 0x0000782d 0x00007809
229 phy
.reg
[5] = phy
.reg
[4] | PHY_ISOLATE
| PHY_RESET
;
230 reg_write(av
.mdio
, MDIO_LINK
, 0x80000000);
232 } else if (addr
== PHY_BMSR
) {
233 val
|= PHY_LINKED
| NWAY_CAPABLE
| NWAY_COMPLETE
;
239 static void phy_write(unsigned addr
, uint16_t val
)
241 TRACE_PHY(logout("\n"));
242 if (!phy
.enabled
) return;
244 if (addr
== PHY_BMCR
) {
245 if (val
& PHY_RESET
) {
249 if (val
& PHY_LOOP
) {
252 if (val
& RENEGOTIATE
) {
254 if (phy
.reg
[PHY_BMCR
] & AUTO_NEGOTIATE_EN
) {
258 if (val
& PHY_COLLISION_TEST
) {
261 } else if (addr
== PHY_BMSR
|| addr
== PHY_PHYIDR1
|| addr
== PHY_PHYIDR2
) {
264 } else if (addr
== PHY_ANAR
) {
268 //~ 1000 7809 0000 0000 01e1 0001
269 //~ mdio_useraccess_data[0][PHY_BMCR] = 0x1000;
270 //~ mdio_useraccess_data[0][PHY_BMSR] = 0x782d;
271 //~ mdio_useraccess_data[0][NWAY_ADVERTIZE_REG] = 0x01e1;
272 /* 100FD=Yes, 100HD=Yes, 10FD=Yes, 10HD=Yes */
273 //~ mdio_useraccess_data[0][NWAY_REMADVERTISE_REG] = 0x85e1;
278 static void phy_init(void)
280 #if defined(DEBUG_PHY)
281 set_phy_traceflags("DEBUG_AR7");
283 TRACE_PHY(logout("\n"));
287 /* phy code from eepro100 */
288 uint8_t raiseint
= (val
& 0x20000000) >> 29;
289 uint8_t opcode
= (val
& 0x0c000000) >> 26;
290 uint8_t phy
= (val
& 0x03e00000) >> 21;
291 uint8_t reg
= (val
& 0x001f0000) >> 16;
292 uint16_t data
= (val
& 0x0000ffff);
294 /* Unsupported PHY address. */
295 //~ logout("phy must be 1 but is %u\n", phy);
297 } else if (opcode
!= 1 && opcode
!= 2) {
298 /* Unsupported opcode. */
299 logout("opcode must be 1 or 2 but is %u\n", opcode
);
301 } else if (reg
> 6) {
302 /* Unsupported register. */
303 logout("register must be 0...6 but is %u\n", reg
);
306 TRACE(MDI
, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
307 val
, raiseint
, mdi_op_name
[opcode
], phy
,
308 mdi_reg_name
[reg
], data
));
312 case 0: /* Control Register */
314 /* Reset status and control registers to default. */
315 s
->mdimem
[0] = eepro100_mdi_default
[0];
316 s
->mdimem
[1] = eepro100_mdi_default
[1];
317 data
= s
->mdimem
[reg
];
319 /* Restart Auto Configuration = Normal Operation */
323 case 1: /* Status Register */
324 missing("not writable");
325 data
= s
->mdimem
[reg
];
327 case 2: /* PHY Identification Register (Word 1) */
328 case 3: /* PHY Identification Register (Word 2) */
329 missing("not implemented");
331 case 4: /* Auto-Negotiation Advertisement Register */
332 case 5: /* Auto-Negotiation Link Partner Ability Register */
334 case 6: /* Auto-Negotiation Expansion Register */
336 missing("not implemented");
338 s
->mdimem
[reg
] = data
;
339 } else if (opcode
== 2) {
342 case 0: /* Control Register */
344 /* Reset status and control registers to default. */
345 s
->mdimem
[0] = eepro100_mdi_default
[0];
346 s
->mdimem
[1] = eepro100_mdi_default
[1];
349 case 1: /* Status Register */
350 s
->mdimem
[reg
] |= 0x0020;
352 case 2: /* PHY Identification Register (Word 1) */
353 case 3: /* PHY Identification Register (Word 2) */
354 case 4: /* Auto-Negotiation Advertisement Register */
356 case 5: /* Auto-Negotiation Link Partner Ability Register */
357 s
->mdimem
[reg
] = 0x41fe;
359 case 6: /* Auto-Negotiation Expansion Register */
360 s
->mdimem
[reg
] = 0x0001;
363 data
= s
->mdimem
[reg
];
365 /* Emulation takes no time to finish MDI transaction.
366 * Set MDI bit in SCB status register. */
367 s
->mem
[SCBAck
] |= 0x08;
370 eepro100_mdi_interrupt(s
);
373 val
= (val
& 0xffff0000) + data
;
374 memcpy(&s
->mem
[0x10], &val
, sizeof(val
));