//
// dev/eth_phy.c
//
-// Ethernet transciever (PHY) support
+// Ethernet transceiver (PHY) support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
-// Contributors:
+// Contributors:
// Date: 2003-08-01
-// Purpose:
+// Purpose:
// Description: API support for ethernet PHY
-//
+//
//
//####DESCRIPTIONEND####
//
extern struct _eth_phy_dev_entry __ETH_PHY_TAB__[], __ETH_PHY_TAB_END__;
// MII interface
-#define MII_Start 0x40000000
-#define MII_Read 0x20000000
-#define MII_Write 0x10000000
-#define MII_Cmd 0x30000000
-#define MII_Phy(phy) (phy << 23)
-#define MII_Reg(reg) (reg << 18)
-#define MII_TA 0x00020000
+#define MII_Start 0x40000000
+#define MII_Read 0x20000000
+#define MII_Write 0x10000000
+#define MII_Cmd 0x30000000
+#define MII_Phy(phy) (phy << 23)
+#define MII_Reg(reg) (reg << 18)
+#define MII_TA 0x00020000
//
// PHY unit access (via MII channel, using bit-level operations)
static cyg_uint32
phy_cmd(eth_phy_access_t *f, cyg_uint32 cmd)
{
- cyg_uint32 retval;
- int i, off;
- bool is_read = (cmd & MII_Cmd) == MII_Read;
+ cyg_uint32 retval;
+ int i, off;
+ bool is_read = (cmd & MII_Cmd) == MII_Read;
- // Set both bits as output
- f->ops.bit_level_ops.set_dir(1);
+ // Set both bits as output
+ f->ops.bit_level_ops.set_dir(1);
- // Preamble
- for (i = 0; i < 32; i++) {
- f->ops.bit_level_ops.set_clock(0);
- f->ops.bit_level_ops.set_data(1);
- CYGACC_CALL_IF_DELAY_US(1);
- f->ops.bit_level_ops.set_clock(1);
- CYGACC_CALL_IF_DELAY_US(1);
- }
+ // Preamble
+ for (i = 0; i < 32; i++) {
+ f->ops.bit_level_ops.set_clock(0);
+ f->ops.bit_level_ops.set_data(1);
+ CYGACC_CALL_IF_DELAY_US(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->ops.bit_level_ops.set_clock(0);
- f->ops.bit_level_ops.set_data((cmd >> off) & 0x00000001);
- CYGACC_CALL_IF_DELAY_US(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->ops.bit_level_ops.set_clock(0);
+ f->ops.bit_level_ops.set_data((cmd >> off) & 0x00000001);
+ CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_clock(1);
+ CYGACC_CALL_IF_DELAY_US(1);
+ }
- retval = cmd;
+ retval = cmd;
- // If read, fetch data register
- if (is_read) {
- retval >>= 16;
+ // If read, fetch data register
+ if (is_read) {
+ retval >>= 16;
- f->ops.bit_level_ops.set_clock(0);
- f->ops.bit_level_ops.set_dir(0);
- CYGACC_CALL_IF_DELAY_US(1);
- f->ops.bit_level_ops.set_clock(1);
- CYGACC_CALL_IF_DELAY_US(1);
f->ops.bit_level_ops.set_clock(0);
- CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_dir(0);
+ CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_clock(1);
+ CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_clock(0);
+ CYGACC_CALL_IF_DELAY_US(1);
- for (i = 0, off = 15; i < 16; i++, off--) {
- f->ops.bit_level_ops.set_clock(1);
- retval <<= 1;
- retval |= f->ops.bit_level_ops.get_data();
- CYGACC_CALL_IF_DELAY_US(1);
- f->ops.bit_level_ops.set_clock(0);
- CYGACC_CALL_IF_DELAY_US(1);
- }
- }
+ for (i = 0, off = 15; i < 16; i++, off--) {
+ f->ops.bit_level_ops.set_clock(1);
+ retval <<= 1;
+ retval |= f->ops.bit_level_ops.get_data();
+ CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_clock(0);
+ CYGACC_CALL_IF_DELAY_US(1);
+ }
+ }
- // Set both bits as output
- f->ops.bit_level_ops.set_dir(1);
+ // Set both bits as output
+ f->ops.bit_level_ops.set_dir(1);
- // Postamble
- for (i = 0; i < 32; i++) {
- f->ops.bit_level_ops.set_clock(0);
- f->ops.bit_level_ops.set_data(1);
- CYGACC_CALL_IF_DELAY_US(1);
- f->ops.bit_level_ops.set_clock(1);
- CYGACC_CALL_IF_DELAY_US(1);
- }
+ // Postamble
+ for (i = 0; i < 32; i++) {
+ f->ops.bit_level_ops.set_clock(0);
+ f->ops.bit_level_ops.set_data(1);
+ CYGACC_CALL_IF_DELAY_US(1);
+ f->ops.bit_level_ops.set_clock(1);
+ CYGACC_CALL_IF_DELAY_US(1);
+ }
- return retval;
+ return retval;
}
externC bool
_eth_phy_init(eth_phy_access_t *f)
{
- int addr;
- unsigned short state;
- unsigned long id = 0;
- struct _eth_phy_dev_entry *dev;
+ int addr;
+ unsigned short state;
+ unsigned long id = 0;
+ 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) {
- eth_phy_printf("PHY: %s\n", dev->name);
- f->dev = dev;
- return true;
- }
- }
- }
- }
- }
- if (addr >= 0x20) {
- // Can't handle this PHY
- eth_phy_printf("Unsupported PHY device - id: %lx\n", id);
- }
- f->init_done = false;
- return false;
+ 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) {
+ eth_phy_printf("PHY: %s\n", dev->name);
+ f->dev = dev;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if (addr >= 0x20) {
+ // Can't handle this PHY
+ eth_phy_printf("Unsupported PHY device - id: %lx\n", id);
+ }
+ f->init_done = false;
+ return false;
}
externC void
_eth_phy_reset(eth_phy_access_t *f)
{
- if (!f->init_done) {
- eth_phy_printf("PHY reset without init on PHY: %p\n", f);
- return;
- }
- f->init();
+ if (!f->init_done) {
+ eth_phy_printf("PHY reset without init on PHY: %p\n", f);
+ return;
+ }
+ f->init();
}
externC void
_eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data)
{
- if (!f->init_done) {
- eth_phy_printf("PHY write without init on PHY: %p\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);
- }
+ if (!f->init_done) {
+ eth_phy_printf("PHY write without init on PHY: %p\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
_eth_phy_read(eth_phy_access_t *f, int reg, int addr, unsigned short *val)
{
- cyg_uint32 ret;
+ cyg_uint32 ret;
- if (!f->init_done) {
- eth_phy_printf("PHY read without init on PHY: %p\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);
- }
+ if (!f->init_done) {
+ eth_phy_printf("PHY read without init on PHY: %p\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 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;
+ 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) {
- eth_phy_printf("PHY config without init on PHY: %p\n", f);
- return 0;
- }
+ if (!f->init_done) {
+ eth_phy_printf("PHY config without init on PHY: %p\n", f);
+ return 0;
+ }
- // Reset PHY (transceiver)
- phy_ok = false;
- _eth_phy_reset(f);
+ // 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);
- eth_phy_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)) {
- eth_phy_printf("PPC405: Can't get PHY unit to soft reset: %x\n", phy_state);
- return 0;
- }
+ _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);
+ eth_phy_printf("PHY: %04x\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)) {
+ eth_phy_printf("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) {
- eth_phy_printf("** PPC405 Warning: PHY LINK UP failed: %04x\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) {
+ eth_phy_printf("**Warning: PHY LINK UP failed: %04x\n", phy_state);
+ return 0;
+ }
- return _eth_phy_state(f);
+ return _eth_phy_state(f);
}
externC int
_eth_phy_state(eth_phy_access_t *f)
{
- int state = 0;
+ int state = 0;
- if (!f->init_done) {
- eth_phy_printf("PHY state without init on PHY: %p\n", f);
- return 0;
- }
- if (f->dev->stat(f, &state)) {
- return state;
- } else {
- return 0;
- }
- return state;
+ if (!f->init_done) {
+ eth_phy_printf("PHY state without init on PHY: %p\n", f);
+ return 0;
+ }
+ if (f->dev->stat(f, &state)) {
+ return state;
+ } else {
+ return 0;
+ }
+ return state;
}