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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [eth/] [sh/] [etherc/] [v2_0/] [src/] [if_etherc.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      dev/if_etherc.c
4
//
5
//      Ethernet device driver for SH EtherC CPU module controller
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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 version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):    jskov
44
// Contributors: jskov
45
// Date:         2002-01-30
46
// Purpose:      
47
// Description:  Hardware driver for SH EtherC CPU module controller
48
//
49
// Notes:        The KEEP_STATISTICS code is not implemented yet. Look
50
//               for FIXME macro.
51
//
52
//####DESCRIPTIONEND####
53
//
54
//==========================================================================
55
 
56
#include <pkgconf/system.h>
57
#include <pkgconf/devs_eth_sh_etherc.h>
58
#include <pkgconf/io_eth_drivers.h>
59
 
60
#include <cyg/infra/cyg_type.h>
61
#include <cyg/hal/hal_arch.h>
62
#include <cyg/hal/hal_intr.h>
63
#include <cyg/infra/cyg_ass.h>
64
#include <cyg/infra/diag.h>
65
#include <cyg/hal/drv_api.h>
66
#include <cyg/hal/hal_if.h>             // delays
67
#include <string.h>
68
#include <cyg/io/eth/netdev.h>
69
#include <cyg/io/eth/eth_drv.h>
70
#ifdef CYGPKG_NET
71
#include <pkgconf/net.h>
72
#include <cyg/kernel/kapi.h>
73
#include <net/if.h>  /* Needed for struct ifnet */
74
#include <pkgconf/io_eth_drivers.h>
75
#endif
76
#include CYGHWR_MEMORY_LAYOUT_H
77
 
78
#define FIXME 0
79
 
80
// Set size so it is 16-byte aligned
81
#define _BUF_SIZE (1544+8)
82
 
83
#define IEEE_8023_MIN_FRAME           64    // Smallest possible ethernet frame
84
 
85
#ifdef CYGPKG_INFRA_DEBUG
86
// Then we log, OOI, the number of times we get a bad packet number
87
// from the tx done fifo.
88
int etherc_txfifo_good = 0;
89
int etherc_txfifo_bad = 0;
90
#endif
91
 
92
#include "sh_etherc.h"
93
#define __WANT_DEVS
94
#include CYGDAT_DEVS_ETH_SH_ETHERC_INL
95
#undef  __WANT_DEVS
96
 
97
static void       etherc_poll(struct eth_drv_sc *sc);
98
 
99
static cyg_uint16 etherc_read_MII(struct etherc_priv_data *cpd, int id, int reg);
100
static void       etherc_write_MII(struct etherc_priv_data *cpd, int id, int reg, cyg_uint16 value);
101
#define _MII_READ(_priv_, _id_, _reg_) etherc_read_MII(_priv_, _id_, _reg_)
102
#define _MII_WRITE(_priv_, _id_, _reg_, _val_) etherc_write_MII(_priv_, _id_, _reg_, _val_)
103
#define _MII_HAS_EXTENDED
104
#include "phyter.inl"
105
 
106
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
107
// This ISR is called when the ethernet interrupt occurs
108
static cyg_uint32
109
etherc_isr(cyg_vector_t vector, cyg_addrword_t data)
110
{
111
    struct etherc_priv_data *cpd = (struct etherc_priv_data *)data;
112
 
113
    DEBUG_FUNCTION();
114
 
115
    INCR_STAT( interrupts );
116
 
117
    cyg_drv_interrupt_mask(cpd->interrupt);
118
    cyg_drv_interrupt_acknowledge(cpd->interrupt);
119
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
120
}
121
 
122
static void
123
etherc_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
124
{
125
    // This conditioning out is necessary because of explicit calls to this
126
    // DSR - which would not ever be called in the case of a polled mode
127
    // usage ie. in RedBoot.
128
#ifdef CYGPKG_IO_ETH_DRIVERS_NET
129
    struct etherc_priv_data* cpd = (struct etherc_priv_data *)data;
130
    struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp);
131
    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
132
 
133
    // but here, it must be a *sc:
134
    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
135
#else
136
# ifndef CYGPKG_REDBOOT
137
#  error Empty Etherc ethernet DSR is compiled.  Is this what you want?
138
# endif
139
#endif
140
}
141
#endif // CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
142
 
143
 
144
// The deliver function (ex-DSR)  handles the ethernet [logical] processing
145
static void
146
etherc_deliver(struct eth_drv_sc *sc)
147
{
148
    struct etherc_priv_data *cpd =
149
        (struct etherc_priv_data *)sc->driver_private;
150
 
151
    DEBUG_FUNCTION();
152
 
153
    // Service the interrupt:
154
    etherc_poll(sc);
155
    // Allow interrupts to happen again
156
    cyg_drv_interrupt_unmask(cpd->interrupt);
157
}
158
 
159
static int
160
etherc_int_vector(struct eth_drv_sc *sc)
161
{
162
    struct etherc_priv_data *cpd =
163
        (struct etherc_priv_data *)sc->driver_private;
164
 
165
    return (cpd->interrupt);
166
}
167
 
168
 
169
static bool
170
sh_etherc_init(struct cyg_netdevtab_entry *tab)
171
{
172
    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
173
    struct etherc_priv_data *cpd =
174
        (struct etherc_priv_data *)sc->driver_private;
175
    cyg_uint8 *p, *d;
176
    cyg_uint32 reg;
177
    int i;
178
    bool esa_configured = true;
179
 
180
    DEBUG_FUNCTION();
181
 
182
    cpd->txbusy = 0;
183
 
184
    // Ensure that addresses of ring descriptors and buffers are properly aligned
185
    // and in uncached memory.
186
    cpd->rx_buffers = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->rx_buffers+16-1) & ~(16-1));
