Blame view

arch/mips/cpu/au1x00_eth.c 7.38 KB
5da627a42   wdenk   * Patch by Steven...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /* Only eth0 supported for now
   *
   * (C) Copyright 2003
   * Thomas.Lange@corelatus.se
   *
   * See file CREDITS for list of people who contributed to this
   * project.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation; either version 2 of
   * the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
265817c7e   Wolfgang Denk   Add support for A...
16
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
5da627a42   wdenk   * Patch by Steven...
17
18
19
20
21
22
23
24
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   * MA 02111-1307 USA
   */
  #include <config.h>
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
25
  #if defined(CONFIG_SYS_DISCOVER_PHY)
265817c7e   Wolfgang Denk   Add support for A...
26
  #error "PHY not supported yet"
5da627a42   wdenk   * Patch by Steven...
27
28
29
  /* We just assume that we are running 100FD for now */
  /* We all use switches, right? ;-) */
  #endif
a2663ea4f   wdenk   * Patches by Davi...
30
  /* I assume ethernet behaves like au1000 */
8bde63eb3   Shinya Kuribayashi   [MIPS] Rename Alc...
31
  #ifdef CONFIG_SOC_AU1000
5da627a42   wdenk   * Patch by Steven...
32
33
34
35
  /* Base address differ between cpu:s */
  #define ETH0_BASE AU1000_ETH0_BASE
  #define MAC0_ENABLE AU1000_MAC0_ENABLE
  #else
8bde63eb3   Shinya Kuribayashi   [MIPS] Rename Alc...
36
  #ifdef CONFIG_SOC_AU1100
a2663ea4f   wdenk   * Patches by Davi...
37
38
39
  #define ETH0_BASE AU1100_ETH0_BASE
  #define MAC0_ENABLE AU1100_MAC0_ENABLE
  #else
8bde63eb3   Shinya Kuribayashi   [MIPS] Rename Alc...
40
  #ifdef CONFIG_SOC_AU1500
a2663ea4f   wdenk   * Patches by Davi...
41
42
43
  #define ETH0_BASE AU1500_ETH0_BASE
  #define MAC0_ENABLE AU1500_MAC0_ENABLE
  #else
8bde63eb3   Shinya Kuribayashi   [MIPS] Rename Alc...
44
  #ifdef CONFIG_SOC_AU1550
ff36fd859   wdenk   * Patch by Leif L...
45
46
47
  #define ETH0_BASE AU1550_ETH0_BASE
  #define MAC0_ENABLE AU1550_MAC0_ENABLE
  #else
a2663ea4f   wdenk   * Patches by Davi...
48
49
50
  #error "No valid cpu set"
  #endif
  #endif
5da627a42   wdenk   * Patch by Steven...
51
  #endif
ff36fd859   wdenk   * Patch by Leif L...
52
  #endif
5da627a42   wdenk   * Patch by Steven...
53
54
55
56
57
58
59
  
  #include <common.h>
  #include <malloc.h>
  #include <net.h>
  #include <command.h>
  #include <asm/io.h>
  #include <asm/au1x00.h>
4431283c7   Jon Loeliger   cpu/m*: Remove ob...
60
  #if defined(CONFIG_CMD_MII)
63ff004c4   Marian Balakowicz   Add support for m...
61
62
  #include <miiphy.h>
  #endif
5da627a42   wdenk   * Patch by Steven...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  /* Ethernet Transmit and Receive Buffers */
  #define DBUF_LENGTH  1520
  #define PKT_MAXBUF_SIZE		1518
  
  static char txbuf[DBUF_LENGTH];
  
  static int next_tx;
  static int next_rx;
  
  /* 4 rx and 4 tx fifos */
  #define NO_OF_FIFOS 4
  
  typedef struct{
  	u32 status;
  	u32 addr;
  	u32 len; /* Only used for tx */
  	u32 not_used;
  } mac_fifo_t;
  
  mac_fifo_t mac_fifo[NO_OF_FIFOS];
  
  #define MAX_WAIT 1000
f01320459   Shinya Kuribayashi   [MIPS] au1x00_eth...
85
  #if defined(CONFIG_CMD_MII)
