]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/netarm_eth.c
Apply SoC concept to arm926ejs CPUs, i.e. move the SoC specific timer and
[karo-tx-uboot.git] / drivers / netarm_eth.c
1 /*
2  * Copyright (C) 2004 IMMS gGmbH <www.imms.de>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307 USA
18  *
19  * author(s): Thomas Elste, <info@elste.org>
20  *            (some parts derived from uCLinux Netarm Ethernet Driver)
21  */
22
23
24 #include <common.h>
25
26 #ifdef CONFIG_DRIVER_NETARMETH
27 #include <command.h>
28 #include <net.h>
29 #include "netarm_eth.h"
30 #include <asm/arch/netarm_registers.h>
31
32
33 #if (CONFIG_COMMANDS & CFG_CMD_NET)
34
35 static int na_mii_poll_busy (void);
36
37 static void na_get_mac_addr (void)
38 {
39         unsigned short p[3];
40         char *m_addr;
41         char ethaddr[20];
42
43         m_addr = (char *) p;
44
45         p[0] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_1);
46         p[1] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_2);
47         p[2] = (unsigned short) GET_EADDR (NETARM_ETH_SAL_STATION_ADDR_3);
48
49         sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
50                  m_addr[0], m_addr[1],
51                  m_addr[2], m_addr[3], m_addr[4], m_addr[5]);
52
53         printf ("HW-MAC Address:  %s\n", ethaddr);
54
55         /* set env, todo: check if already an adress is set */
56         setenv ("ethaddr", ethaddr);
57 }
58
59
60 static void na_mii_write (int reg, int value)
61 {
62         int mii_addr;
63
64         /* Select register */
65         mii_addr = CFG_ETH_PHY_ADDR + reg;
66         SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
67         /* Write value */
68         SET_EADDR (NETARM_ETH_MII_WRITE, value);
69         na_mii_poll_busy ();
70 }
71
72 static unsigned int na_mii_read (int reg)
73 {
74         int mii_addr, val;
75
76         /* Select register */
77         mii_addr = CFG_ETH_PHY_ADDR + reg;
78         SET_EADDR (NETARM_ETH_MII_ADDR, mii_addr);
79         /* do one management cycle */
80         SET_EADDR (NETARM_ETH_MII_CMD,
81                    GET_EADDR (NETARM_ETH_MII_CMD) | NETARM_ETH_MIIC_RSTAT);
82         na_mii_poll_busy ();
83         /* Return read value */
84         val = GET_EADDR (NETARM_ETH_MII_READ);
85         return val;
86 }
87
88 static int na_mii_poll_busy (void)
89 {
90         /* arm simple, non interrupt dependent timer */
91         reset_timer_masked ();
92         while (get_timer_masked () < NA_MII_POLL_BUSY_DELAY) {
93                 if (!(GET_EADDR (NETARM_ETH_MII_IND) & NETARM_ETH_MIII_BUSY)) {
94                         return 1;
95                 }
96         }
97         printf ("na_mii_busy timeout\n");
98         return (0);
99 }
100
101 static int na_mii_identify_phy (void)
102 {
103         int id_reg_a = 0;
104
105         /* get phy id register */
106         id_reg_a = na_mii_read (MII_PHY_ID);
107
108         if (id_reg_a == 0x0043) {
109                 /* This must be an Enable or a Lucent LU3X31 PHY chip */
110                 return 1;
111         } else if (id_reg_a == 0x0013) {
112                 /* it is an Intel LXT971A */
113                 return 1;
114         }
115         return (0);
116 }
117
118 static int na_mii_negotiate (void)
119 {
120         int i = 0;
121
122         /* Enable auto-negotiation */
123         na_mii_write (MII_PHY_AUTONEGADV, 0x01e1);
124         /* FIXME: 0x01E1 is 100Mb half and full duplex, 0x0061 is 10Mb only */
125         /* Restart auto-negotiation */
126         na_mii_write (MII_PHY_CONTROL, 0x1200);
127
128         /* status register is 0xffff after setting the autoneg restart bit */
129         while (na_mii_read (MII_PHY_STATUS) == 0xffff) {
130                 i++;
131         }
132
133         /* na_mii_read uses the timer already, so we can't use it again for
134            timeout checking.
135            Instead we just try some times.
136          */
137         for (i = 0; i < 40000; i++) {
138                 if ((na_mii_read (MII_PHY_STATUS) & 0x0024) == 0x0024) {
139                         return 0;
140                 }
141         }
142         /*
143            printf("*Warning* autonegotiation timeout, status: 0x%x\n",na_mii_read(MII_PHY_STATUS));
144          */
145         return (1);
146 }
147
148 static unsigned int na_mii_check_speed (void)
149 {
150         unsigned int status;
151
152         /* Read Status register */
153         status = na_mii_read (MII_PHY_STATUS);
154         /* Check link status.  If 0, default to 100 Mbps. */
155         if ((status & 0x0004) == 0) {
156                 printf ("*Warning* no link detected, set default speed to 100Mbs\n");
157                 return 1;
158         } else {
159                 if ((na_mii_read (17) & 0x4000) != 0) {
160                         printf ("100Mbs link detected\n");
161                         return 1;
162                 } else {
163                         printf ("10Mbs link detected\n");
164                         return 0;
165                 }
166         }
167         return 0;
168 }
169
170 static int reset_eth (void)
171 {
172         int pt;
173
174         na_get_mac_addr ();
175         pt = na_mii_identify_phy ();
176
177         /* reset the phy */
178         na_mii_write (MII_PHY_CONTROL, 0x8000);
179         reset_timer_masked ();
180         while (get_timer_masked () < NA_MII_NEGOTIATE_DELAY) {
181                 if ((na_mii_read (MII_PHY_STATUS) & 0x8000) == 0) {
182                         break;
183                 }
184         }
185         if (get_timer_masked () >= NA_MII_NEGOTIATE_DELAY)
186                 printf ("phy reset timeout\n");
187
188         /* set the PCS reg */
189         SET_EADDR (NETARM_ETH_PCS_CFG, NETARM_ETH_PCSC_CLKS_25M |
190                    NETARM_ETH_PCSC_ENJAB | NETARM_ETH_PCSC_NOCFR);
191
192         na_mii_negotiate ();
193         na_mii_check_speed ();
194
195         /* Delay 10 millisecond.  (Maybe this should be 1 second.) */
196         udelay (10000);
197
198         /* Turn receive on.
199            Enable statistics register autozero on read.
200            Do not insert MAC address on transmit.
201            Do not enable special test modes.  */
202         SET_EADDR (NETARM_ETH_STL_CFG,
203                    (NETARM_ETH_STLC_AUTOZ | NETARM_ETH_STLC_RXEN));
204
205         /* Set the inter-packet gap delay to 0.96us for MII.
206            The NET+ARM H/W Reference Guide indicates that the Back-to-back IPG
207            Gap Timer Register should be set to 0x15 and the Non Back-to-back IPG
208            Gap Timer Register should be set to 0x00000C12 for the MII PHY. */
209         SET_EADDR (NETARM_ETH_B2B_IPG_GAP_TMR, 0x15);
210         SET_EADDR (NETARM_ETH_NB2B_IPG_GAP_TMR, 0x00000C12);
211
212         /* Add CRC to end of packets.
213            Pad packets to minimum length of 64 bytes.
214            Allow unlimited length transmit packets.
215            Receive all broadcast packets.
216            NOTE:  Multicast addressing is NOT enabled here currently. */
217         SET_EADDR (NETARM_ETH_MAC_CFG,
218                    (NETARM_ETH_MACC_CRCEN |
219                     NETARM_ETH_MACC_PADEN | NETARM_ETH_MACC_HUGEN));
220         SET_EADDR (NETARM_ETH_SAL_FILTER, NETARM_ETH_SALF_BROAD);
221
222         /* enable fifos */
223         SET_EADDR (NETARM_ETH_GEN_CTRL,
224                    (NETARM_ETH_GCR_ERX | NETARM_ETH_GCR_ETX));
225
226         return (0);
227 }
228
229
230 extern int eth_init (bd_t * bd)
231 {
232         reset_eth ();
233         return 0;
234 }
235
236 extern void eth_halt (void)
237 {
238         SET_EADDR (NETARM_ETH_GEN_CTRL, 0);
239 }
240
241 /* Get a data block via Ethernet */
242 extern int eth_rx (void)
243 {
244         int i;
245         unsigned short rxlen;
246         unsigned int *addr;
247         unsigned int rxstatus, lastrxlen;
248         char *pa;
249
250         /* RXBR is 1, data block was received */
251         if ((GET_EADDR (NETARM_ETH_GEN_STAT) & NETARM_ETH_GST_RXBR) == 0)
252                 return 0;
253
254         /* get status register and the length of received block */
255         rxstatus = GET_EADDR (NETARM_ETH_RX_STAT);
256         rxlen = (rxstatus & NETARM_ETH_RXSTAT_SIZE) >> 16;
257
258         if (rxlen == 0)
259                 return 0;
260
261         /* clear RXBR to make fifo available */
262         SET_EADDR (NETARM_ETH_GEN_STAT,
263                    GET_EADDR (NETARM_ETH_GEN_STAT) & ~NETARM_ETH_GST_RXBR);
264
265         /* clear TXBC to make fifo available */
266         /* According to NETARM50 data manual you just have to clear
267            RXBR but that has no effect. Only after clearing TXBC the
268            Fifo becomes readable. */
269         SET_EADDR (NETARM_ETH_GEN_STAT,
270                    GET_EADDR (NETARM_ETH_GEN_STAT) & ~NETARM_ETH_GST_TXBC);
271
272         addr = (unsigned int *) NetRxPackets[0];
273         pa = (char *) NetRxPackets[0];
274
275         /* read the fifo */
276         for (i = 0; i < rxlen / 4; i++) {
277                 *addr = GET_EADDR (NETARM_ETH_FIFO_DAT1);
278                 addr++;
279         }
280
281         if (GET_EADDR (NETARM_ETH_GEN_STAT) & NETARM_ETH_GST_RXREGR) {
282                 /* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */
283                 lastrxlen =
284                         (GET_EADDR (NETARM_ETH_GEN_STAT) &
285                          NETARM_ETH_GST_RXFDB) >> 28;
286                 *addr = GET_EADDR (NETARM_ETH_FIFO_DAT1);
287                 switch (lastrxlen) {
288                 case 1:
289                         *addr &= 0xff000000;
290                         break;
291                 case 2:
292                         *addr &= 0xffff0000;
293                         break;
294                 case 3:
295                         *addr &= 0xffffff00;
296                         break;
297                 }
298         }
299
300         /* Pass the packet up to the protocol layers. */
301         NetReceive (NetRxPackets[0], rxlen);
302
303         return rxlen;
304 }
305
306 /* Send a data block via Ethernet. */
307 extern int eth_send (volatile void *packet, int length)
308 {
309         int i, length32;
310         char *pa;
311         unsigned int *pa32, lastp = 0, rest;
312
313         pa = (char *) packet;
314         pa32 = (unsigned int *) packet;
315         length32 = length / 4;
316         rest = length % 4;
317
318         /* make sure there's no garbage in the last word */
319         switch (rest) {
320         case 0:
321                 lastp = pa32[length32];
322                 length32--;
323                 break;
324         case 1:
325                 lastp = pa32[length32] & 0x000000ff;
326                 break;
327         case 2:
328                 lastp = pa32[length32] & 0x0000ffff;
329                 break;
330         case 3:
331                 lastp = pa32[length32] & 0x00ffffff;
332                 break;
333         }
334
335         /* write to the fifo */
336         for (i = 0; i < length32; i++)
337                 SET_EADDR (NETARM_ETH_FIFO_DAT1, pa32[i]);
338
339         /* the last word is written to an extra register, this
340            starts the transmission */
341         SET_EADDR (NETARM_ETH_FIFO_DAT2, lastp);
342
343         /* NETARM_ETH_TXSTAT_TXOK should be checked, to know if the transmission
344            went fine. But we can't use the timer for a timeout loop because
345            of it is used already in upper layers. So we just try some times. */
346         i = 0;
347         while (i < 50000) {
348                 if ((GET_EADDR (NETARM_ETH_TX_STAT) & NETARM_ETH_TXSTAT_TXOK)
349                     == NETARM_ETH_TXSTAT_TXOK)
350                         return 0;
351                 i++;
352         }
353
354         printf ("eth_send timeout\n");
355         return 1;
356 }
357
358 #endif /* COMMANDS & CFG_NET */
359
360 #endif /* CONFIG_DRIVER_NETARMETH */