187
    cpd->rx_ring = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->rx_ring+16-1) & ~(16-1));
188
    cpd->tx_buffers = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->tx_buffers+16-1) & ~(16-1));
189
    cpd->tx_ring = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->tx_ring+16-1) & ~(16-1));
190
 
191
#if DEBUG & 8
192
    db_printf("Etherc at base 0x%08x\n", cpd->base);
193
#endif
194
 
195
    // Find ESA - check possible sources in sequence and stop when
196
    // one provides the ESA:
197
    //   RedBoot option (via provide_esa)
198
    //   Compile-time configuration
199
    //   EEPROM
200
    //   <fail configuration of device>
201
    if (NULL != cpd->provide_esa) {
202
        esa_configured = cpd->provide_esa(cpd);
203
# if DEBUG & 8
204
        if (esa_configured)
205
            diag_printf("Got ESA from RedBoot option\n");
206
# endif
207
    }
208
    if (!esa_configured && cpd->hardwired_esa) {
209
        // ESA is already set in cpd->esa[]
210
        esa_configured = true;
211
    }
212
    if (!esa_configured) {
213
# if DEBUG & 8
214
        diag_printf("EtherC - no EEPROM, static ESA or RedBoot config option.\n");
215
# endif
216
        return false;
217
    }
218
 
219
#if DEBUG & 9
220
    db_printf("ETHERC ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
221
                cpd->esa[0], cpd->esa[1], cpd->esa[2],
222
                cpd->esa[3], cpd->esa[4], cpd->esa[5] );
223
#endif
224
 
225
    // Prepare RX and TX rings
226
    p = cpd->rx_ring;
227
    d = cpd->rx_buffers;
228
    for (i = 0; i < cpd->rx_ring_cnt; i++) {
229
        _SU32(p, ETHERC_RD_STAT) = ETHERC_RD_STAT_RACT | ETHERC_RD_STAT_RFP_OTO;
230
        _SU16(p, ETHERC_RD_RBL) = _BUF_SIZE;
231
        _SU16(p, ETHERC_RD_RDL) = 0;
232
        _SU32(p, ETHERC_RD_RBA) = (cyg_uint32)d;
233
        _SU32(p, ETHERC_RD_PAD) = 0;
234
        p += ETHERC_RD_SIZE;
235
        d += _BUF_SIZE;
236
    }
237
    // Set ring-end marker
238
    p -= ETHERC_RD_SIZE;
239
    _SU32(p, ETHERC_RD_STAT) |= ETHERC_RD_STAT_RDLE;
240
    cpd->rx_ring_next = 0;
241
 
242
    p = cpd->tx_ring;
243
    d = cpd->tx_buffers;
244
    for (i = 0; i < cpd->tx_ring_cnt; i++) {
245
        _SU32(p, ETHERC_TD_STAT) = ETHERC_TD_STAT_TFP_OTO;
246
        _SU16(p, ETHERC_TD_TDL) = 0;
247
        _SU16(p, ETHERC_TD_PAD0) = 0;
248
        _SU32(p, ETHERC_TD_TBA) = (cyg_uint32)d;
249
        _SU32(p, ETHERC_TD_PAD1) = 0;
250
        p += ETHERC_TD_SIZE;
251
        d += _BUF_SIZE;
252
    }
253
    // Set ring-end marker
254
    p -= ETHERC_RD_SIZE;
255
    _SU32(p, ETHERC_TD_STAT) |= ETHERC_TD_STAT_TDLE;
256
    cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
257
 
258
    // Reset ethernet module, then wait for (at least) 16 clocks.
259
    put_reg(cpd, _REG_EDMR, CYGARC_REG_EDMR_SWR | CYGARC_REG_EDMR_DL16);
260
    for (i = 0; i < 16; i++);
261
    put_reg(cpd, _REG_EDMR, CYGARC_REG_EDMR_DL16);
262
 
263
    // Program ring data into controller
264
    put_reg(cpd, _REG_RDLAR, (cyg_uint32)cpd->rx_ring);
265
    put_reg(cpd, _REG_TDLAR, (cyg_uint32)cpd->tx_ring);
266
 
267
    // Set ESA
268
    put_reg(cpd, _REG_MAHR, (cpd->esa[0] << 24) | (cpd->esa[1] << 16) | (cpd->esa[2] << 8) | cpd->esa[3]);
269
    put_reg(cpd, _REG_MALR, (cpd->esa[4] << 8) | cpd->esa[5]);
270
 
271
    // Set receive mode: receive continuously
272
    put_reg(cpd, _REG_RCR, CYGARC_REG_RCR_RNC);
273
 
274
    // Stop controller, set duplex mode
275
    put_reg(cpd, _REG_ECMR, CYGARC_REG_ECMR_DM);
276
    cpd->active = 0;
277
 
278
    // Clear pending interrupt flags
279
    reg = get_reg(cpd, _REG_EESR);
280
    put_reg(cpd, _REG_EESR, reg);
281
 
282
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
283
    // Attach ISR/DSRs.
284
    cpd->interrupt = CYGNUM_HAL_INTERRUPT_EDMAC_EINT;
