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

Subversion Repositories amber

[/] [amber/] [trunk/] [sw/] [boot-loader-ethmac/] [ethmac.c] - Blame information for rev 78

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

Line No. Rev Author Line
1 61 csantifort
/*----------------------------------------------------------------
2
//                                                              //
3
//  boot-loader-ethmac.c                                        //
4
//                                                              //
5
//  This file is part of the Amber project                      //
6
//  http://www.opencores.org/project,amber                      //
7
//                                                              //
8
//  Description                                                 //
9
//  The main functions for the boot loader application. This    //
10 78 csantifort
//  application is embedded in the FPGA's SRAM and is used      //
11 61 csantifort
//  to load larger applications into the DDR3 memory on         //
12
//  the development board.                                      //
13
//                                                              //
14
//  Author(s):                                                  //
15
//      - Conor Santifort, csantifort.amber@gmail.com           //
16
//                                                              //
17
//////////////////////////////////////////////////////////////////
18
//                                                              //
19
// Copyright (C) 2011 Authors and OPENCORES.ORG                 //
20
//                                                              //
21
// This source file may be used and distributed without         //
22
// restriction provided that this copyright statement is not    //
23
// removed from the file and that any derivative work contains  //
24
// the original copyright notice and the associated disclaimer. //
25
//                                                              //
26
// This source file is free software; you can redistribute it   //
27
// and/or modify it under the terms of the GNU Lesser General   //
28
// Public License as published by the Free Software Foundation; //
29
// either version 2.1 of the License, or (at your option) any   //
30
// later version.                                               //
31
//                                                              //
32
// This source is distributed in the hope that it will be       //
33
// useful, but WITHOUT ANY WARRANTY; without even the implied   //
34
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
35
// PURPOSE.  See the GNU Lesser General Public License for more //
36
// details.                                                     //
37
//                                                              //
38
// You should have received a copy of the GNU Lesser General    //
39
// Public License along with this source; if not, download it   //
40
// from http://www.opencores.org/lgpl.shtml                     //
41
//                                                              //
42
----------------------------------------------------------------*/
43
 
44
 
45
#include "amber_registers.h"
46
#include "address_map.h"
47
#include "timer.h"
48
#include "utilities.h"
49
#include "line-buffer.h"
50
#include "packet.h"
51
#include "ethmac.h"
52
 
53
 
