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,18 +30,18 @@ | ||
| 30 | 30 | ||
| 31 | #define D(x) | 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 | struct qemu_phy | 38 | struct qemu_phy |
| 40 | { | 39 | { |
| 41 | uint32_t regs[32]; | 40 | uint32_t regs[32]; |
| 42 | 41 | ||
| 43 | unsigned int (*read)(struct qemu_phy *phy, unsigned int req); | 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 | static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) | 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,11 +61,35 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) | ||
| 61 | r |= (1 << 3); /* Autoneg able. */ | 61 | r |= (1 << 3); /* Autoneg able. */ |
| 62 | r |= (1 << 2); /* Link. */ | 62 | r |= (1 << 2); /* Link. */ |
| 63 | break; | 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 | default: | 88 | default: |
| 65 | r = phy->regs[regnum]; | 89 | r = phy->regs[regnum]; |
| 66 | break; | 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 | return r; | 93 | return r; |
| 70 | } | 94 | } |
| 71 | 95 | ||
| @@ -86,6 +110,13 @@ tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) | @@ -86,6 +110,13 @@ tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) | ||
| 86 | static void | 110 | static void |
| 87 | tdk_init(struct qemu_phy *phy) | 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 | phy->read = tdk_read; | 120 | phy->read = tdk_read; |
| 90 | phy->write = tdk_write; | 121 | phy->write = tdk_write; |
| 91 | } | 122 | } |
| @@ -230,8 +261,8 @@ static void mdio_cycle(struct qemu_mdio *bus) | @@ -230,8 +261,8 @@ static void mdio_cycle(struct qemu_mdio *bus) | ||
| 230 | case DATA: | 261 | case DATA: |
| 231 | if (!bus->mdc) { | 262 | if (!bus->mdc) { |
| 232 | if (bus->drive) { | 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 | } else { | 267 | } else { |
| 237 | if (!bus->drive) { | 268 | if (!bus->drive) { |
| @@ -241,7 +272,9 @@ static void mdio_cycle(struct qemu_mdio *bus) | @@ -241,7 +272,9 @@ static void mdio_cycle(struct qemu_mdio *bus) | ||
| 241 | if (bus->cnt == 16 * 2) { | 272 | if (bus->cnt == 16 * 2) { |
| 242 | bus->cnt = 0; | 273 | bus->cnt = 0; |
| 243 | bus->state = PREAMBLE; | 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 | break; | 280 | break; |
| @@ -250,6 +283,11 @@ static void mdio_cycle(struct qemu_mdio *bus) | @@ -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 | struct fs_eth | 292 | struct fs_eth |
| 255 | { | 293 | { |
| @@ -398,15 +436,15 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len) | @@ -398,15 +436,15 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len) | ||
| 398 | } | 436 | } |
| 399 | 437 | ||
| 400 | static CPUReadMemoryFunc *eth_read[] = { | 438 | static CPUReadMemoryFunc *eth_read[] = { |
| 401 | - ð_rinvalid, | ||
| 402 | - ð_rinvalid, | ||
| 403 | - ð_readl, | 439 | + ð_rinvalid, |
| 440 | + ð_rinvalid, | ||
| 441 | + ð_readl, | ||
| 404 | }; | 442 | }; |
| 405 | 443 | ||
| 406 | static CPUWriteMemoryFunc *eth_write[] = { | 444 | static CPUWriteMemoryFunc *eth_write[] = { |
| 407 | - ð_winvalid, | ||
| 408 | - ð_winvalid, | ||
| 409 | - ð_writel, | 445 | + ð_winvalid, |
| 446 | + ð_winvalid, | ||
| 447 | + ð_writel, | ||
| 410 | }; | 448 | }; |
| 411 | 449 | ||
| 412 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | 450 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |