OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [eth/] [phy/] [current/] [src/] [eth_phy.c] - Blame information for rev 808

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      dev/eth_phy.c
4
//
5
//      Ethernet transciever (PHY) support 
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2003, 2004 Free Software Foundation, Inc.                  
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: 
44
// Date:         2003-08-01
45
// Purpose:      
46
// Description:  API support for ethernet PHY
47
//              
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/system.h>
54
#include <pkgconf/io_eth_drivers.h>
55
#include <pkgconf/devs_eth_phy.h>
56
#include <cyg/infra/cyg_type.h>
57
 
58
#include <cyg/hal/hal_arch.h>
59
#include <cyg/hal/drv_api.h>
60
#include <cyg/hal/hal_if.h>
61
#include <cyg/hal/hal_tables.h>
62
 
63
#include <cyg/io/eth_phy.h>
64
#include <cyg/io/eth_phy_dev.h>
65
 
66
// Define table boundaries
67
CYG_HAL_TABLE_BEGIN( __ETH_PHY_TAB__, _eth_phy_devs );
68
CYG_HAL_TABLE_END( __ETH_PHY_TAB_END__, _eth_phy_devs );
69
extern struct _eth_phy_dev_entry __ETH_PHY_TAB__[], __ETH_PHY_TAB_END__;
70
 
71
// MII interface
72
#define MII_Start            0x40000000
73
#define MII_Read             0x20000000
74
#define MII_Write            0x10000000
75
#define MII_Cmd              0x30000000
76
#define MII_Phy(phy)         (phy << 23)
77
#define MII_Reg(reg)         (reg << 18)
78
#define MII_TA               0x00020000
79
 
80
//
81
// PHY unit access (via MII channel, using bit-level operations)
82
//
83
 
84
static cyg_uint32
85
phy_cmd(eth_phy_access_t *f, cyg_uint32 cmd)
86
{
87
    cyg_uint32  retval;
88
    int         i, off;
89
    bool        is_read = ((cmd & MII_Cmd) == MII_Read);
90
 
91
    // Set both bits as output
92
    (f->ops.bit_level_ops.set_dir)(1);
93
 
94
    // Preamble
95
    for (i = 0; i < 32; i++) {
96
        (f->ops.bit_level_ops.set_clock)(0);
97
        (f->ops.bit_level_ops.set_data)(1);
98
        CYGACC_CALL_IF_DELAY_US(1);
99
        (f->ops.bit_level_ops.set_clock)(1);
100
        CYGACC_CALL_IF_DELAY_US(1);
101
    }
102
 
103
    // Command/data
104
    for (i = 0, off = 31; i < (is_read ? 14 : 32); i++, --off) {
105
        (f->ops.bit_level_ops.set_clock)(0);
106
        (f->ops.bit_level_ops.set_data)((cmd >> off) & 0x00000001);
107
        CYGACC_CALL_IF_DELAY_US(1);
108
        (f->ops.bit_level_ops.set_clock)(1);
109
        CYGACC_CALL_IF_DELAY_US(1);
110
    }
111
 
112
    retval = cmd;
113
 
114
    // If read, fetch data register
115
    if (is_read) {
116
        retval >>= 16;
117
 
118
        (f->ops.bit_level_ops.set_clock)(0);
119
        (f->ops.bit_level_ops.set_dir)(0);
120
        CYGACC_CALL_IF_DELAY_US(1);
121
        (f->ops.bit_level_ops.set_clock)(1);
122
        CYGACC_CALL_IF_DELAY_US(1);
123
        (f->ops.bit_level_ops.set_clock)(0);
124
        CYGACC_CALL_IF_DELAY_US(1);
125
 
126
        for (i = 0, off = 15; i < 16; i++, off--) {
127
            (f->ops.bit_level_ops.set_clock)(1);
128
            retval <<= 1;
129
            retval |= (f->ops.bit_level_ops.get_data)();
130
            CYGACC_CALL_IF_DELAY_US(1);
131
            (f->ops.bit_level_ops.set_clock)(0);
132
            CYGACC_CALL_IF_DELAY_US(1);
133
        }
134
    }
135
 
136
    // Set both bits as output
137
    (f->ops.bit_level_ops.set_dir)(1);
138
 
139
    // Postamble
140
    for (i = 0; i < 32; i++) {
141
        (f->ops.bit_level_ops.set_clock)(0);
142
        (f->ops.bit_level_ops.set_data)(1);
143
        CYGACC_CALL_IF_DELAY_US(1);
144
        (f->ops.bit_level_ops.set_clock)(1);
145
        CYGACC_CALL_IF_DELAY_US(1);
146
    }
147
 
148
    return retval;
149
}
150
 
151
externC bool
152
_eth_phy_init(eth_phy_access_t *f)
153
{
154
    int addr;
155
    unsigned short state;
156
    unsigned long id = 0;
157
    struct _eth_phy_dev_entry *dev;
158
 
159
    if (f->init_done) return true;
160
    (f->init)();
161
    // Scan to determine PHY address
162
    f->init_done = true;
163
    for (addr = 0;  addr < 0x20;  addr++) {
164
        if (_eth_phy_read(f, PHY_ID1, addr, &state)) {
165
            id = state << 16;
166
            if (_eth_phy_read(f, PHY_ID2, addr, &state)) {
167
                id |= state;
168
                f->phy_addr = addr;
169
                for (dev = __ETH_PHY_TAB__; dev != &__ETH_PHY_TAB_END__;  dev++) {
170
                    if (dev->id == id) {
171
                        eth_phy_printf("PHY: %s at addr %x\n", dev->name, f->phy_addr);
172
                        f->dev = dev;
173
                        return true;
174
                    }
175
                }
176
            }
177
        }
178
    }
179
    if (addr >= 0x20)
180
    {
181
        // Can't handle this PHY
182
        eth_phy_printf("Unsupported PHY device - id: %x\n", id);
183
    }
184
    f->init_done = false;
185
    return false;
186
}
187
 
188
externC void
189
_eth_phy_reset(eth_phy_access_t *f)
190
{
191
    if (!f->init_done) {
192
        eth_phy_printf("PHY reset without init on PHY: %x\n", f);
193
        return;
194
    }
195
    (f->init)();
196
}
197
 
198
externC void
199
_eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data)
200
{
201
    if (!f->init_done) {
202
        eth_phy_printf("PHY write without init on PHY: %x\n", f);
203
        return;
204
    }
205
    if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) {
206
        phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data);
207
    } else {
208
        (f->ops.reg_level_ops.put_reg)(reg, addr, data);
209
    }
210
}
211
 
212
externC bool
213
_eth_phy_read(eth_phy_access_t *f, int reg, int addr, unsigned short *val)
214
{
215
    cyg_uint32 ret;
216
 
217
    if (!f->init_done) {
218
        eth_phy_printf("PHY read without init on PHY: %x\n", f);
219
        return false;
220
    }
221
    if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) {
222
        ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA);
223
        *val = ret;
224
        return true;
225
    } else {
226
        return (f->ops.reg_level_ops.get_reg)(reg, addr, val);
227
    }
228
}
229
 
230
externC int
231
_eth_phy_cfg(eth_phy_access_t *f, int mode)
232
{
233
    int phy_timeout = 5*1000;  // Wait 5 seconds max for link to clear
234
    bool phy_ok;
235
    unsigned short reset_mode, phy_state;
236
    int i;
237
 
238
    if (!f->init_done) {
239
        eth_phy_printf("PHY config without init on PHY: %x\n", f);
240
        return 0;
241
    }
242
 
243
    // Reset PHY (transceiver)
244
    phy_ok = false;
245
    _eth_phy_reset(f);
246
 
247
    _eth_phy_write(f, PHY_BMCR, f->phy_addr, PHY_BMCR_RESET);
248
    for (i = 0;  i < 5*100;  i++) {
249
        phy_ok = _eth_phy_read(f, PHY_BMCR, f->phy_addr, &phy_state);
250
        eth_phy_printf("PHY: %x\n", phy_state);
251
        if (phy_ok && !(phy_state & PHY_BMCR_RESET)) break;
252
        CYGACC_CALL_IF_DELAY_US(10000);   // 10ms
253
    }
254
    if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
255
        eth_phy_printf("PPC405: Can't get PHY unit to soft reset: %x\n", phy_state);
256
        return 0;
257
    }
258
 
259
    reset_mode = PHY_BMCR_RESTART | PHY_BMCR_AUTO_NEG;
260
    _eth_phy_write(f, PHY_BMCR, f->phy_addr, reset_mode);
261
    while (phy_timeout-- >= 0) {
262
        phy_ok = _eth_phy_read(f, PHY_BMSR, f->phy_addr, &phy_state);
263
        if (phy_ok && (phy_state & PHY_BMSR_AUTO_NEG)) {
264
            break;
265
        } else {
266
            CYGACC_CALL_IF_DELAY_US(10000);   // 10ms
267
        }
268
    }
269
    if (phy_timeout <= 0) {
270
        eth_phy_printf("** PPC405 Warning: PHY LINK UP failed: %04x\n", phy_state);
271
        return 0;
272
    }
273
 
274
    return _eth_phy_state(f);
275
}
276
 
277
externC int
278
_eth_phy_state(eth_phy_access_t *f)
279
{
280
    int state = 0;
281
 
282
    if (!f->init_done) {
283
        eth_phy_printf("PHY state without init on PHY: %x\n", f);
284
        return 0;
285
    }
286
    if ((f->dev->stat)(f, &state)) {
287
        return state;
288
    } else {
289
        return 0;
290
    }
291
    return state;
292
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.