This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PHY - New abstractions and better device support


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);
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]