285
    cyg_drv_interrupt_create(cpd->interrupt,
286
                             1,                   // Priority
287
                             (cyg_addrword_t)cpd, // Data item passed to ISR & DSR
288
                             etherc_isr,          // ISR
289
                             etherc_dsr,          // DSR
290
                             &cpd->interrupt_handle, // handle to intr obj
291
                             &cpd->interrupt_object ); // space for int obj
292
 
293
    cyg_drv_interrupt_attach(cpd->interrupt_handle);
294
    cyg_drv_interrupt_unmask(cpd->interrupt);
295
    put_reg(cpd, _REG_EESIPR, CYGARC_REG_EESIPR_TCIP|CYGARC_REG_EESIPR_FRIP);
296
#if DEBUG & 8
297
    db_printf("Attached interrupt on vector %d\n", cpd->interrupt);
298
#endif
299
#endif
300
 
301
    // Record the net dev pointer
302
    cpd->ndp = (void *)tab;
303
 
304
 
305
    // Initialize the PHY
306
#ifdef CYGSEM_DEVS_ETH_SH_ETHERC_FORCE_10MBPS
307
#if DEBUG & 8
308
    db_printf("Forcing 10Mb link\n");
309
#endif
310
    _MII_SPEED_FORCE_10MB(cpd, 1);
311
    _MII_RENEGOTIATE(cpd, 1);
312
#else
313
    // Wait for automatic negotiation to complete
314
    _MII_RENEGOTIATION_WAIT(cpd, 1);
315
#endif
316
 
317
    // Initialize upper level driver
318
    (sc->funs->eth_drv->init)(sc, cpd->esa);
319
 
320
#if DEBUG & 9
321
    db_printf("Done\n");
322
#endif
323
    return true;
324
}
325
 
