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

Subversion Repositories amber

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

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 80 csantifort
/* open a link */
55
void init_ethmac()
56 61 csantifort
{
57 80 csantifort
    /* initialize the packet rx buffer */
58
    init_packet();
59 78 csantifort
 
60 80 csantifort
    /* open ethernet port and wait for connection requests
61
       keep trying forever */
62
    while (!open_link());
63
}
64 78 csantifort
 
65
 
66 61 csantifort
 
67
/* return 1 if link comes up */
68
int open_link (void)
69
{
70
    int packet;
71
    int n;
72
    unsigned int d32;
73 78 csantifort
 
74 61 csantifort
    /* Disable Ethmac interrupt in interrupt controller */
75
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
76
 
77
    /* Set my MAC address */
78
    d32 = self_g.mac[2]<<24|self_g.mac[3]<<16|self_g.mac[4]<<8|self_g.mac[5];
79
    *(unsigned int *) ( ADR_ETHMAC_MAC_ADDR0 ) = d32;
80 78 csantifort
 
81 61 csantifort
    d32 = self_g.mac[0]<<8|self_g.mac[1];
82
    *(unsigned int *) ( ADR_ETHMAC_MAC_ADDR1 ) = d32;
83 78 csantifort
 
84 80 csantifort
    if (!init_phy())
85
        return 0;
86 61 csantifort
 
87
    /* Write the Receive Packet Buffer Descriptor */
88
    /* Buffer Pointer */
89
    for (packet=0; packet<ETHMAC_RX_BUFFERS; packet++) {
90
        *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x204 + packet*8 ) = ETHMAC_RX_BUFFER + packet * 0x1000;
91 78 csantifort
        /* Ready Rx buffer
92
           [31:16] = length in bytes,
93 61 csantifort
           [15] = empty
94
           [14] = Enable IRQ
95
           [13] = wrap bit */
96
        /* set empty flag again */
97
        if (packet == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */
98 78 csantifort
            /* Set wrap bit is last buffer */
99 61 csantifort
            *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000e000;
100
        else
101
            *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000c000;
102
        }
103
 
104 78 csantifort
 
105 61 csantifort
    /* Enable EthMac interrupts in Ethmac core */
106
    /* Receive frame and receive error botgh enabled */
107
    /* When a bad frame is received is still gets written to a buffer
108
       so needs to be dealt with */
109
    *(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0xc;
110 78 csantifort
 
111 61 csantifort
    /* Enable Ethmac interrupt in interrupt controller */
112
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
113 78 csantifort
 
114 61 csantifort
    /* Set transmit packet buffer location */
115
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 4 ) = ETHMAC_TX_BUFFER;
116 78 csantifort
 
117 61 csantifort
    /* Set the ready bit, bit 15, low */
118
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = 0x7800;
119
 
120
    /* Enable Rx & Tx - MODER Register
121
     [15] = Add pads to short frames
122
     [13] = CRCEN
123
     [10] = Enable full duplex
124
     [7]  = loopback
125
     [5]  = 1 for promiscuous, 0 rx only frames that match mac address
126
     [1]  = txen
127
     [0]  = rxen  */
128
    *(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa423;
129 78 csantifort
 
130 61 csantifort
    return 1;
131
}
132
 
133
 
134 80 csantifort
 
135
void close_link (void)
136
{
137
    /* Disable EthMac interrupts in Ethmac core */
138
    *(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0;
139
 
140
    /* Disable Ethmac interrupt in interrupt controller */
141
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
142
 
143
    /* Disable Rx & Tx - MODER Register
144
     [15] = Add pads to short frames
145
     [13] = CRCEN
146
     [10] = Enable full duplex
147
     [7]  = loopback
148
     [5]  = 1 for promiscuous, 0 rx only frames that match mac address
149
     [1]  = txen
150
     [0]  = rxen  */
151
    *(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420;
152
 
153
    /* Put the PHY into reset */
154
    phy_rst(0);  /* reset is active low */
155
 
156
}
157
 
158
 
159 81 csantifort
void ethmac_tx_packet(char* buf, int len)
160 61 csantifort
{
161
    unsigned int status = 0;
162 78 csantifort
 
163 81 csantifort
    /* copy the packet into the tx buffer */
164
    strncpy((char*)ETHMAC_TX_BUFFER, buf, len);
165 78 csantifort
 
166 81 csantifort
 
167 61 csantifort
    /* Poll the ready bit.
168
       Wait until the ready bit is cleared by the ethmac hardware
169
       This holds everything up while the packet is being transmitted, but
170
       it keeps things simple. */
171
    status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 );
172
    while ((status & 0x8000) != 0) {
173
        udelay20();
174
        status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 );
175
        }
176
 
177
 
178
    /* Enable packet tx
179 78 csantifort
       [31:16] = length in bytes,
180 61 csantifort
       [15] = ready
181
       [14] = tx int
182 78 csantifort
       [13] = wrap bit
183 61 csantifort
       [12] = pad enable for short packets
184
       [11] = crc en
185
    */
186
    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = len<<16 | 0xf800;
187
}
188
 
189
 
190 81 csantifort
 
191 61 csantifort
/* returns 1 if link comes up */
192 80 csantifort
int init_phy (void)
193 61 csantifort
{
194
    int addr;
195
    int bmcr;
196
    int stat;
197
    int phy_id;
198
    int link_up = 1;
199 78 csantifort
    time_t* link_timer;
200 61 csantifort
 
201 80 csantifort
    link_timer = new_timer();
202 78 csantifort
 
203 61 csantifort
    /* Bring PHY out of reset */
204
    phy_rst(1);  /* reset is active low */
205 78 csantifort
 
206 61 csantifort
    /* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
207
    for(addr = 0; addr < 32; addr++) {
208
            phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
209
            bmcr = mdio_read(phy_id, MII_BMCR);  /* Basic Mode Control Register */
210
            stat = mdio_read(phy_id, MII_BMSR);
211
            stat = mdio_read(phy_id, MII_BMSR);
212
            if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
213 78 csantifort
                break;
214 61 csantifort
    }
215 78 csantifort
    /* Failed to find a PHY on the md bus */
216
    if (addr == 32)
217
        return 0;
218
 
219 61 csantifort
    /* Reset PHY */
220
    bmcr = mdio_read(phy_id, MII_BMCR);
221
    mdio_write(phy_id, MII_BMCR, bmcr | BMCR_RESET);
222
 
223
    /* Advertise that PHY is NOT B1000-T capable */
224
    /* Set bits 9.8, 9.9 to 0 */
225
    bmcr = mdio_read(phy_id, MII_CTRL1000);
226
    mdio_write(phy_id, MII_CTRL1000, bmcr & 0xfcff );
227 78 csantifort
 
228 61 csantifort
    /* Restart autoneg */
229
    bmcr = mdio_read(phy_id, MII_BMCR);
230
    mdio_write(phy_id, MII_BMCR, bmcr | BMCR_ANRESTART);
231 78 csantifort
 
232 61 csantifort
    /* Wait for link up */
233
    /* Print PHY status MII_BMSR = Basic Mode Status Register*/
234 78 csantifort
    /* allow a few seconds for the link to come up before giving up */
235
    set_timer(link_timer, 5000);
236
 
237 61 csantifort
    while (!((stat = mdio_read(phy_id, MII_BMSR)) & BMSR_LSTATUS)) {
238
        if (timer_expired(link_timer)) {
239 78 csantifort
            link_up = 0;
240
            break;
241 61 csantifort
            }
242
        }
243 78 csantifort
 
244 61 csantifort
    return link_up;
245
}
246
 