54
void close_link (void)
55
{
56
    /* Disable EthMac interrupts in Ethmac core */
57
    *(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0;
58 78 csantifort
 
59 61 csantifort
    /* Disable Ethmac interrupt in interrupt controller */
60
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
61 78 csantifort
 
62 61 csantifort
    /* Disable Rx & Tx - MODER Register
63
     [15] = Add pads to short frames
64
     [13] = CRCEN
65
     [10] = Enable full duplex
66
     [7]  = loopback
67
     [5]  = 1 for promiscuous, 0 rx only frames that match mac address
68
     [1]  = txen
69
     [0]  = rxen  */
70 78 csantifort
    *(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420;
71
 
72 61 csantifort
    /* Put the PHY into reset */
73
    phy_rst(0);  /* reset is active low */
74
 
75
}
76
 
77
 
78
/* return 1 if link comes up */
79
int open_link (void)
80
{
81
    int packet;
82
    int n;
83
    unsigned int d32;
84 78 csantifort
 
85 61 csantifort
    /* Disable Ethmac interrupt in interrupt controller */
86
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
87
 
88
    /* Set my MAC address */
89
    d32 = self_g.mac[2]<<24|self_g.mac[3]<<16|self_g.mac[4]<<8|self_g.mac[5];
90
    *(unsigned int *) ( ADR_ETHMAC_MAC_ADDR0 ) = d32;
91 78 csantifort
 
92 61 csantifort
    d32 = self_g.mac[0]<<8|self_g.mac[1];
93
    *(unsigned int *) ( ADR_ETHMAC_MAC_ADDR1 ) = d32;
94 78 csantifort
 
95 61 csantifort
    if (!config_phy()) return 0;
96
 
97
    /* Write the Receive Packet Buffer Descriptor */
98
    /* Buffer Pointer */
99
    for (packet=0; packet<ETHMAC_RX_BUFFERS; packet++) {
100
        *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x204 + packet*8 ) = ETHMAC_RX_BUFFER + packet * 0x1000;
101 78 csantifort
        /* Ready Rx buffer
102
           [31:16] = length in bytes,
103 61 csantifort
           [15] = empty
104
           [14] = Enable IRQ
105
           [13] = wrap bit */
106
        /* set empty flag again */
107
        if (packet == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */
108 78 csantifort
            /* Set wrap bit is last buffer */
109 61 csantifort
            *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000e000;
110
        else
111
            *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000c000;
112
        }
113
 
114 78 csantifort
 
115 61 csantifort
    /* Enable EthMac interrupts in Ethmac core */
116
    /* Receive frame and receive error botgh enabled */
117
    /* When a bad frame is received is still gets written to a buffer
118
       so needs to be dealt with */
119
    *(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0xc;
120 78 csantifort
 
121 61 csantifort
    /* Enable Ethmac interrupt in interrupt controller */
122
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
123 78 csantifort
 
124 61 csantifort
    /* Set transmit packet buffer location */
125
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 4 ) = ETHMAC_TX_BUFFER;
126 78 csantifort
 
127 61 csantifort
    /* Set the ready bit, bit 15, low */
128
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = 0x7800;
129
 
130
    /* Enable Rx & Tx - MODER Register
131
     [15] = Add pads to short frames
132
     [13] = CRCEN
133
     [10] = Enable full duplex
134
     [7]  = loopback
135
     [5]  = 1 for promiscuous, 0 rx only frames that match mac address
136
     [1]  = txen
137
     [0]  = rxen  */
138
    *(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa423;
139 78 csantifort
 
140 61 csantifort
    return 1;
141
}
142
 
143
 
144
void tx_packet(int len)
145
{
146
    unsigned int status = 0;
147 78 csantifort
 
148
 
149 61 csantifort
    /* Poll the ready bit.
150
       Wait until the ready bit is cleared by the ethmac hardware
151
       This holds everything up while the packet is being transmitted, but
152
       it keeps things simple. */
153
    status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 );
154
    while ((status & 0x8000) != 0) {
155
        udelay20();
156
        status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 );
157
        }
158
 
159
 
160
    /* Enable packet tx
161 78 csantifort
       [31:16] = length in bytes,
162 61 csantifort
       [15] = ready
163
       [14] = tx int
164 78 csantifort
       [13] = wrap bit
165 61 csantifort
       [12] = pad enable for short packets
166
       [11] = crc en
167
    */
168
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = len<<16 | 0xf800;
169
}
170
 
171
 
172
/* returns 1 if link comes up */
173
int config_phy (void)
174
{
175
    int addr;
176
    int bmcr;
177
    int stat;
178
    int phy_id;
179
    int link_up = 1;
180 78 csantifort
    time_t* link_timer;
181 61 csantifort
 
182
    link_timer = init_timer();
183 78 csantifort
 
184 61 csantifort
    /* Bring PHY out of reset */
185
    phy_rst(1);  /* reset is active low */
186 78 csantifort
 
187 61 csantifort
    /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
188
    for(addr = 0; addr < 32; addr++) {
189
            phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
190
            bmcr = mdio_read(phy_id, MII_BMCR);  /* Basic Mode Control Register */
191
            stat = mdio_read(phy_id, MII_BMSR);
192
            stat = mdio_read(phy_id, MII_BMSR);
193
            if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
194 78 csantifort
                break;
195 61 csantifort
    }
196 78 csantifort
    /* Failed to find a PHY on the md bus */
197
    if (addr == 32)
198
        return 0;
199
 
200 61 csantifort
    /* Reset PHY */
201
    bmcr = mdio_read(phy_id, MII_BMCR);
202
    mdio_write(phy_id, MII_BMCR, bmcr | BMCR_RESET);
203
 
204
    /* Advertise that PHY is NOT B1000-T capable */
205
    /* Set bits 9.8, 9.9 to 0 */
206
    bmcr = mdio_read(phy_id, MII_CTRL1000);
207
    mdio_write(phy_id, MII_CTRL1000, bmcr & 0xfcff );
208 78 csantifort
 
209 61 csantifort
    /* Restart autoneg */
210
    bmcr = mdio_read(phy_id, MII_BMCR);
211
    mdio_write(phy_id, MII_BMCR, bmcr | BMCR_ANRESTART);
212 78 csantifort
 
213 61 csantifort
    /* Wait for link up */
214
    /* Print PHY status MII_BMSR = Basic Mode Status Register*/
215 78 csantifort
    /* allow a few seconds for the link to come up before giving up */
216
    set_timer(link_timer, 5000);
217
 
218 61 csantifort
    while (!((stat = mdio_read(phy_id, MII_BMSR)) & BMSR_LSTATUS)) {
219
        if (timer_expired(link_timer)) {
220 78 csantifort
            link_up = 0;
221
            break;
222 61 csantifort
            }
223
        }
224 78 csantifort
 
225 61 csantifort
    return link_up;
226
}
227
 
228
 
229
int mdio_read(int addr, int reg)
230
{
231
    return mdio_ctrl(addr, mdi_read, reg, 0);
232
}
233
 
234
 
235
void mdio_write(int addr, int reg, int data)
236
{
237
    mdio_ctrl(addr, mdi_write, reg, data);
238
}
239
 
240
 
241
/*
242
 addr = PHY address
243 78 csantifort
 reg  = register address within PHY
244 61 csantifort
 */
245
unsigned short mdio_ctrl(unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data)
246
{
247
    unsigned int data_out = 0;
248
    unsigned int i;
249
    unsigned long flags;
250
 
251 78 csantifort
    mdio_ready();
252
 
253 61 csantifort
    *(volatile unsigned int *)(ADR_ETHMAC_MIIADDRESS) = (reg << 8) | (addr & 0x1f);
254
 
255 78 csantifort
    if (dir == mdi_write) {
256
        *(volatile unsigned int *)(ADR_ETHMAC_MIITXDATA) = data;
257
        /* Execute Write ! */
258
        *(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x4;
259
    }
260
    else {
261
        /* Execute Read ! */
262
        *(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x2;
263
        mdio_ready();
264
        data_out = *(volatile unsigned int *)(ADR_ETHMAC_MIIRXDATA);
265
    }
266
 
267 61 csantifort
    return (unsigned short) data_out;
268
}
269
 
270
 
271
/* Wait until its ready */
272
void mdio_ready()
273 78 csantifort
{
274 61 csantifort
    int i;
275
    for (;;) {
276 78 csantifort
        /* Bit 1 is high when the MD i/f is busy */
277
        if ((*(volatile unsigned int *)(ADR_ETHMAC_MIISTATUS) & 0x2) == 0x0)
278 61 csantifort
            break;
279 78 csantifort
 
280 61 csantifort
        i++;
281
        if (i==10000000) {
282
            i=0;
283
            }
284
        }
285
}
286
 
287
 
288
 
289
void ethmac_interrupt(void)
290 78 csantifort
{
291 61 csantifort
    int buffer;
292
    unsigned int int_src;
293
    unsigned int rx_buf_status;
294 78 csantifort
 
295 61 csantifort
    /* Mask ethmac interrupts */
296
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK   ) = 0;
297 78 csantifort
 
298 61 csantifort
    int_src = *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE );
299 78 csantifort
 
300
    if (int_src) {
301
        for (buffer=0; buffer<ETHMAC_RX_BUFFERS; buffer++) {
302
 
303
           rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 );
304
 
305
           if ((rx_buf_status & 0x8000) == 0) {
306
 
307
                parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g);
308
 
309
                /* set empty flag again */
310
                if (buffer == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */
311
                    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000e000;
312
                else
313
                    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000c000;
314
                }
315 61 csantifort
            }
316
        }
317
 
318
    /* Clear all ethmac interrupts */
319
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE ) = int_src;
320
 
321
    /* UnMask ethmac interrupts */
322
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK   ) = 0xc;
323
}
324
 
325
 

powered by: WebSVN 2.1.0

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