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