Commit 2e56350ef10e06373b4c6aa715bb2f8b3db50f51
1 parent
a37af289
ETRAX: Add some kind of support for simulating 802.3 auto-negotiation.
* Add support for link partner ability and diagnostics reg. * Correct the endianess for MDIO responses. * Dont trash PHY registers after reads. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4456 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
55 additions
and
17 deletions
hw/etraxfs_eth.c
| ... | ... | @@ -30,18 +30,18 @@ |
| 30 | 30 | |
| 31 | 31 | #define D(x) |
| 32 | 32 | |
| 33 | -#define R_STAT 0x2c | |
| 34 | -#define RW_MGM_CTRL 0x28 | |
| 35 | -#define FS_ETH_MAX_REGS 0x5c | |
| 36 | - | |
| 37 | - | |
| 38 | - | |
| 33 | +/* | |
| 34 | + * The MDIO extensions in the TDK PHY model were reversed engineered from the | |
| 35 | + * linux driver (PHYID and Diagnostics reg). | |
| 36 | + * TODO: Add friendly names for the register nums. | |
| 37 | + */ | |
| 39 | 38 | struct qemu_phy |
| 40 | 39 | { |
| 41 | 40 | uint32_t regs[32]; |
| 42 | 41 | |
| 43 | 42 | unsigned int (*read)(struct qemu_phy *phy, unsigned int req); |
| 44 | - void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); | |
| 43 | + void (*write)(struct qemu_phy *phy, unsigned int req, | |
| 44 | + unsigned int data); | |
| 45 | 45 | }; |
| 46 | 46 | |
| 47 | 47 | static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) |
| ... | ... | @@ -61,11 +61,35 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) |
| 61 | 61 | r |= (1 << 3); /* Autoneg able. */ |
| 62 | 62 | r |= (1 << 2); /* Link. */ |
| 63 | 63 | break; |
| 64 | + case 5: | |
| 65 | + /* Link partner ability. | |
| 66 | + We are kind; always agree with whatever best mode | |
| 67 | + the guest advertises. */ | |
| 68 | + r = 1 << 14; /* Success. */ | |
| 69 | + /* Copy advertised modes. */ | |
| 70 | + r |= phy->regs[4] & (15 << 5); | |
| 71 | + /* Autoneg support. */ | |
| 72 | + r |= 1; | |
| 73 | + break; | |
| 74 | + case 18: | |
| 75 | + { | |
| 76 | + /* Diagnostics reg. */ | |
| 77 | + int duplex = 0; | |
| 78 | + int speed_100 = 0; | |
| 79 | + | |
| 80 | + /* Are we advertising 100 half or 100 duplex ? */ | |
| 81 | + speed_100 = !!(phy->regs[4] & 0x180); | |
| 82 | + /* Are we advertising 10 duplex or 100 duplex ? */ | |
| 83 | + duplex = !!(phy->regs[4] & 0x180); | |
| 84 | + r = (speed_100 << 10) | (duplex << 11); | |
| 85 | + } | |
| 86 | + break; | |
| 87 | + | |
| 64 | 88 | default: |
| 65 | 89 | r = phy->regs[regnum]; |
| 66 | 90 | break; |
| 67 | 91 | } |
| 68 | - D(printf("%s %x = reg[%d]\n", __func__, r, regnum)); | |
| 92 | + D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); | |
| 69 | 93 | return r; |
| 70 | 94 | } |
| 71 | 95 | |
| ... | ... | @@ -86,6 +110,13 @@ tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) |
| 86 | 110 | static void |
| 87 | 111 | tdk_init(struct qemu_phy *phy) |
| 88 | 112 | { |
| 113 | + phy->regs[0] = 0x3100; | |
| 114 | + /* PHY Id. */ | |
| 115 | + phy->regs[2] = 0x0300; | |
| 116 | + phy->regs[3] = 0xe400; | |
| 117 | + /* Autonegotiation advertisement reg. */ | |
| 118 | + phy->regs[4] = 0x01E1; | |
| 119 | + | |
| 89 | 120 | phy->read = tdk_read; |
| 90 | 121 | phy->write = tdk_write; |
| 91 | 122 | } |
| ... | ... | @@ -230,8 +261,8 @@ static void mdio_cycle(struct qemu_mdio *bus) |
| 230 | 261 | case DATA: |
| 231 | 262 | if (!bus->mdc) { |
| 232 | 263 | if (bus->drive) { |
| 233 | - bus->mdio = bus->data & 1; | |
| 234 | - bus->data >>= 1; | |
| 264 | + bus->mdio = !!(bus->data & (1 << 15)); | |
| 265 | + bus->data <<= 1; | |
| 235 | 266 | } |
| 236 | 267 | } else { |
| 237 | 268 | if (!bus->drive) { |
| ... | ... | @@ -241,7 +272,9 @@ static void mdio_cycle(struct qemu_mdio *bus) |
| 241 | 272 | if (bus->cnt == 16 * 2) { |
| 242 | 273 | bus->cnt = 0; |
| 243 | 274 | bus->state = PREAMBLE; |
| 244 | - mdio_write_req(bus); | |
| 275 | + if (!bus->drive) | |
| 276 | + mdio_write_req(bus); | |
| 277 | + bus->drive = 0; | |
| 245 | 278 | } |
| 246 | 279 | } |
| 247 | 280 | break; |
| ... | ... | @@ -250,6 +283,11 @@ static void mdio_cycle(struct qemu_mdio *bus) |
| 250 | 283 | } |
| 251 | 284 | } |
| 252 | 285 | |
| 286 | +/* ETRAX-FS Ethernet MAC block starts here. */ | |
| 287 | + | |
| 288 | +#define R_STAT 0x2c | |
| 289 | +#define RW_MGM_CTRL 0x28 | |
| 290 | +#define FS_ETH_MAX_REGS 0x5c | |
| 253 | 291 | |
| 254 | 292 | struct fs_eth |
| 255 | 293 | { |
| ... | ... | @@ -398,15 +436,15 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len) |
| 398 | 436 | } |
| 399 | 437 | |
| 400 | 438 | static CPUReadMemoryFunc *eth_read[] = { |
| 401 | - ð_rinvalid, | |
| 402 | - ð_rinvalid, | |
| 403 | - ð_readl, | |
| 439 | + ð_rinvalid, | |
| 440 | + ð_rinvalid, | |
| 441 | + ð_readl, | |
| 404 | 442 | }; |
| 405 | 443 | |
| 406 | 444 | static CPUWriteMemoryFunc *eth_write[] = { |
| 407 | - ð_winvalid, | |
| 408 | - ð_winvalid, | |
| 409 | - ð_writel, | |
| 445 | + ð_winvalid, | |
| 446 | + ð_winvalid, | |
| 447 | + ð_writel, | |
| 410 | 448 | }; |
| 411 | 449 | |
| 412 | 450 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | ... | ... |