326
static void
327
etherc_suspend(struct etherc_priv_data *cpd)
328
{
329
    cyg_uint32 reg;
330
#if 0
331
    bool still_active;
332
#endif
333
 
334
    reg = get_reg(cpd, _REG_ECMR);
335
    reg &= ~(CYGARC_REG_ECMR_TE | CYGARC_REG_ECMR_RE);
336
    put_reg(cpd, _REG_ECMR, reg);
337
 
338
#if 0 // 
339
    // Try to find out if controller stopped. Supposedly, it should
340
    // communicate this by clearing the active signal of the active
341
    // RX/TX descriptors.
342
 
343
    // Check RX
344
    do {
345
        still_active = false;
346
        reg = get_reg(cpd, _REG_RDFAR);
347
#if 1
348
        {
349
            int i;
350
            cyg_uint8* p;
351
            p = cpd->rx_ring;
352
            for (i = 0; i < cpd->rx_ring_cnt; i++) {
353
                if ((cyg_uint32)p == reg) {
354
                    if (_SU32(reg, ETHERC_RD_STAT) & ETHERC_RD_STAT_RACT) {
355
                        still_active = true;
356
                        break;
357
                    }
358
                }
359
            }
360
        }
361
#else
362
        if (_SU32(reg, ETHERC_RD_STAT) & ETHERC_RD_STAT_RACT)
363
            still_active = true;
364
#endif
365
    } while (still_active);
366
 
367
    // Check TX
368
    do {
369
        still_active = false;
370
        reg = get_reg(cpd, _REG_TDFAR);
371
#if 1
372
        {
373
            int i;
374
            cyg_uint8* p;
375
            p = cpd->tx_ring;
376
            for (i = 0; i < cpd->tx_ring_cnt; i++) {
377
                if ((cyg_uint32)p == reg) {
378
                    if (_SU32(reg, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT) {
379
                        still_active = true;
380
                        break;
381
                    }
382
                }
383
            }
384
        }
385
#else
386
        if (_SU32(reg, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT)
387
            still_active = true;
388
#endif
389
    } while (still_active);
390
 
391
    db_printf("all done\n");
392
#endif
393
    cpd->active = 0;
394
}
395
 
396
static void
397
etherc_stop(struct eth_drv_sc *sc)
398
{
399
    struct etherc_priv_data *cpd =
400
        (struct etherc_priv_data *)sc->driver_private;
401
 
402
    DEBUG_FUNCTION();
403
 
404
    etherc_suspend(cpd);
405
}
406
 
407
//
408
// This function is called to "start up" the interface.  It may be called
409
// multiple times, even when the hardware is already running.  It will be
410
// called whenever something "hardware oriented" changes and should leave
411
// the hardware ready to send/receive packets.
412
//
413
static void
414
etherc_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
415
{
416
    cyg_uint32 reg, prm_mode = 0;
417
    struct etherc_priv_data *cpd =
418
        (struct etherc_priv_data *)sc->driver_private;
419
#ifdef CYGPKG_NET
420
    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
421
#endif
422
    DEBUG_FUNCTION();
423
 
424
    // If device is already active, suspend it
425
    if (cpd->active) {
426
        etherc_suspend(cpd);
427
    }
428
 
429
#ifdef CYGPKG_NET
430
    if (( 0
431
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
432
          != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
433
#endif
434
            ) || (ifp->if_flags & IFF_PROMISC)
435
        ) {
436
        // Then we select promiscuous mode.
437
        prm_mode = CYGARC_REG_ECMR_PRM;
438
    }
439
#endif
440
 
441
    // Unsuspend the device
442
    reg = get_reg(cpd, _REG_ECMR);
443
    reg |= CYGARC_REG_ECMR_TE | CYGARC_REG_ECMR_RE;
444
    reg &= ~CYGARC_REG_ECMR_PRM;
445
    reg |= prm_mode;
446
    put_reg(cpd, _REG_ECMR, reg);
447
 
448
    put_reg(cpd, _REG_EDRRR, CYGARC_REG_EDRRR_RR);
449
 
450
    cpd->active = 1;
451
}
452
 
453
//
454
// This routine is called to perform special "control" opertions
455
//
456
static int
457
etherc_control(struct eth_drv_sc *sc, unsigned long key,
458
               void *data, int data_length)
459
{
460
    cyg_uint8 *esa = (cyg_uint8 *)data;
461
    int i, res;
462
    cyg_uint16 reg;
463
    struct etherc_priv_data *cpd =
464
        (struct etherc_priv_data *)sc->driver_private;
465
    cyg_bool was_active = cpd->active;
466
 
467
    DEBUG_FUNCTION();
468
 
469
    // If device is already active, suspend it
470
    if (cpd->active) {
471
        etherc_suspend(cpd);
472
    }
473
 
474
    res = 0;                            // expect success
475
    switch (key) {
476
    case ETH_DRV_SET_MAC_ADDRESS:
477
#if 9 & DEBUG
478
        db_printf("ETHERC - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
479
                esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );
480
#endif // DEBUG
481
 
482
        for ( i = 0; i < sizeof(cpd->esa);  i++ )
483
            cpd->esa[i] = esa[i];
484
        put_reg(cpd, _REG_MAHR,(cpd->esa[0] << 24) | (cpd->esa[1] << 16) | (cpd->esa[2] << 8) | cpd->esa[3]);
485
        put_reg(cpd, _REG_MALR, (cpd->esa[4] << 8) | cpd->esa[5]);
486
        break;
487
 
488
#ifdef ETH_DRV_GET_MAC_ADDRESS
489
    case ETH_DRV_GET_MAC_ADDRESS:
490
        // Extract the MAC address that is in the chip, and tell the
491
        // system about it.
492
        cyg_uint32 reg;
493
        reg = get_reg(cpd, _REG_MAHR);
494
        cpd->esa[0] = (reg >> 24) & 0xff;
495
        cpd->esa[1] = (reg >> 16) & 0xff;
496
        cpd->esa[2] = (reg >> 08) & 0xff;
497
        cpd->esa[3] = (reg >> 00) & 0xff;
498
        reg = get_reg(cpd, _REG_MALR);
499
        cpd->esa[4] = (reg >> 08) & 0xff;
500
        cpd->esa[5] = (reg >> 00) & 0xff;
501
        break;
502
#endif
503
 
504
#ifdef ETH_DRV_GET_IF_STATS_UD
505
    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
506
#endif
507
        // drop through
508
#ifdef ETH_DRV_GET_IF_STATS
509
    case ETH_DRV_GET_IF_STATS:
510
#endif
511
 
512
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
513
    {
514
        struct ether_drv_stats *p = (struct ether_drv_stats *)data;
515
        // Chipset entry is no longer supported; RFC1573.
516
        for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
517
            p->snmp_chipset[i] = 0;
518
 
519
        // This perhaps should be a config opt, so you can make up your own
520
        // description, or supply it from the instantiation.
521
        strcpy( p->description, "SH Etherc" );
522
        // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
523
 
524
        if (_MII_LINK_STATE(cpd, 1)) {
525
            // Link is up
526
            p->operational = 3;         // LINK UP
527
            if (_MII_DUPLEX_STATE(cpd, 1))
528
                p->duplex = 3;              // 3 = DUPLEX
529
            else
530
                p->duplex = 2;              // 2 = SIMPLEX
531
            if (_MII_SPEED_STATE(cpd, 1))
532
                p->speed = 100 * 1000000;
533
            else
534
                p->speed = 10 * 1000000;
535
        } else {
536
            // Link is down
537
            p->operational = 2;         // LINK DOWN
538
            p->duplex = 1;              // UNKNOWN
539
            p->speed = 0;
540
        }
541
#if FIXME
542
#ifdef KEEP_STATISTICS
543
        {
544
            struct sh_etherc_stats *ps = &(cpd->stats);
545
 
546
            // Admit to it...
547
            p->supports_dot3        = true;
548
 
549
            p->tx_good              = ps->tx_good             ;
550
            p->tx_max_collisions    = ps->tx_max_collisions   ;
551
            p->tx_late_collisions   = ps->tx_late_collisions  ;
552
            p->tx_underrun          = ps->tx_underrun         ;
553
            p->tx_carrier_loss      = ps->tx_carrier_loss     ;
554
            p->tx_deferred          = ps->tx_deferred         ;
555
            p->tx_sqetesterrors     = ps->tx_sqetesterrors    ;
556
            p->tx_single_collisions = ps->tx_single_collisions;
557
            p->tx_mult_collisions   = ps->tx_mult_collisions  ;
558
            p->tx_total_collisions  = ps->tx_total_collisions ;
559
            p->rx_good              = ps->rx_good             ;
560
            p->rx_crc_errors        = ps->rx_crc_errors       ;
561
            p->rx_align_errors      = ps->rx_align_errors     ;
562
            p->rx_resource_errors   = ps->rx_resource_errors  ;
563
            p->rx_overrun_errors    = ps->rx_overrun_errors   ;
564
            p->rx_collisions        = ps->rx_collisions       ;
565
            p->rx_short_frames      = ps->rx_short_frames     ;
566
            p->rx_too_long_frames   = ps->rx_too_long_frames  ;
567
            p->rx_symbol_errors     = ps->rx_symbol_errors    ;
568
 
569
            p->interrupts           = ps->interrupts          ;
570
            p->rx_count             = ps->rx_count            ;
571
            p->rx_deliver           = ps->rx_deliver          ;
572
            p->rx_resource          = ps->rx_resource         ;
573
            p->rx_restart           = ps->rx_restart          ;
574
            p->tx_count             = ps->tx_count            ;
575
            p->tx_complete          = ps->tx_complete         ;
576
            p->tx_dropped           = ps->tx_dropped          ;
577
        }
578
#endif // KEEP_STATISTICS
579
#endif // FIXME
580
 
581
        p->tx_queue_len = 1;
582
        break;
583
    }
584
#endif
585
    default:
586
        res = 1;
587
        break;
588
    }
589
 
590
    // Restore controller state
591
    if (was_active) {
592
        // Unsuspend the device
593
        reg = get_reg(cpd, _REG_ECMR);
594
        reg |= CYGARC_REG_ECMR_RE | CYGARC_REG_ECMR_TE;
595
        put_reg(cpd, _REG_ECMR, reg);
596
    }
597
 
598
    return res;
599
}
600
 
601
//
602
// This routine is called to see if it is possible to send another packet.
603
// It will return non-zero if a transmit is possible, zero otherwise.
604
//
605
static int
606
etherc_can_send(struct eth_drv_sc *sc)
607
{
608
    struct etherc_priv_data *cpd =
609
        (struct etherc_priv_data *)sc->driver_private;
610
 
611
    DEBUG_FUNCTION();
612
 
613
    if (!_MII_LINK_STATE(cpd, 1))
614
        return 0;                       // Link not connected
615
 
616
    return (0 == cpd->txbusy);
617
}
618
 
619
//
620
// This routine is called to send data to the hardware.
621
static void
622
etherc_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
623
            int total_len, unsigned long key)
624
{
625
    struct etherc_priv_data *cpd =
626
        (struct etherc_priv_data *)sc->driver_private;
627
    int i, len, plen, ring_entry;
628
 
629
    cyg_uint8* sdata = NULL;
630
    cyg_uint8 *d, *buf, *txd;
631
 
632
    DEBUG_FUNCTION();
633
 
634
    INCR_STAT( tx_count );
635
 
636
    cpd->txbusy = 1;
637
    cpd->txkey = key;
638
 
639
    // Find packet length
640
    plen = 0;
641
    for (i = 0;  i < sg_len;  i++)
642
        plen += sg_list[i].len;
643
 
644
    CYG_ASSERT( plen == total_len, "sg data length mismatch" );
645
 
646
    // Get next TX descriptor
647
    ring_entry = cpd->tx_ring_free;
648
    do {
649
        if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
650
            // Is this a dead end? Probably is.
651
#if DEBUG & 1
652
            db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
653
#endif
654
            continue;
655
        }
656
 
657
        cpd->tx_ring_free++;
658
        cpd->tx_ring_owned++;
659
        if (cpd->tx_ring_free == cpd->tx_ring_cnt)
660
            cpd->tx_ring_free = 0;
661
    } while (0);
662
 
663
    txd = cpd->tx_ring + ring_entry*ETHERC_TD_SIZE;
664
    buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
665
    CYG_ASSERT(0 == (_SU32(txd, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT),
666
               "TX descriptor not free");
667
 
668
#if DEBUG & 4
669
    db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
670
                txd, buf);
671
#endif
672
 
673
    // Put data into buffer
674
    d = buf;
675
    for (i = 0;  i < sg_len;  i++) {
676
        sdata = (cyg_uint8 *)sg_list[i].buf;
677
        len = sg_list[i].len;
678
 
679
        CYG_ASSERT( sdata, "No sg data pointer here" );
680
        while(len--)
681
            *d++ = *sdata++;
682
    }
683
    CYG_ASSERT( sdata, "No sg data pointer outside" );
684
 
685
    if (plen < IEEE_8023_MIN_FRAME) {
686
#if DEBUG & 1
687
        db_printf("Packet too short (%d) - padding to %d bytes.\n", plen, IEEE_8023_MIN_FRAME);
688
#endif
689
        for (i = plen; i < IEEE_8023_MIN_FRAME; i++)
690
            *d++ = 0;
691
        plen = IEEE_8023_MIN_FRAME;
692
    }
693
 
694
    _SU16(txd, ETHERC_TD_TDL) = plen;
695
    _SU32(txd, ETHERC_TD_STAT) |= ETHERC_TD_STAT_TACT;
696
 
697
#if DEBUG & 1
698
    db_printf("Last TX: LEN %04x STAT %08x PTR %08x\n",
699
              _SU16(txd, ETHERC_TD_TDL),
700
              _SU32(txd, ETHERC_TD_STAT),
701
              _SU32(txd, ETHERC_TD_TBA));
702
#endif
703
 
704
    // Set transmit demand
705
    put_reg(cpd, _REG_EDTRR, CYGARC_REG_EDTRR_TR);
706
 
707
#if DEBUG & 1
708
    {
709
        cyg_uint32 reg;
710
        reg = get_reg(cpd, _REG_EESR);
711
        db_printf("%s:END: EESR at TX: 0x%08x\n", __FUNCTION__, reg);
712
    }
713
#endif
714
}
715
 