5700bb635   Mike Frysinger   miiphy: constify ...
86
  int  au1x00_miiphy_read(const char *devname, unsigned char addr,
f01320459   Shinya Kuribayashi   [MIPS] au1x00_eth...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  		unsigned char reg, unsigned short * value)
  {
  	volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
  	volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
  	u32 mii_control;
  	unsigned int timedout = 20;
  
  	while (*mii_control_reg & MAC_MII_BUSY) {
  		udelay(1000);
  		if (--timedout == 0) {
  			printf("au1x00_eth: miiphy_read busy timeout!!
  ");
  			return -1;
  		}
  	}
  
  	mii_control = MAC_SET_MII_SELECT_REG(reg) |
  		MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_READ;
  
  	*mii_control_reg = mii_control;
  
  	timedout = 20;
  	while (*mii_control_reg & MAC_MII_BUSY) {
  		udelay(1000);
  		if (--timedout == 0) {
  			printf("au1x00_eth: miiphy_read busy timeout!!
  ");
  			return -1;
  		}
  	}
  	*value = *mii_data_reg;
  	return 0;
  }
5700bb635   Mike Frysinger   miiphy: constify ...
120
  int  au1x00_miiphy_write(const char *devname, unsigned char addr,
f01320459   Shinya Kuribayashi   [MIPS] au1x00_eth...
121
122
123
124
125
126
127
128
129
130
131
132
  		unsigned char reg, unsigned short value)
  {
  	volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
  	volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
  	u32 mii_control;
  	unsigned int timedout = 20;
  
  	while (*mii_control_reg & MAC_MII_BUSY) {
  		udelay(1000);
  		if (--timedout == 0) {
  			printf("au1x00_eth: miiphy_write busy timeout!!
  ");
4fbd0741b   Shinya Kuribayashi   [MIPS] au1x00_eth...
133
  			return -1;
f01320459   Shinya Kuribayashi   [MIPS] au1x00_eth...
134
135
136
137
138
139
140
141
142
143
144
  		}
  	}
  
  	mii_control = MAC_SET_MII_SELECT_REG(reg) |
  		MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_WRITE;
  
  	*mii_data_reg = value;
  	*mii_control_reg = mii_control;
  	return 0;
  }
  #endif
5da627a42   wdenk   * Patch by Steven...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  static int au1x00_send(struct eth_device* dev, volatile void *packet, int length){
  	volatile mac_fifo_t *fifo_tx =
  		(volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
  	int i;
  	int res;
  
  	/* tx fifo should always be idle */
  	fifo_tx[next_tx].len = length;
  	fifo_tx[next_tx].addr = (virt_to_phys(packet))|TX_DMA_ENABLE;
  	au_sync();
  
  	udelay(1);
  	i=0;
  	while(!(fifo_tx[next_tx].addr&TX_T_DONE)){
  		if(i>MAX_WAIT){
  			printf("TX timeout
  ");
  			break;
  		}
  		udelay(1);
  		i++;
  	}
  
  	/* Clear done bit */
  	fifo_tx[next_tx].addr = 0;
  	fifo_tx[next_tx].len = 0;
  	au_sync();
  
  	res = fifo_tx[next_tx].status;
  
  	next_tx++;
  	if(next_tx>=NO_OF_FIFOS){
  		next_tx=0;
  	}
  	return(res);
  }
  
  static int au1x00_recv(struct eth_device* dev){
  	volatile mac_fifo_t *fifo_rx =
  		(volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
  
  	int length;
  	u32 status;
  
  	for(;;){
  		if(!(fifo_rx[next_rx].addr&RX_T_DONE)){
  			/* Nothing has been received */
  			return(-1);
  		}
  
  		status = fifo_rx[next_rx].status;
  
  		length = status&0x3FFF;
  
  		if(status&RX_ERROR){
  			printf("Rx error 0x%x
  ", status);
  		}
  		else{
  			/* Pass the packet up to the protocol layers. */
  			NetReceive(NetRxPackets[next_rx], length - 4);
  		}
  
  		fifo_rx[next_rx].addr = (virt_to_phys(NetRxPackets[next_rx]))|RX_DMA_ENABLE;
  
  		next_rx++;
  		if(next_rx>=NO_OF_FIFOS){
  			next_rx=0;
  		}
  	} /* for */
  
  	return(0); /* Does anyone use this? */
  }
  
  static int au1x00_init(struct eth_device* dev, bd_t * bd){
  
  	volatile u32 *macen = (volatile u32*)MAC0_ENABLE;
  	volatile u32 *mac_ctrl = (volatile u32*)(ETH0_BASE+MAC_CONTROL);
  	volatile u32 *mac_addr_high = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_HIGH);
  	volatile u32 *mac_addr_low = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_LOW);
  	volatile u32 *mac_mcast_high = (volatile u32*)(ETH0_BASE+MAC_MCAST_HIGH);
  	volatile u32 *mac_mcast_low = (volatile u32*)(ETH0_BASE+MAC_MCAST_LOW);
  	volatile mac_fifo_t *fifo_tx =
  		(volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
  	volatile mac_fifo_t *fifo_rx =
  		(volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
  	int i;
4bc12f1cc   Wolfgang Denk   Fix ethernet time...
232
233
  	next_tx = TX_GET_DMA_BUFFER(fifo_tx[0].addr);
  	next_rx = RX_GET_DMA_BUFFER(fifo_rx[0].addr);
5da627a42   wdenk   * Patch by Steven...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  
  	/* We have to enable clocks before releasing reset */
  	*macen = MAC_EN_CLOCK_ENABLE;
  	udelay(10);
  
  	/* Enable MAC0 */
  	/* We have to release reset before accessing registers */
  	*macen = MAC_EN_CLOCK_ENABLE|MAC_EN_RESET0|
  		MAC_EN_RESET1|MAC_EN_RESET2;
  	udelay(10);
  
  	for(i=0;i<NO_OF_FIFOS;i++){
  		fifo_tx[i].len = 0;
  		fifo_tx[i].addr = virt_to_phys(&txbuf[0]);
  		fifo_rx[i].addr = (virt_to_phys(NetRxPackets[i]))|RX_DMA_ENABLE;
  	}
  
  	/* Put mac addr in little endian */
  #define ea eth_get_dev()->enetaddr
265817c7e   Wolfgang Denk   Add support for A...
253
254
255
  	*mac_addr_high	=	(ea[5] <<  8) | (ea[4]	    ) ;
  	*mac_addr_low	=	(ea[3] << 24) | (ea[2] << 16) |
  		(ea[1] <<  8) | (ea[0]	    ) ;
5da627a42   wdenk   * Patch by Steven...
256
  #undef ea
5da627a42   wdenk   * Patch by Steven...
257
258
  	*mac_mcast_low = 0;
  	*mac_mcast_high = 0;
63f349124   wdenk   * Patch by AndrĂ© ...
259
260
261
262
263
264
  	/* Make sure the MAC buffer is in the correct endian mode */
  #ifdef __LITTLE_ENDIAN
  	*mac_ctrl = MAC_FULL_DUPLEX;
  	udelay(1);
  	*mac_ctrl = MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
  #else
5da627a42   wdenk   * Patch by Steven...
265
266
267
  	*mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX;
  	udelay(1);
  	*mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
63f349124   wdenk   * Patch by AndrĂ© ...
268
  #endif
5da627a42   wdenk   * Patch by Steven...
269
270
271
272
273
  
  	return(1);
  }
  
  static void au1x00_halt(struct eth_device* dev){
87423d740   Thomas Lange   MIPS: Implement e...
274
275
276
277
  	volatile u32 *macen = (volatile u32*)MAC0_ENABLE;
  
  	/* Put MAC0 in reset */
  	*macen = 0;
5da627a42   wdenk   * Patch by Steven...
278
279
280
281
  }
  
  int au1x00_enet_initialize(bd_t *bis){
  	struct eth_device* dev;
955153061   Wolfgang Denk   au1x00_eth.c: che...
282
283
284
  	if ((dev = (struct eth_device*)malloc(sizeof *dev)) == NULL) {
  		puts ("malloc failed
  ");
5dfb3ee3f   Shinya Kuribayashi   net: Move initial...
285
  		return -1;
955153061   Wolfgang Denk   au1x00_eth.c: che...
286
  	}
5da627a42   wdenk   * Patch by Steven...
287
  	memset(dev, 0, sizeof *dev);
955153061   Wolfgang Denk   au1x00_eth.c: che...
288
  	sprintf(dev->name, "Au1X00 ethernet");
5da627a42   wdenk   * Patch by Steven...
289
290
291
292
293
294
295
296
  	dev->iobase = 0;
  	dev->priv   = 0;
  	dev->init   = au1x00_init;
  	dev->halt   = au1x00_halt;
  	dev->send   = au1x00_send;
  	dev->recv   = au1x00_recv;
  
  	eth_register(dev);
4431283c7   Jon Loeliger   cpu/m*: Remove ob...
297
  #if defined(CONFIG_CMD_MII)
63ff004c4   Marian Balakowicz   Add support for m...
298
299
300
  	miiphy_register(dev->name,
  		au1x00_miiphy_read, au1x00_miiphy_write);
  #endif
5da627a42   wdenk   * Patch by Steven...
301
302
  	return 1;
  }