blob: ef9be891ec1f674a7f64afe4b54db5727a5eae63 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk9b7f3842003-10-09 20:09:04 +00002/* Only eth0 supported for now
3 *
4 * (C) Copyright 2003
5 * Thomas.Lange@corelatus.se
wdenk9b7f3842003-10-09 20:09:04 +00006 */
7#include <config.h>
8
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02009#if defined(CONFIG_SYS_DISCOVER_PHY)
Wolfgang Denk0cbaf642005-09-25 00:53:22 +020010#error "PHY not supported yet"
wdenk9b7f3842003-10-09 20:09:04 +000011/* We just assume that we are running 100FD for now */
12/* We all use switches, right? ;-) */
13#endif
14
wdenk4ea537d2003-12-07 18:32:37 +000015/* I assume ethernet behaves like au1000 */
16
Shinya Kuribayashied49a6a2008-06-07 20:51:56 +090017#ifdef CONFIG_SOC_AU1000
wdenk9b7f3842003-10-09 20:09:04 +000018/* Base address differ between cpu:s */
19#define ETH0_BASE AU1000_ETH0_BASE
20#define MAC0_ENABLE AU1000_MAC0_ENABLE
21#else
Shinya Kuribayashied49a6a2008-06-07 20:51:56 +090022#ifdef CONFIG_SOC_AU1100
wdenk4ea537d2003-12-07 18:32:37 +000023#define ETH0_BASE AU1100_ETH0_BASE
24#define MAC0_ENABLE AU1100_MAC0_ENABLE
25#else
Shinya Kuribayashied49a6a2008-06-07 20:51:56 +090026#ifdef CONFIG_SOC_AU1500
wdenk4ea537d2003-12-07 18:32:37 +000027#define ETH0_BASE AU1500_ETH0_BASE
28#define MAC0_ENABLE AU1500_MAC0_ENABLE
29#else
30#error "No valid cpu set"
31#endif
32#endif
wdenk9b7f3842003-10-09 20:09:04 +000033#endif
34
35#include <common.h>
36#include <malloc.h>
37#include <net.h>
38#include <command.h>
39#include <asm/io.h>
Daniel Schwierzeck536ce922015-12-21 16:35:14 +010040#include <mach/au1x00.h>
wdenk9b7f3842003-10-09 20:09:04 +000041
Jon Loeliger526e5ce2007-07-09 19:06:00 -050042#if defined(CONFIG_CMD_MII)
Marian Balakowiczaab8c492005-10-28 22:30:33 +020043#include <miiphy.h>
44#endif
45
wdenk9b7f3842003-10-09 20:09:04 +000046/* Ethernet Transmit and Receive Buffers */
47#define DBUF_LENGTH 1520
48#define PKT_MAXBUF_SIZE 1518
49
50static char txbuf[DBUF_LENGTH];
51
52static int next_tx;
53static int next_rx;
54
55/* 4 rx and 4 tx fifos */
56#define NO_OF_FIFOS 4
57
58typedef struct{
59 u32 status;
60 u32 addr;
61 u32 len; /* Only used for tx */
62 u32 not_used;
63} mac_fifo_t;
64
65mac_fifo_t mac_fifo[NO_OF_FIFOS];
66
67#define MAX_WAIT 1000
68
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +090069#if defined(CONFIG_CMD_MII)
Joe Hershberger1fbcbed2016-08-08 11:28:38 -050070int au1x00_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +090071{
Joe Hershberger1fbcbed2016-08-08 11:28:38 -050072 unsigned short value = 0;
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +090073 volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
74 volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
75 u32 mii_control;
76 unsigned int timedout = 20;
77
78 while (*mii_control_reg & MAC_MII_BUSY) {
79 udelay(1000);
80 if (--timedout == 0) {
81 printf("au1x00_eth: miiphy_read busy timeout!!\n");
82 return -1;
83 }
84 }
85
86 mii_control = MAC_SET_MII_SELECT_REG(reg) |
87 MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_READ;
88
89 *mii_control_reg = mii_control;
90
91 timedout = 20;
92 while (*mii_control_reg & MAC_MII_BUSY) {
93 udelay(1000);
94 if (--timedout == 0) {
95 printf("au1x00_eth: miiphy_read busy timeout!!\n");
96 return -1;
97 }
98 }
Joe Hershberger1fbcbed2016-08-08 11:28:38 -050099 value = *mii_data_reg;
100 return value;
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +0900101}
102
Joe Hershberger1fbcbed2016-08-08 11:28:38 -0500103int au1x00_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
104 u16 value)
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +0900105{
106 volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
107 volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
108 u32 mii_control;
109 unsigned int timedout = 20;
110
111 while (*mii_control_reg & MAC_MII_BUSY) {
112 udelay(1000);
113 if (--timedout == 0) {
114 printf("au1x00_eth: miiphy_write busy timeout!!\n");
Shinya Kuribayashiac263152007-10-27 15:22:33 +0900115 return -1;
Shinya Kuribayashi8df3da22007-10-27 15:00:25 +0900116 }
117 }
118
119 mii_control = MAC_SET_MII_SELECT_REG(reg) |
120 MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_WRITE;
121
122 *mii_data_reg = value;
123 *mii_control_reg = mii_control;
124 return 0;
125}
126#endif
127
Joe Hershbergere4e04882012-05-22 18:36:19 +0000128static int au1x00_send(struct eth_device *dev, void *packet, int length)
129{
wdenk9b7f3842003-10-09 20:09:04 +0000130 volatile mac_fifo_t *fifo_tx =
131 (volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
132 int i;
133 int res;
134
135 /* tx fifo should always be idle */
136 fifo_tx[next_tx].len = length;
137 fifo_tx[next_tx].addr = (virt_to_phys(packet))|TX_DMA_ENABLE;
138 au_sync();
139
140 udelay(1);
141 i=0;
142 while(!(fifo_tx[next_tx].addr&TX_T_DONE)){
143 if(i>MAX_WAIT){
144 printf("TX timeout\n");
145 break;
146 }
147 udelay(1);
148 i++;
149 }
150
151 /* Clear done bit */
152 fifo_tx[next_tx].addr = 0;
153 fifo_tx[next_tx].len = 0;
154 au_sync();
155
156 res = fifo_tx[next_tx].status;
157
158 next_tx++;
159 if(next_tx>=NO_OF_FIFOS){
160 next_tx=0;
161 }
162 return(res);
163}
164
165static int au1x00_recv(struct eth_device* dev){
166 volatile mac_fifo_t *fifo_rx =
167 (volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
168
169 int length;
170 u32 status;
171
172 for(;;){
173 if(!(fifo_rx[next_rx].addr&RX_T_DONE)){
174 /* Nothing has been received */
175 return(-1);
176 }
177
178 status = fifo_rx[next_rx].status;
179
180 length = status&0x3FFF;
181
182 if(status&RX_ERROR){
183 printf("Rx error 0x%x\n", status);
Joe Hershberger9f09a362015-04-08 01:41:06 -0500184 } else {
wdenk9b7f3842003-10-09 20:09:04 +0000185 /* Pass the packet up to the protocol layers. */
Joe Hershberger9f09a362015-04-08 01:41:06 -0500186 net_process_received_packet(net_rx_packets[next_rx],
187 length - 4);
wdenk9b7f3842003-10-09 20:09:04 +0000188 }
189
Joe Hershberger9f09a362015-04-08 01:41:06 -0500190 fifo_rx[next_rx].addr =
191 (virt_to_phys(net_rx_packets[next_rx])) | RX_DMA_ENABLE;
wdenk9b7f3842003-10-09 20:09:04 +0000192
193 next_rx++;
194 if(next_rx>=NO_OF_FIFOS){
195 next_rx=0;
196 }
197 } /* for */
198
199 return(0); /* Does anyone use this? */
200}
201
202static int au1x00_init(struct eth_device* dev, bd_t * bd){
203
204 volatile u32 *macen = (volatile u32*)MAC0_ENABLE;
205 volatile u32 *mac_ctrl = (volatile u32*)(ETH0_BASE+MAC_CONTROL);
206 volatile u32 *mac_addr_high = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_HIGH);
207 volatile u32 *mac_addr_low = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_LOW);
208 volatile u32 *mac_mcast_high = (volatile u32*)(ETH0_BASE+MAC_MCAST_HIGH);
209 volatile u32 *mac_mcast_low = (volatile u32*)(ETH0_BASE+MAC_MCAST_LOW);
210 volatile mac_fifo_t *fifo_tx =
211 (volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
212 volatile mac_fifo_t *fifo_rx =
213 (volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
214 int i;
215
Wolfgang Denkaa9d1522005-09-24 22:05:40 +0200216 next_tx = TX_GET_DMA_BUFFER(fifo_tx[0].addr);
217 next_rx = RX_GET_DMA_BUFFER(fifo_rx[0].addr);
wdenk9b7f3842003-10-09 20:09:04 +0000218
219 /* We have to enable clocks before releasing reset */
220 *macen = MAC_EN_CLOCK_ENABLE;
221 udelay(10);
222
223 /* Enable MAC0 */
224 /* We have to release reset before accessing registers */
225 *macen = MAC_EN_CLOCK_ENABLE|MAC_EN_RESET0|
226 MAC_EN_RESET1|MAC_EN_RESET2;
227 udelay(10);
228
229 for(i=0;i<NO_OF_FIFOS;i++){
230 fifo_tx[i].len = 0;
231 fifo_tx[i].addr = virt_to_phys(&txbuf[0]);
Joe Hershberger9f09a362015-04-08 01:41:06 -0500232 fifo_rx[i].addr = (virt_to_phys(net_rx_packets[i])) |
233 RX_DMA_ENABLE;
wdenk9b7f3842003-10-09 20:09:04 +0000234 }
235
236 /* Put mac addr in little endian */
Joe Hershberger11cd5a02015-03-22 17:09:00 -0500237#define ea eth_get_ethaddr()
Wolfgang Denk0cbaf642005-09-25 00:53:22 +0200238 *mac_addr_high = (ea[5] << 8) | (ea[4] ) ;
239 *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) |
240 (ea[1] << 8) | (ea[0] ) ;
wdenk9b7f3842003-10-09 20:09:04 +0000241#undef ea
wdenk9b7f3842003-10-09 20:09:04 +0000242 *mac_mcast_low = 0;
243 *mac_mcast_high = 0;
244
wdenk0260cd62004-01-02 15:01:32 +0000245 /* Make sure the MAC buffer is in the correct endian mode */
246#ifdef __LITTLE_ENDIAN
247 *mac_ctrl = MAC_FULL_DUPLEX;
248 udelay(1);
249 *mac_ctrl = MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
250#else
wdenk9b7f3842003-10-09 20:09:04 +0000251 *mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX;
252 udelay(1);
253 *mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
wdenk0260cd62004-01-02 15:01:32 +0000254#endif
wdenk9b7f3842003-10-09 20:09:04 +0000255
256 return(1);
257}
258
259static void au1x00_halt(struct eth_device* dev){
Thomas Lange5451a202009-04-24 16:22:16 +0200260 volatile u32 *macen = (volatile u32*)MAC0_ENABLE;
261
262 /* Put MAC0 in reset */
263 *macen = 0;
wdenk9b7f3842003-10-09 20:09:04 +0000264}
265
266int au1x00_enet_initialize(bd_t *bis){
267 struct eth_device* dev;
268
Wolfgang Denk16aedb92006-03-13 01:00:22 +0100269 if ((dev = (struct eth_device*)malloc(sizeof *dev)) == NULL) {
270 puts ("malloc failed\n");
Shinya Kuribayashi93971f62008-10-19 12:08:50 +0900271 return -1;
Wolfgang Denk16aedb92006-03-13 01:00:22 +0100272 }
273
wdenk9b7f3842003-10-09 20:09:04 +0000274 memset(dev, 0, sizeof *dev);
275
Ben Whitten34fd6c92015-12-30 13:05:58 +0000276 strcpy(dev->name, "Au1X00 ethernet");
wdenk9b7f3842003-10-09 20:09:04 +0000277 dev->iobase = 0;
278 dev->priv = 0;
279 dev->init = au1x00_init;
280 dev->halt = au1x00_halt;
281 dev->send = au1x00_send;
282 dev->recv = au1x00_recv;
283
284 eth_register(dev);
285
Jon Loeliger526e5ce2007-07-09 19:06:00 -0500286#if defined(CONFIG_CMD_MII)
Joe Hershberger1fbcbed2016-08-08 11:28:38 -0500287 int retval;
288 struct mii_dev *mdiodev = mdio_alloc();
289 if (!mdiodev)
290 return -ENOMEM;
291 strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
292 mdiodev->read = au1x00_miiphy_read;
293 mdiodev->write = au1x00_miiphy_write;
294
295 retval = mdio_register(mdiodev);
296 if (retval < 0)
297 return retval;
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200298#endif
299
wdenk9b7f3842003-10-09 20:09:04 +0000300 return 1;
301}
Daniel Schwierzeck74fc3c02015-01-29 14:47:01 +0100302
303int cpu_eth_init(bd_t *bis)
304{
305 au1x00_enet_initialize(bis);
306 return 0;
307}