716
static void
717
etherc_TxEvent(struct eth_drv_sc *sc, int stat)
718
{
719
     struct etherc_priv_data *cpd =
720
        (struct etherc_priv_data *)sc->driver_private;
721
    int success = 1;
722
    cyg_uint8 *txd;
723
    cyg_uint32 pkt_stat;
724
 
725
    DEBUG_FUNCTION();
726
 
727
    if (0 == cpd->tx_ring_owned) {
728
#if DEBUG & 1
729
        db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
730
#endif
731
        // Ack the TX int
732
        put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_TC);
733
        return;
734
    }
735
 
736
 
737
    INCR_STAT( tx_complete );
738
 
739
    txd = cpd->tx_ring + cpd->tx_ring_alloc*ETHERC_TD_SIZE;
740
    pkt_stat = _SU32(txd, ETHERC_TD_STAT);
741
    if (pkt_stat & ETHERC_TD_STAT_TACT) {
742
#if DEBUG & 1
743
        db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
744
#endif
745
        // first dirty ring entry not freed - wtf?
746
    }
747
 
748
    if (pkt_stat & ETHERC_TD_STAT_TDFE) {
749
        // We had an error. Tell the stack.
750
        success = 0;
751
#if DEBUG & 1
752
        db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
753
#endif
754
    }