247
 
248
int mdio_read(int addr, int reg)
249
{
250
    return mdio_ctrl(addr, mdi_read, reg, 0);
251
}
252
 
253
 
254
void mdio_write(int addr, int reg, int data)
255
{
256
    mdio_ctrl(addr, mdi_write, reg, data);
257
}
258
 
259
 
260
/*
261
 addr = PHY address
262 78 csantifort
 reg  = register address within PHY
263 61 csantifort
 */
264
unsigned short mdio_ctrl(unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data)
265
{
266
    unsigned int data_out = 0;
267
    unsigned int i;
268
    unsigned long flags;
269
 
270 78 csantifort
    mdio_ready();
271
 
272 61 csantifort
    *(volatile unsigned int *)(ADR_ETHMAC_MIIADDRESS) = (reg << 8) | (addr & 0x1f);
273
 
274 78 csantifort
    if (dir == mdi_write) {
275
        *(volatile unsigned int *)(ADR_ETHMAC_MIITXDATA) = data;
276
        /* Execute Write ! */
277
        *(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x4;
278
    }
279
    else {
280
        /* Execute Read ! */
281
        *(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x2;
282
        mdio_ready();
283
        data_out = *(volatile unsigned int *)(ADR_ETHMAC_MIIRXDATA);
284
    }
285
 
286 61 csantifort
    return (unsigned short) data_out;
287
}
288
 
289
 
290
/* Wait until its ready */
291
void mdio_ready()
292 78 csantifort
{
293 61 csantifort
    int i;
294
    for (;;) {
295 78 csantifort
        /* Bit 1 is high when the MD i/f is busy */
296
        if ((*(volatile unsigned int *)(ADR_ETHMAC_MIISTATUS) & 0x2) == 0x0)
297 61 csantifort
            break;
298 78 csantifort
 
299 61 csantifort
        i++;
300
        if (i==10000000) {
301
            i=0;
302
            }
303
        }
304
}
305
 
306
 
307
 
308
void ethmac_interrupt(void)
309 78 csantifort
{
310 61 csantifort
    int buffer;
311
    unsigned int int_src;
312
    unsigned int rx_buf_status;
313 78 csantifort
 
314 61 csantifort
    /* Mask ethmac interrupts */
315
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK   ) = 0;
316 78 csantifort
 
317 61 csantifort
    int_src = *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE );
318 78 csantifort
 
319
    if (int_src) {
320
        for (buffer=0; buffer<ETHMAC_RX_BUFFERS; buffer++) {
321
 
322
           rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 );
323
 
324
           if ((rx_buf_status & 0x8000) == 0) {
325
                parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g);
326
 
327
                /* set empty flag again */
328
                if (buffer == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */
329
                    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000e000;
330
                else
331
                    *(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000c000;
332
                }
333 61 csantifort
            }
334
        }
335
 
336
    /* Clear all ethmac interrupts */
337
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE ) = int_src;
338
 
339
    /* UnMask ethmac interrupts */
340
    *(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK   ) = 0xc;
341
}
342
 
343
 

powered by: WebSVN 2.1.0

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