Mercurial > ecos
diff packages/devs/eth/phy/current/src/eth_phy.c @ 1178:0832585993c1
New abstractions to handle device specifics
| author | gthomas |
|---|---|
| date | Tue, 26 Aug 2003 17:54:00 +0000 |
| parents | 719dd033d039 |
| children | 0418d60dd8fb |
line wrap: on
line diff
--- a/packages/devs/eth/phy/current/src/eth_phy.c +++ b/packages/devs/eth/phy/current/src/eth_phy.c @@ -58,8 +58,15 @@ #include <cyg/hal/hal_arch.h> #include <cyg/hal/drv_api.h> #include <cyg/hal/hal_if.h> +#include <cyg/hal/hal_tables.h> #include <cyg/io/eth_phy.h> +#include <cyg/io/eth_phy_dev.h> + +// Define table boundaries +CYG_HAL_TABLE_BEGIN( __ETH_PHY_TAB__, _eth_phy_devs ); +CYG_HAL_TABLE_END( __ETH_PHY_TAB_END__, _eth_phy_devs ); +extern struct _eth_phy_dev_entry __ETH_PHY_TAB__[], __ETH_PHY_TAB_END__; // MII interface #define MII_Start 0x40000000 @@ -71,7 +78,7 @@ #define MII_TA 0x00020000 // -// PHY unit access (via MII channel) +// PHY unit access (via MII channel, using bit-level operations) // static cyg_uint32 @@ -82,23 +89,23 @@ phy_cmd(eth_phy_access_t *f, cyg_uint32 bool is_read = ((cmd & MII_Cmd) == MII_Read); // Set both bits as output - (f->set_dir)(1); + (f->ops.bit_level_ops.set_dir)(1); // Preamble for (i = 0; i < 32; i++) { - (f->set_clock)(0); - (f->set_data)(1); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } // Command/data for (i = 0, off = 31; i < (is_read ? 14 : 32); i++, --off) { - (f->set_clock)(0); - (f->set_data)((cmd >> off) & 0x00000001); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)((cmd >> off) & 0x00000001); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } @@ -108,49 +115,95 @@ phy_cmd(eth_phy_access_t *f, cyg_uint32 if (is_read) { retval >>= 16; - (f->set_clock)(0); - (f->set_dir)(0); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_dir)(0); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(0); + (f->ops.bit_level_ops.set_clock)(0); CYGACC_CALL_IF_DELAY_US(1); for (i = 0, off = 15; i < 16; i++, off--) { - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); retval <<= 1; - retval |= (f->get_data)(); + retval |= (f->ops.bit_level_ops.get_data)(); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(0); + (f->ops.bit_level_ops.set_clock)(0); CYGACC_CALL_IF_DELAY_US(1); } } // Set both bits as output - (f->set_dir)(1); + (f->ops.bit_level_ops.set_dir)(1); // Postamble for (i = 0; i < 32; i++) { - (f->set_clock)(0); - (f->set_data)(1); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } return retval; } -externC void +externC bool _eth_phy_init(eth_phy_access_t *f) { + int addr; + unsigned short state; + unsigned long id; + struct _eth_phy_dev_entry *dev; + + if (f->init_done) return true; + (f->init)(); + // Scan to determine PHY address + f->init_done = true; + for (addr = 0; addr < 0x20; addr++) { + if (_eth_phy_read(f, PHY_ID1, addr, &state)) { + id = state << 16; + if (_eth_phy_read(f, PHY_ID2, addr, &state)) { + id |= state; + f->phy_addr = addr; + for (dev = __ETH_PHY_TAB__; dev != &__ETH_PHY_TAB_END__; dev++) { + if (dev->id == id) { + diag_printf("PHY: %s\n", dev->name); + f->dev = dev; + return true; + } + } + diag_printf("Unsupported PHY device - id: %x\n", id); + break; // Can't handle this PHY + } + } + } + f->init_done = false; + return false; +} + +externC void +_eth_phy_reset(eth_phy_access_t *f) +{ + if (!f->init_done) { + diag_printf("PHY reset without init on PHY: %x\n", f); + return; + } (f->init)(); } externC void _eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data) { - phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data); + if (!f->init_done) { + diag_printf("PHY write without init on PHY: %x\n", f); + return; + } + if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) { + phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data); + } else { + (f->ops.reg_level_ops.put_reg)(reg, addr, data); + } } externC bool @@ -158,11 +211,79 @@ externC bool { cyg_uint32 ret; - ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA); - *val = ret; - return true; + if (!f->init_done) { + diag_printf("PHY read without init on PHY: %x\n", f); + return false; + } + if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) { + ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA); + *val = ret; + return true; + } else { + return (f->ops.reg_level_ops.get_reg)(reg, addr, val); + } } -externC void _eth_phy_init(eth_phy_access_t *f); -externC void _eth_phy_write(eth_phy_access_t *f, int reg, int unit, unsigned short data); -externC bool _eth_phy_read(eth_phy_access_t *f, int reg, int unit, unsigned short *val); +externC int +_eth_phy_cfg(eth_phy_access_t *f, int mode) +{ + int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear + bool phy_ok; + unsigned short reset_mode, phy_state; + int i; + + if (!f->init_done) { + diag_printf("PHY config without init on PHY: %x\n", f); + return; + } + + // Reset PHY (transceiver) + phy_ok = false; + _eth_phy_reset(f); + + _eth_phy_write(f, PHY_BMCR, f->phy_addr, PHY_BMCR_RESET); + for (i = 0; i < 5*100; i++) { + phy_ok = _eth_phy_read(f, PHY_BMCR, f->phy_addr, &phy_state); + diag_printf("PHY: %x\n", phy_state); + if (phy_ok && !(phy_state & PHY_BMCR_RESET)) break; + CYGACC_CALL_IF_DELAY_US(10000); // 10ms + } + if (!phy_ok || (phy_state & PHY_BMCR_RESET)) { + diag_printf("PPC405: Can't get PHY unit to soft reset: %x\n", phy_state); + return 0; + } + + reset_mode = PHY_BMCR_RESTART | PHY_BMCR_AUTO_NEG; + _eth_phy_write(f, PHY_BMCR, f->phy_addr, reset_mode); + while (phy_timeout-- >= 0) { + phy_ok = _eth_phy_read(f, PHY_BMSR, f->phy_addr, &phy_state); + if (phy_ok && (phy_state & PHY_BMSR_AUTO_NEG)) { + break; + } else { + CYGACC_CALL_IF_DELAY_US(10000); // 10ms + } + } + if (phy_timeout <= 0) { + diag_printf("** PPC405 Warning: PHY LINK UP failed: %04x\n", phy_state); + return 0; + } + + return _eth_phy_state(f); +} + +externC int +_eth_phy_state(eth_phy_access_t *f) +{ + int state = 0; + + if (!f->init_done) { + diag_printf("PHY state without init on PHY: %x\n", f); + return 0; + } + if ((f->dev->stat)(f, &state)) { + return state; + } else { + return 0; + } + return state; +}