755
 
756
    cpd->tx_ring_alloc++;
757
    if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)
758
        cpd->tx_ring_alloc = 0;
759
    cpd->tx_ring_owned--;
760
 
761
#if FIXME
762
#ifdef KEEP_STATISTICS
763
    {
764
        cyg_uint16 reg;
765
 
766
        reg = get_reg( sc, ETHERC_CSR_CSCR );
767
 
768
        // Covering each bit in turn...
769
        if ( reg & ETHERC_STATUS_TX_UNRN   ) INCR_STAT( tx_underrun );
770
        //if ( reg & ETHERC_STATUS_LINK_OK ) INCR_STAT(  );
771
        //if ( reg & ETHERC_STATUS_CTR_ROL ) INCR_STAT(  );
772
        //if ( reg & ETHERC_STATUS_EXC_DEF ) INCR_STAT(  );
773
        if ( reg & ETHERC_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
774
        if ( reg & ETHERC_STATUS_LATCOL    ) INCR_STAT( tx_late_collisions );
775
        //if ( reg & ETHERC_STATUS_WAKEUP  ) INCR_STAT(  );
776
        if ( reg & ETHERC_STATUS_TX_DEFR   ) INCR_STAT( tx_deferred );
777
        //if ( reg & ETHERC_STATUS_LTX_BRD ) INCR_STAT(  );
778
        if ( reg & ETHERC_STATUS_SQET      ) INCR_STAT( tx_sqetesterrors );
779
        if ( reg & ETHERC_STATUS_16COL     ) INCR_STAT( tx_max_collisions );
780
        //if ( reg & ETHERC_STATUS_LTX_MULT) INCR_STAT(  );
781
        if ( reg & ETHERC_STATUS_MUL_COL   ) INCR_STAT( tx_mult_collisions );
782
        if ( reg & ETHERC_STATUS_SNGL_COL  ) INCR_STAT( tx_single_collisions );
783
        if ( reg & ETHERC_STATUS_TX_SUC    ) INCR_STAT( tx_good );
784
 
785
        cpd->stats.tx_total_collisions =
786
            cpd->stats.tx_late_collisions +
787
            cpd->stats.tx_max_collisions +
788
            cpd->stats.tx_mult_collisions +
789
            cpd->stats.tx_single_collisions;
790
 
791
        // We do not need to look in the Counter Register (ETHERC_COUNTER)
792
        // because it just mimics the info we already have above.
793
    }
794
#endif // KEEP_STATISTICS
795
#endif // FIXME
796
 
797
    // Ack the TX int
798
    put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_TC);
799
 
800
#if DEBUG & 4
801
    db_printf("#####Tx packet freed 0x%08x\n", txd );
802
#endif
803
 
804
    if ( cpd->txbusy ) {
805
        cpd->txbusy = 0;
806
        (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
807
    }
808
}
809
 
810
 
