This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
PHY - New abstractions and better device support
- From: Gary Thomas <gary at mlbassoc dot com>
- To: eCos patches <ecos-patches at sources dot redhat dot com>
- Date: 26 Aug 2003 11:56:36 -0600
- Subject: PHY - New abstractions and better device support
- Organization: MLB Associates
The PHY support is now more generalized and has been
tested with both a bit-level MII access (Rattler/MPC8250)
and a high level MII access (PPC405GPr)
Also, by utilizing the HAL tables mechanism, PHY device
drivers could be anywhere, not just in this package.
--
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: devs/eth/phy/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/phy/current/ChangeLog,v
retrieving revision 1.1
diff -u -5 -p -r1.1 ChangeLog
--- devs/eth/phy/current/ChangeLog 19 Aug 2003 17:26:48 -0000 1.1
+++ devs/eth/phy/current/ChangeLog 26 Aug 2003 17:52:15 -0000
@@ -1,5 +1,15 @@
+2003-08-26 Gary Thomas <gary@mlbassoc.com>
+
+ * src/DP83847.c:
+ * src/AM79C874.c: New file(s) - driver(s) for PHY devices.
+
+ * src/eth_phy.c:
+ * include/eth_phy_dev.h:
+ * include/eth_phy.h:
+ * cdl/phy_eth_drivers.cdl: Add device/chip specific drivers.
+
2003-08-19 Gary Thomas <gary@mlbassoc.com>
* src/eth_phy.c:
* include/eth_phy.h:
* cdl/phy_eth_drivers.cdl: New file(s) - generic API for dealing
Index: devs/eth/phy/current/cdl/phy_eth_drivers.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/phy/current/cdl/phy_eth_drivers.cdl,v
retrieving revision 1.1
diff -u -5 -p -r1.1 phy_eth_drivers.cdl
--- devs/eth/phy/current/cdl/phy_eth_drivers.cdl 19 Aug 2003 17:26:49 -0000 1.1
+++ devs/eth/phy/current/cdl/phy_eth_drivers.cdl 26 Aug 2003 17:36:52 -0000
@@ -57,6 +57,24 @@ cdl_package CYGPKG_DEVS_ETH_PHY {
active_if CYGPKG_IO_ETH_DRIVERS
include_dir cyg/io
compile eth_phy.c
+
+ cdl_option CYGHWR_DEVS_ETH_PHY_DP83847 {
+ display "NSDP83847"
+ flavor bool
+ default_value 0
+ compile -library=libextras.a DP83847.c
+ description "
+ Include support for National Semiconductor DP83847 DsPHYTER II"
+ }
+
+ cdl_option CYGHWR_DEVS_ETH_PHY_AM79C874 {
+ display "AMD 79C874"
+ flavor bool
+ default_value 0
+ compile -library=libextras.a AM79C874.c
+ description "
+ Include support for AMD 79C874 NetPHY"
+ }
}
Index: devs/eth/phy/current/include/eth_phy.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/phy/current/include/eth_phy.h,v
retrieving revision 1.1
diff -u -5 -p -r1.1 eth_phy.h
--- devs/eth/phy/current/include/eth_phy.h 19 Aug 2003 17:26:50 -0000 1.1
+++ devs/eth/phy/current/include/eth_phy.h 26 Aug 2003 17:14:55 -0000
@@ -2,11 +2,11 @@
#define CYGONCE_DEVS_ETH_PHY_H_
//==========================================================================
//
// eth_phy.h
//
-// API for ethernet transciever (PHY) support
+// User API for ethernet transciever (PHY) support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
@@ -50,40 +50,52 @@
//
//####DESCRIPTIONEND####
//
//==========================================================================
-
-// Transceiver mode
-#define PHY_BMCR 0x00 // Register number
-#define PHY_BMCR_RESET 0x8000
-#define PHY_BMCR_LOOPBACK 0x4000
-#define PHY_BMCR_100MB 0x2000
-#define PHY_BMCR_AUTO_NEG 0x1000
-#define PHY_BMCR_POWER_DOWN 0x0800
-#define PHY_BMCR_ISOLATE 0x0400
-#define PHY_BMCR_RESTART 0x0200
-#define PHY_BMCR_FULL_DUPLEX 0x0100
-#define PHY_BMCR_COLL_TEST 0x0080
-
-#define PHY_BMSR 0x01 // Status register
-#define PHY_BMSR_AUTO_NEG 0x0020
-#define PHY_BMSR_LINK 0x0004
+#define PHY_BIT_LEVEL_ACCESS_TYPE 0
+#define PHY_REG_LEVEL_ACCESS_TYPE 1
// Physical device access - defined by hardware instance
typedef struct {
+ int ops_type; // 0 => bit level, 1 => register level
+ bool init_done;
void (*init)(void);
- void (*set_data)(int);
- int (*get_data)(void);
- void (*set_clock)(int);
- void (*set_dir)(int);
+ void (*reset)(void);
+ union {
+ struct {
+ void (*set_data)(int);
+ int (*get_data)(void);
+ void (*set_clock)(int);
+ void (*set_dir)(int);
+ } bit_level_ops;
+ struct {
+ void (*put_reg)(int reg, int unit, unsigned short data);
+ bool (*get_reg)(int reg, int unit, unsigned short *data);
+ } reg_level_ops;
+ } ops;
+ int phy_addr;
+ struct _eth_phy_dev_entry *dev; // Chip access functions
} eth_phy_access_t;
-#define ETH_PHY_ACCESS_FUNS(_l,_init,_set_data,_get_data,_set_clock,_set_dir) \
-static eth_phy_access_t _l = {_init, _set_data, _get_data, _set_clock, _set_dir}
-
-externC void _eth_phy_init(eth_phy_access_t *f);
+#define ETH_PHY_BIT_LEVEL_ACCESS_FUNS(_l,_init,_reset,_set_data,_get_data,_set_clock,_set_dir) \
+static eth_phy_access_t _l = {PHY_BIT_LEVEL_ACCESS_TYPE, false, _init, _reset, \
+ {.bit_level_ops = {_set_data, _get_data, _set_clock, _set_dir}}}
+
+#define ETH_PHY_REG_LEVEL_ACCESS_FUNS(_l,_init,_reset,_put_reg,_get_reg) \
+static eth_phy_access_t _l = {PHY_REG_LEVEL_ACCESS_TYPE, false, _init, _reset, \
+ {.reg_level_ops = {_put_reg, _get_reg}}}
+
+#define ETH_PHY_STAT_LINK 0x0001 // Link up/down
+#define ETH_PHY_STAT_100MB 0x0002 // Connection is 100Mb
+#define ETH_PHY_STAT_FDX 0x0004 // Connection is full duplex
+
+externC bool _eth_phy_init(eth_phy_access_t *f);
+externC void _eth_phy_reset(eth_phy_access_t *f);
+externC int _eth_phy_state(eth_phy_access_t *f);
+externC int _eth_phy_cfg(eth_phy_access_t *f, int mode);
+// Internal routines
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);
#endif // CYGONCE_DEVS_ETH_PHY_H_
// ------------------------------------------------------------------------
Index: devs/eth/phy/current/include/eth_phy_dev.h
===================================================================
RCS file: devs/eth/phy/current/include/eth_phy_dev.h
diff -N devs/eth/phy/current/include/eth_phy_dev.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/phy/current/include/eth_phy_dev.h 26 Aug 2003 17:14:55 -0000
@@ -0,0 +1,91 @@
+#ifndef CYGONCE_DEVS_ETH_PHY_DEV_H_
+#define CYGONCE_DEVS_ETH_PHY_DEV_H_
+//==========================================================================
+//
+// eth_phy_dev.h
+//
+// Device API for ethernet transciever (PHY) support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2003-08-01
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// Transceiver mode
+#define PHY_BMCR 0x00 // Register number
+#define PHY_BMCR_RESET 0x8000
+#define PHY_BMCR_LOOPBACK 0x4000
+#define PHY_BMCR_100MB 0x2000
+#define PHY_BMCR_AUTO_NEG 0x1000
+#define PHY_BMCR_POWER_DOWN 0x0800
+#define PHY_BMCR_ISOLATE 0x0400
+#define PHY_BMCR_RESTART 0x0200
+#define PHY_BMCR_FULL_DUPLEX 0x0100
+#define PHY_BMCR_COLL_TEST 0x0080
+
+#define PHY_BMSR 0x01 // Status register
+#define PHY_BMSR_100T4 0x8000
+#define PHY_BMSR_100FDX 0x4000
+#define PHY_BMSR_100HDX 0x2000
+#define PHY_BMSR_10FDX 0x1000
+#define PHY_BMSR_10HDX 0x0800
+#define PHY_BMSR_AUTO_NEG 0x0020
+#define PHY_BMSR_LINK 0x0004
+
+#define PHY_ID1 0x02 // Chip ID register (high 16 bits)
+#define PHY_ID2 0x03 // Chip ID register (low 16 bits)
+
+struct _eth_phy_dev_entry {
+ char *name;
+ unsigned long id;
+ bool (*stat)(eth_phy_access_t *f, int *stat);
+} CYG_HAL_TABLE_TYPE;
+
+#define _eth_phy_dev(_name_,_id_,_stat_) \
+struct _eth_phy_dev_entry _eth_phy_dev_##_id_ \
+ CYG_HAL_TABLE_QUALIFIED_ENTRY(_eth_phy_devs,_id_) = \
+ { _name_, _id_, _stat_ };
+
+#endif // CYGONCE_DEVS_ETH_PHY_DEV_H_
+// ------------------------------------------------------------------------
Index: devs/eth/phy/current/src/AM79C874.c
===================================================================
RCS file: devs/eth/phy/current/src/AM79C874.c
diff -N devs/eth/phy/current/src/AM79C874.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/phy/current/src/AM79C874.c 26 Aug 2003 17:49:05 -0000
@@ -0,0 +1,101 @@
+//==========================================================================
+//
+// dev/AM79C874.c
+//
+// Ethernet transciever (PHY) support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors:
+// Date: 2003-08-01
+// Purpose:
+// Description: Support for ethernet NS AM79C874 PHY
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/diag.h>
+
+#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>
+
+static bool am79c874_stat(eth_phy_access_t *f, int *state)
+{
+ unsigned short phy_state;
+ int tries;
+
+ // Read negotiated state
+ if (_eth_phy_read(f, 0x1, f->phy_addr, &phy_state)) {
+ if ((phy_state & 0x20) == 0) {
+ diag_printf("... waiting for auto-negotiation");
+ for (tries = 0; tries < 15; tries++) {
+ if (_eth_phy_read(f, 0x1, f->phy_addr, &phy_state)) {
+ if ((phy_state & 0x20) != 0) {
+ break;
+ }
+ }
+ CYGACC_CALL_IF_DELAY_US(1000000); // 1 second
+ diag_printf(".");
+ }
+ diag_printf("\n");
+ }
+ if ((phy_state & 0x20) != 0) {
+ *state = 0;
+ if ((phy_state & 0x0004) != 0) *state |= ETH_PHY_STAT_LINK;
+ if (_eth_phy_read(f, 0x5, f->phy_addr, &phy_state)) {
+ // Partner negotiated parameters
+ if ((phy_state & 0x0100) != 0) *state |= ETH_PHY_STAT_100MB | ETH_PHY_STAT_FDX;
+ if ((phy_state & 0x0080) != 0) *state |= ETH_PHY_STAT_100MB;
+ if ((phy_state & 0x0040) != 0) *state |= ETH_PHY_STAT_FDX;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+_eth_phy_dev("AMD AM79C874", 0x0022561B, am79c874_stat)
Index: devs/eth/phy/current/src/DP83847.c
===================================================================
RCS file: devs/eth/phy/current/src/DP83847.c
diff -N devs/eth/phy/current/src/DP83847.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ devs/eth/phy/current/src/DP83847.c 26 Aug 2003 17:14:55 -0000
@@ -0,0 +1,97 @@
+//==========================================================================
+//
+// dev/DP83847.c
+//
+// Ethernet transciever (PHY) support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors:
+// Date: 2003-08-01
+// Purpose:
+// Description: Support for ethernet NS DP83847 PHY
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/diag.h>
+
+#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>
+
+static bool dp83847_stat(eth_phy_access_t *f, int *state)
+{
+ unsigned short phy_state;
+ int tries;
+
+ // Read negotiated state
+ if (_eth_phy_read(f, 0x10, f->phy_addr, &phy_state)) {
+ if ((phy_state & 0x10) == 0) {
+ diag_printf("... waiting for auto-negotiation");
+ for (tries = 0; tries < 15; tries++) {
+ if (_eth_phy_read(f, 0x10, f->phy_addr, &phy_state)) {
+ if ((phy_state & 0x10) != 0) {
+ break;
+ }
+ }
+ CYGACC_CALL_IF_DELAY_US(1000000); // 1 second
+ diag_printf(".");
+ }
+ diag_printf("\n");
+ }
+ if ((phy_state & 0x10) != 0) {
+ *state = 0;
+ if ((phy_state & 0x0001) != 0) *state |= ETH_PHY_STAT_LINK;
+ if ((phy_state & 0x0002) == 0) *state |= ETH_PHY_STAT_100MB;
+ if ((phy_state & 0x0004) != 0) *state |= ETH_PHY_STAT_FDX;
+ return true;
+ }
+ }
+ return false;
+}
+
+_eth_phy_dev("National Semiconductor DP83847", 0x20005c30, dp83847_stat)
Index: devs/eth/phy/current/src/eth_phy.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/phy/current/src/eth_phy.c,v
retrieving revision 1.1
diff -u -5 -p -r1.1 eth_phy.c
--- devs/eth/phy/current/src/eth_phy.c 19 Aug 2003 17:26:51 -0000 1.1
+++ devs/eth/phy/current/src/eth_phy.c 26 Aug 2003 17:14:55 -0000
@@ -56,12 +56,19 @@
#include <cyg/infra/diag.h>
#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
#define MII_Read 0x20000000
#define MII_Write 0x10000000
@@ -69,100 +76,214 @@
#define MII_Phy(phy) (phy << 23)
#define MII_Reg(reg) (reg << 18)
#define MII_TA 0x00020000
//
-// PHY unit access (via MII channel)
+// 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);
// 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);
}
retval = cmd;
// If read, fetch data register
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
_eth_phy_read(eth_phy_access_t *f, int reg, int addr, unsigned short *val)
{
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;
+}
Index: devs/eth/powerpc/fcc/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/fcc/current/ChangeLog,v
retrieving revision 1.1
diff -u -5 -p -r1.1 ChangeLog
--- devs/eth/powerpc/fcc/current/ChangeLog 19 Aug 2003 17:29:42 -0000 1.1
+++ devs/eth/powerpc/fcc/current/ChangeLog 26 Aug 2003 17:52:38 -0000
@@ -1,5 +1,9 @@
+2003-08-26 Gary Thomas <gary@mlbassoc.com>
+
+ * src/if_fcc.c: Use new PHY support.
+
2003-08-19 Gary Thomas <gary@mlbassoc.com>
* src/if_fcc.c:
* src/fcc.h:
* cdl/fcc_eth_drivers.cdl: New file(s) - generic ethernet driver
Index: devs/eth/powerpc/fcc/current/src/if_fcc.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/fcc/current/src/if_fcc.c,v
retrieving revision 1.1
diff -u -5 -p -r1.1 if_fcc.c
--- devs/eth/powerpc/fcc/current/src/if_fcc.c 19 Aug 2003 17:29:43 -0000 1.1
+++ devs/eth/powerpc/fcc/current/src/if_fcc.c 26 Aug 2003 17:48:11 -0000
@@ -156,10 +156,13 @@ fcc_eth_init(struct cyg_netdevtab_entry
unsigned long rxbase, txbase;
struct fcc_bd *rxbd, *txbd;
// The FCC seems rather picky about these...
static long rxbd_base = 0x3000;
static long txbd_base = 0xB000;
+#ifdef CYGPKG_DEVS_ETH_PHY
+ unsigned short phy_state = 0;
+#endif
// Set up pointers to FCC controller
switch (qi->int_vector) {
case CYGNUM_HAL_INTERRUPT_FCC1:
qi->fcc_reg = &(IMM->fcc_regs[FCC1]);
@@ -304,53 +307,38 @@ fcc_eth_init(struct cyg_netdevtab_entry
fcc_chan |
CPCR_MCN_FCC |
CPCR_FLG; /* ISSUE COMMAND */
while ((IMM->cpm_cpcr & CPCR_FLG) != CPCR_READY_TO_RX_CMD);
+ // Operating mode
+ if (!_eth_phy_init(qi->phy)) {
+ return false;
+ }
#ifdef CYGSEM_DEVS_ETH_POWERPC_FCC_RESET_PHY
- {
- unsigned short phy_state;
- unsigned short reset_mode;
- int phy_unit = 0;
- int phy_ok;
- int phy_timeout = 5*100;
-
- // Reset PHY (transceiver)
- _eth_phy_init(qi->phy);
-
- if (_eth_phy_read(qi->phy, PHY_BMSR, phy_unit, &phy_state)) {
- if ((phy_state & PHY_BMSR_LINK) != PHY_BMSR_LINK) {
- _eth_phy_write(qi->phy, PHY_BMCR, phy_unit, PHY_BMCR_RESET);
- for (i = 0; i < 10; i++) {
- phy_ok = _eth_phy_read(qi->phy, PHY_BMCR, phy_unit, &phy_state);
- if (!phy_ok) break;
- if (!(phy_state & PHY_BMCR_RESET)) break;
- }
- if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
- diag_printf("%s: Can't get PHY unit to soft reset: %x\n", dtp->name, phy_state);
- return false;
- }
- reset_mode = PHY_BMCR_RESTART | PHY_BMCR_AUTO_NEG | PHY_BMCR_FULL_DUPLEX;
- _eth_phy_write(qi->phy, PHY_BMCR, phy_unit, reset_mode);
- while (phy_timeout-- >= 0) {
- phy_ok = _eth_phy_read(qi->phy, PHY_BMSR, phy_unit, &phy_state);
- if (phy_ok && (phy_state & PHY_BMSR_LINK)) {
- break;
- } else {
- CYGACC_CALL_IF_DELAY_US(10000); // 10ms
- }
- }
- if (phy_timeout <= 0) {
- diag_printf("** %s Warning: PHY LINK UP failed\n", dtp->name);
- }
- }
- else {
- diag_printf("** %s Info: PHY LINK already UP \n", dtp->name);
- }
+ if (!_eth_phy_reset(qi->phy)) {
+ return false;
+ }
+#endif
+ phy_state = _eth_phy_state(qi->phy);
+ os_printf("FCC ETH: ");
+ if ((phy_state & ETH_PHY_STAT_LINK) != 0) {
+ if ((phy_state & ETH_PHY_STAT_100MB) != 0) {
+ // Link can handle 100Mb
+ os_printf("100Mb");
+ if ((phy_state & ETH_PHY_STAT_FDX) != 0) {
+ os_printf("/Full Duplex");
+ }
+ } else {
+ // Assume 10Mb, half duplex
+ os_printf("10Mb");
}
+ } else {
+ os_printf("/***NO LINK***");
+ return false;
}
-#endif // CYGSEM_DEVS_ETH_POWERPC_FCC_RESET_PHY
+ os_printf("\n");
+
// Initialize upper level driver for ecos
(sc->funs->eth_drv->init)(sc, (unsigned char *)&qi->enaddr);
return true;
Index: devs/eth/powerpc/rattler/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/rattler/current/ChangeLog,v
retrieving revision 1.1
diff -u -5 -p -r1.1 ChangeLog
--- devs/eth/powerpc/rattler/current/ChangeLog 19 Aug 2003 17:29:44 -0000 1.1
+++ devs/eth/powerpc/rattler/current/ChangeLog 26 Aug 2003 17:53:09 -0000
@@ -1,5 +1,10 @@
+2003-08-26 Gary Thomas <gary@mlbassoc.com>
+
+ * include/rattler_eth.inl:
+ * cdl/rattler_eth_drivers.cdl: Update PHY support, using AMD AM79C874.
+
2003-08-19 Gary Thomas <gary@mlbassoc.com>
* include/rattler_eth.inl:
* cdl/rattler_eth_drivers.cdl: New file(s) - platform specifics
for ethernet drivers on Analogue & Micro Rattler (MPC8250) board.
Index: devs/eth/powerpc/rattler/current/cdl/rattler_eth_drivers.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/rattler/current/cdl/rattler_eth_drivers.cdl,v
retrieving revision 1.1
diff -u -5 -p -r1.1 rattler_eth_drivers.cdl
--- devs/eth/powerpc/rattler/current/cdl/rattler_eth_drivers.cdl 19 Aug 2003 17:29:45 -0000 1.1
+++ devs/eth/powerpc/rattler/current/cdl/rattler_eth_drivers.cdl 26 Aug 2003 17:38:25 -0000
@@ -59,10 +59,11 @@ cdl_package CYGPKG_DEVS_ETH_POWERPC_RATT
active_if CYGPKG_HAL_POWERPC
active_if CYGPKG_HAL_POWERPC_MPC8XXX
requires CYGPKG_DEVS_ETH_POWERPC_FCC
requires CYGPKG_HAL_POWERPC_RATTLER
+ requires CYGHWR_DEVS_ETH_PHY_AM79C874
cdl_option CYGHWR_DEVS_ETH_POWERPC_RATTLER_FCC1 {
display "Include fcc1/eth0 ethernet device"
default_value 1
description "
Index: devs/eth/powerpc/rattler/current/include/rattler_eth.inl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/rattler/current/include/rattler_eth.inl,v
retrieving revision 1.1
diff -u -5 -p -r1.1 rattler_eth.inl
--- devs/eth/powerpc/rattler/current/include/rattler_eth.inl 19 Aug 2003 17:29:45 -0000 1.1
+++ devs/eth/powerpc/rattler/current/include/rattler_eth.inl 26 Aug 2003 17:19:12 -0000
@@ -69,16 +69,26 @@
//
static void
fcc1_phy_init(void)
{
// Set up PHY reset line
- IMM->io_regs[PORT_B].pdat &= ~FCC1_PHY_RESET;
IMM->io_regs[PORT_B].pdat |= FCC1_PHY_RESET;
IMM->io_regs[PORT_C].pdir |= FCC1_PHY_CLOCK;
}
//
+// Reset the PHY associated with FCC1/eth0
+//
+static void
+fcc1_phy_reset(void)
+{
+ // Toggle PHY reset line
+ IMM->io_regs[PORT_B].pdat &= ~FCC1_PHY_RESET;
+ IMM->io_regs[PORT_B].pdat |= FCC1_PHY_RESET;
+}
+
+//
// Set up a particular data bit for FCC1/eth0
//
static void
fcc1_phy_set_data(int val)
{
@@ -133,12 +143,13 @@ fcc1_phy_set_dir(int data_dir)
// Input
IMM->io_regs[PORT_C].pdir &= ~FCC1_PHY_DATA;
}
}
-ETH_PHY_ACCESS_FUNS(fcc1_phy,
+ETH_PHY_BIT_LEVEL_ACCESS_FUNS(fcc1_phy,
fcc1_phy_init,
+ fcc1_phy_reset,
fcc1_phy_set_data,
fcc1_phy_get_data,
fcc1_phy_set_clock,
fcc1_phy_set_dir);
@@ -191,16 +202,26 @@ NETDEVTAB_ENTRY(fcc_eth0_netdev,
//
static void
fcc2_phy_init(void)
{
// Set up PHY reset line
- IMM->io_regs[PORT_B].pdat &= ~FCC2_PHY_RESET;
IMM->io_regs[PORT_B].pdat |= FCC2_PHY_RESET;
IMM->io_regs[PORT_C].pdir |= FCC2_PHY_CLOCK;
}
//
+// Reset the PHY associated with FCC2/eth1
+//
+static void
+fcc2_phy_reset(void)
+{
+ // Toggle the PHY reset line
+ IMM->io_regs[PORT_B].pdat &= ~FCC2_PHY_RESET;
+ IMM->io_regs[PORT_B].pdat |= FCC2_PHY_RESET;
+}
+
+//
// Set up a particular data bit for FCC2/eth1
//
static void
fcc2_phy_set_data(int val)
{
@@ -255,12 +276,13 @@ fcc2_phy_set_dir(int data_dir)
// Input
IMM->io_regs[PORT_C].pdir &= ~FCC2_PHY_DATA;
}
}
-ETH_PHY_ACCESS_FUNS(fcc2_phy,
+ETH_PHY_BIT_LEVEL_ACCESS_FUNS(fcc2_phy,
fcc2_phy_init,
+ fcc2_phy_reset,
fcc2_phy_set_data,
fcc2_phy_get_data,
fcc2_phy_set_clock,
fcc2_phy_set_dir);