811
//
812
// This function is called when a packet has been received.  Its job is
813
// to prepare to unload the packet from the hardware.  Once the length of
814
// the packet is known, the upper layer of the driver can be told.  When
815
// the upper layer is ready to unload the packet, the internal function
816
// 'etherc_recv' will be called to actually fetch it from the hardware.
817
//
818
static void
819
etherc_RxEvent(struct eth_drv_sc *sc)
820
{
821
    struct etherc_priv_data *cpd =
822
        (struct etherc_priv_data *)sc->driver_private;
823
    cyg_uint8 *rxd;
824
    cyg_uint32 rstat;
825
    cyg_uint32 ints;
826
    cyg_uint16 len;
827
 
828
    DEBUG_FUNCTION();
829
 
830
    ints = get_reg(cpd, _REG_EESR);
831
#if DEBUG & 1
832
    db_printf("RxEvent - ESSR: 0x%08x\n", ints);
833
#endif
834
 
835
    while (1) {
836
        // Get state of next (supposedly) full ring entry
837
        cpd->rxpacket = cpd->rx_ring_next;
838
        rxd = cpd->rx_ring + cpd->rxpacket*ETHERC_RD_SIZE;
839
        rstat = _SU32(rxd, ETHERC_RD_STAT);
840
 
841
        // Keep going until we hit an entry that is owned by the
842
        // controller.
843
        if (rstat & ETHERC_RD_STAT_RACT) {
844
#if DEBUG & 1
845
            int i;
846
            for (i = 0; i < cpd->rx_ring_cnt; i++) {
847
                rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
848
                rstat = _SU32(rxd, ETHERC_RD_STAT);
849
 
850
                if (!(rstat & ETHERC_RD_STAT_RACT)) {
851
                    int i;
852
                    cyg_uint32 rstat;
853
                    cyg_uint16 mlen, blen;
854
                    cyg_uint8* rxd;
855
 
856
                    db_printf("%s: Inconsistent RX state for %d\n", __FUNCTION__, cpd->rxpacket);
857
                    for (i = 0; i < cpd->rx_ring_cnt; i++) {
858
                        rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
859
 
860
                        rstat = _SU32(rxd, ETHERC_RD_STAT);
861
                        blen = _SU16(rxd, ETHERC_RD_RBL);
862
                        mlen = _SU16(rxd, ETHERC_RD_RDL);
863
                        db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
864
                    }
865
                }
866
            }
867
#endif
868
            break;
869
        }
870
 
871
#if DEBUG & 4
872
        db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
873
#endif
874
 
875
        // Increment counts
876
        INCR_STAT( rx_count );
877
        cpd->rx_ring_next++;
878
        if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;
879
 
880
        len = _SU16(rxd, ETHERC_RD_RDL);
881
 
882
#ifdef KEEP_STATISTICS
883
        //if ( rstat & ETHERC_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
884
        //if ( rstat & ETHERC_RD_PTR_OFLO ) INCR_STAT(  );
885
        if ( rstat & ETHERC_RD_STAT_RFOF ) INCR_STAT( rx_crc_errors );
886
        //if ( rstat & ETHERC_RD_PTR_BUFF ) INCR_STAT(  );
887
#endif // KEEP_STATISTICS
888
 
889
        if (0 == (rstat & ETHERC_RD_STAT_RFE)) {
890
            // It's OK
891
            INCR_STAT( rx_good );
892
 
893
#if DEBUG & 1
894
            db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
895
#endif
896
            // Check for bogusly short packets; can happen in promisc
897
            // mode: Asserted against and checked by upper layer
898
            // driver.
899
#ifdef CYGPKG_NET
900
            if ( len > sizeof( struct ether_header ) )
901
                // then it is acceptable; offer the data to the network stack
902
#endif
903
                (sc->funs->eth_drv->recv)(sc, len);
904
        } else {
905
            // Not OK for one reason or another...
906
#if DEBUG & 1
907
            db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
908
                        rstat, len);
909
#endif
910
        }
911
 
912
        // Free packet (clear all status flags, and set RACT)
913
        _SU32(rxd, ETHERC_RD_STAT) &= ETHERC_RD_STAT_CLEAR;
914
        _SU32(rxd, ETHERC_RD_STAT) |= ETHERC_RD_STAT_RACT;
915
    }
916
 
917
    // Ack RX interrupt set
918
    put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_FR);
919
    // ensure Receive Request is enabled
920
    put_reg(cpd, _REG_EDRRR, CYGARC_REG_EDRRR_RR);
921
#if DEBUG & 1
922
    ints = get_reg(cpd, _REG_EESR);
923
    db_printf("RxEvent exit - ESSR: 0x%08x\n", ints);
924
#endif
925
}
926
 
927
//
928
// This function is called as a result of the "eth_drv_recv()" call above.
929
// Its job is to actually fetch data for a packet from the hardware once
930
// memory buffers have been allocated for the packet.  Note that the buffers
931
// may come in pieces, using a scatter-gather list.  This allows for more
932
// efficient processing in the upper layers of the stack.
933
//
934
static void
935
etherc_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
936
{
937
    struct etherc_priv_data *cpd =
938
        (struct etherc_priv_data *)sc->driver_private;
939
    int i, mlen=0, plen;
940
    cyg_uint8 *data, *rxd, *buf;
941
 
942
    DEBUG_FUNCTION();
943
 
944
    rxd = cpd->rx_ring + cpd->rxpacket*ETHERC_TD_SIZE;
945
    buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
946
 
947
    INCR_STAT( rx_deliver );
948
 
949
    plen = _SU16(rxd, ETHERC_RD_RDL);
950
 
951
    for (i = 0;  i < sg_len;  i++) {
952
        data = (cyg_uint8*)sg_list[i].buf;
953
        mlen = sg_list[i].len;
954
 
955
#if DEBUG & 1
956
        db_printf("%s : mlen %04x, plen %04x\n", __FUNCTION__, mlen, plen);
957
#endif
958
        if (data) {
959
            while (mlen > 0) {
960
                *data++ = *buf++;
961
                mlen--;
962
                plen--;
963
            }
964
        }
965
    }
966
}
967
 
968
static void
969
etherc_poll(struct eth_drv_sc *sc)
970
{
971
    cyg_uint32 event;
972
    struct etherc_priv_data *cpd =
973
        (struct etherc_priv_data *)sc->driver_private;
974
 
975
//    DEBUG_FUNCTION();
976
 
977
    while (1) {
978
        // Get the (unmasked) requests
979
        event = get_reg(cpd, _REG_EESR);
980
        if (0 == event)
981
            break;
982
 
983
        if (event & CYGARC_REG_EESR_FR) {
984
            etherc_RxEvent(sc);
985
        }
986
        else if (event & CYGARC_REG_EESR_TC) {
987
            etherc_TxEvent(sc, event);
988
        }
989
        else if (event & CYGARC_REG_EESR_RDE) {
990
#if DEBUG & 1
991
            int i;
992
            cyg_uint32 rstat;
993
            cyg_uint16 mlen, blen;
994
            cyg_uint8* rxd;
995
            struct etherc_priv_data *cpd =
996
                (struct etherc_priv_data *)sc->driver_private;
997
 
998
            db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);
999
            for (i = 0; i < cpd->rx_ring_cnt; i++) {
1000
                rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
1001
 
1002
                rstat = _SU32(rxd, ETHERC_RD_STAT);
1003
                blen = _SU16(rxd, ETHERC_RD_RBL);
1004
                mlen = _SU16(rxd, ETHERC_RD_RDL);
1005
                db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
1006
            }
1007
#endif
1008
            // Just clear the flag - RF is handled earlier in the loop
1009
            // so a new RX block should be ready when this code
1010
            // executes.
1011
            put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_RDE);
1012
        }
1013
        else {
1014
#if DEBUG & 1
1015
            db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
1016
#endif
1017
            put_reg(cpd, _REG_EESR, event);
1018
        }
1019
    }
1020
 
1021
    // Make sure RX is enabled
1022
    if (cpd->active) {
1023
        cyg_uint32 reg;
1024
        reg = get_reg(cpd, _REG_ECMR);
1025
        reg |= CYGARC_REG_ECMR_RE;
1026
        put_reg(cpd, _REG_ECMR, reg);
1027
    }
1028
}
1029
 
1030
//----------------------------------------------------------------------------
1031
// MII accessors
1032
 
1033
#define _MII_WRITE_BIT(_cpd_, _b_)                                                              \
1034
  CYG_MACRO_START                                                                               \
1035
  cyg_uint32 _d_ = (_b_) ? CYGARC_REG_PIR_MDO : 0;                                              \
1036
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_);                       \
1037
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_ | CYGARC_REG_PIR_MDC);  \
1038
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_);                       \
1039
  CYG_MACRO_END
1040
 
1041
#define _MII_READ_BIT(_cpd_, _b_)                                                       \
1042
  CYG_MACRO_START                                                                       \
1043
  cyg_uint32 _d_;                                                                       \
1044
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ | CYGARC_REG_PIR_MDC); \
1045
  HAL_READ_UINT32(_cpd_->base+_REG_PIR, _d_);                                           \
1046
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ);                      \
1047
  (_b_) = (_d_ & CYGARC_REG_PIR_MDI) ? 1 : 0;                                           \
1048
  CYG_MACRO_END
1049
 
1050
#define _MII_RELEASE(_cpd_)                                                             \
1051
  CYG_MACRO_START                                                                       \
1052
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ);                      \
1053
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ | CYGARC_REG_PIR_MDC); \
1054
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ);                      \
1055
  CYG_MACRO_END
1056
 
1057
#define _MII_RELEASE_INDEP(_cpd_)                                       \
1058
  CYG_MACRO_START                                                       \
1059
  HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ);      \
1060
  CYG_MACRO_END
1061
 
1062
 
1063
static void
1064
etherc_write_MII(struct etherc_priv_data *cpd, int id, int reg, cyg_uint16 value)
1065
{
1066
    int i;
1067
 
1068
    // Pre
1069
    for(i = 0; i < 32; i++)
1070
        _MII_WRITE_BIT(cpd, 1);
1071
    // Start of frame
1072
    _MII_WRITE_BIT(cpd, 0);
1073
    _MII_WRITE_BIT(cpd, 1);
1074
    // Operation (write)
1075
    _MII_WRITE_BIT(cpd, 0);
1076
    _MII_WRITE_BIT(cpd, 1);
1077
    // Phy address
1078
    for (i = 4; i >= 0; i--)
1079
        _MII_WRITE_BIT(cpd, (id & (1<<i)) ? 1: 0);
1080
    // Register address
1081
    for (i = 4; i >= 0; i--)
1082
        _MII_WRITE_BIT(cpd, (reg & (1<<i)) ? 1: 0);
1083
    // TA
1084
    _MII_WRITE_BIT(cpd, 1);
1085
    _MII_WRITE_BIT(cpd, 0);
1086
    // Data
1087
    for (i = 15; i >= 0; i--)
1088
        _MII_WRITE_BIT(cpd, (value & (1<<i)) ? 1: 0);
1089
    // Release bus
1090
    _MII_RELEASE_INDEP(cpd);
1091
}
1092
 
1093
static cyg_uint16
1094
etherc_read_MII(struct etherc_priv_data *cpd, int id, int reg)
1095
{
1096
    bool b;
1097
    int i;
1098
    cyg_uint16 val = 0;
1099
 
1100
    // Pre
1101
    for(i = 0; i < 32; i++)
1102
        _MII_WRITE_BIT(cpd, 1);
1103
    // Start of frame
1104
    _MII_WRITE_BIT(cpd, 0);
1105
    _MII_WRITE_BIT(cpd, 1);
1106
    // Operation (read)
1107
    _MII_WRITE_BIT(cpd, 1);
1108
    _MII_WRITE_BIT(cpd, 0);
1109
    // Phy address
1110
    for (i = 4; i >= 0; i--)
1111
        _MII_WRITE_BIT(cpd, (id & (1<<i)) ? 1: 0);
1112
    // Register address
1113
    for (i = 4; i >= 0; i--)
1114
        _MII_WRITE_BIT(cpd, (reg & (1<<i)) ? 1: 0);
1115
    // TA
1116
    _MII_RELEASE(cpd);
1117
    // Data
1118
    for (i = 15; i >= 0; i--) {
1119
        _MII_READ_BIT(cpd, b);
1120
        val = val << 1;
1121
        if (b) val |= 1;
1122
    }
1123
 
1124
    return val;
1125
}
1126
 
1127
// EOF if_etherc.c

powered by: WebSVN 2.1.0

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