]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/xilinx_emaclite.c
malta: correct tcl script path in README.malta
[karo-tx-uboot.git] / drivers / net / xilinx_emaclite.c
1 /*
2  * (C) Copyright 2007-2009 Michal Simek
3  * (C) Copyright 2003 Xilinx Inc.
4  *
5  * Michal SIMEK <monstr@monstr.eu>
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <net.h>
12 #include <config.h>
13 #include <malloc.h>
14 #include <asm/io.h>
15 #include <fdtdec.h>
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 #undef DEBUG
20
21 #define ENET_ADDR_LENGTH        6
22
23 /* EmacLite constants */
24 #define XEL_BUFFER_OFFSET       0x0800  /* Next buffer's offset */
25 #define XEL_TPLR_OFFSET         0x07F4  /* Tx packet length */
26 #define XEL_TSR_OFFSET          0x07FC  /* Tx status */
27 #define XEL_RSR_OFFSET          0x17FC  /* Rx status */
28 #define XEL_RXBUFF_OFFSET       0x1000  /* Receive Buffer */
29
30 /* Xmit complete */
31 #define XEL_TSR_XMIT_BUSY_MASK          0x00000001UL
32 /* Xmit interrupt enable bit */
33 #define XEL_TSR_XMIT_IE_MASK            0x00000008UL
34 /* Buffer is active, SW bit only */
35 #define XEL_TSR_XMIT_ACTIVE_MASK        0x80000000UL
36 /* Program the MAC address */
37 #define XEL_TSR_PROGRAM_MASK            0x00000002UL
38 /* define for programming the MAC address into the EMAC Lite */
39 #define XEL_TSR_PROG_MAC_ADDR   (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK)
40
41 /* Transmit packet length upper byte */
42 #define XEL_TPLR_LENGTH_MASK_HI         0x0000FF00UL
43 /* Transmit packet length lower byte */
44 #define XEL_TPLR_LENGTH_MASK_LO         0x000000FFUL
45
46 /* Recv complete */
47 #define XEL_RSR_RECV_DONE_MASK          0x00000001UL
48 /* Recv interrupt enable bit */
49 #define XEL_RSR_RECV_IE_MASK            0x00000008UL
50
51 struct xemaclite {
52         u32 nexttxbuffertouse;  /* Next TX buffer to write to */
53         u32 nextrxbuffertouse;  /* Next RX buffer to read from */
54         u32 txpp;               /* TX ping pong buffer */
55         u32 rxpp;               /* RX ping pong buffer */
56 };
57
58 static u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
59
60 static void xemaclite_alignedread(u32 *srcptr, void *destptr, u32 bytecount)
61 {
62         u32 i;
63         u32 alignbuffer;
64         u32 *to32ptr;
65         u32 *from32ptr;
66         u8 *to8ptr;
67         u8 *from8ptr;
68
69         from32ptr = (u32 *) srcptr;
70
71         /* Word aligned buffer, no correction needed. */
72         to32ptr = (u32 *) destptr;
73         while (bytecount > 3) {
74                 *to32ptr++ = *from32ptr++;
75                 bytecount -= 4;
76         }
77         to8ptr = (u8 *) to32ptr;
78
79         alignbuffer = *from32ptr++;
80         from8ptr = (u8 *) &alignbuffer;
81
82         for (i = 0; i < bytecount; i++)
83                 *to8ptr++ = *from8ptr++;
84 }
85
86 static void xemaclite_alignedwrite(void *srcptr, u32 destptr, u32 bytecount)
87 {
88         u32 i;
89         u32 alignbuffer;
90         u32 *to32ptr = (u32 *) destptr;
91         u32 *from32ptr;
92         u8 *to8ptr;
93         u8 *from8ptr;
94
95         from32ptr = (u32 *) srcptr;
96         while (bytecount > 3) {
97
98                 *to32ptr++ = *from32ptr++;
99                 bytecount -= 4;
100         }
101
102         alignbuffer = 0;
103         to8ptr = (u8 *) &alignbuffer;
104         from8ptr = (u8 *) from32ptr;
105
106         for (i = 0; i < bytecount; i++)
107                 *to8ptr++ = *from8ptr++;
108
109         *to32ptr++ = alignbuffer;
110 }
111
112 static void emaclite_halt(struct eth_device *dev)
113 {
114         debug("eth_halt\n");
115 }
116
117 static int emaclite_init(struct eth_device *dev, bd_t *bis)
118 {
119         struct xemaclite *emaclite = dev->priv;
120         debug("EmacLite Initialization Started\n");
121
122 /*
123  * TX - TX_PING & TX_PONG initialization
124  */
125         /* Restart PING TX */
126         out_be32 (dev->iobase + XEL_TSR_OFFSET, 0);
127         /* Copy MAC address */
128         xemaclite_alignedwrite(dev->enetaddr, dev->iobase, ENET_ADDR_LENGTH);
129         /* Set the length */
130         out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
131         /* Update the MAC address in the EMAC Lite */
132         out_be32 (dev->iobase + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR);
133         /* Wait for EMAC Lite to finish with the MAC address update */
134         while ((in_be32 (dev->iobase + XEL_TSR_OFFSET) &
135                 XEL_TSR_PROG_MAC_ADDR) != 0)
136                 ;
137
138         if (emaclite->txpp) {
139                 /* The same operation with PONG TX */
140                 out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
141                 xemaclite_alignedwrite(dev->enetaddr, dev->iobase +
142                         XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
143                 out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
144                 out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
145                         XEL_TSR_PROG_MAC_ADDR);
146                 while ((in_be32 (dev->iobase + XEL_TSR_OFFSET +
147                         XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0)
148                         ;
149         }
150
151 /*
152  * RX - RX_PING & RX_PONG initialization
153  */
154         /* Write out the value to flush the RX buffer */
155         out_be32 (dev->iobase + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK);
156
157         if (emaclite->rxpp)
158                 out_be32 (dev->iobase + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET,
159                         XEL_RSR_RECV_IE_MASK);
160
161         debug("EmacLite Initialization complete\n");
162         return 0;
163 }
164
165 static int xemaclite_txbufferavailable(struct eth_device *dev)
166 {
167         u32 reg;
168         u32 txpingbusy;
169         u32 txpongbusy;
170         struct xemaclite *emaclite = dev->priv;
171
172         /*
173          * Read the other buffer register
174          * and determine if the other buffer is available
175          */
176         reg = in_be32 (dev->iobase +
177                         emaclite->nexttxbuffertouse + 0);
178         txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
179                         XEL_TSR_XMIT_BUSY_MASK);
180
181         reg = in_be32 (dev->iobase +
182                         (emaclite->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0);
183         txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
184                         XEL_TSR_XMIT_BUSY_MASK);
185
186         return !(txpingbusy && txpongbusy);
187 }
188
189 static int emaclite_send(struct eth_device *dev, void *ptr, int len)
190 {
191         u32 reg;
192         u32 baseaddress;
193         struct xemaclite *emaclite = dev->priv;
194
195         u32 maxtry = 1000;
196
197         if (len > PKTSIZE)
198                 len = PKTSIZE;
199
200         while (!xemaclite_txbufferavailable(dev) && maxtry) {
201                 udelay(10);
202                 maxtry--;
203         }
204
205         if (!maxtry) {
206                 printf("Error: Timeout waiting for ethernet TX buffer\n");
207                 /* Restart PING TX */
208                 out_be32 (dev->iobase + XEL_TSR_OFFSET, 0);
209                 if (emaclite->txpp) {
210                         out_be32 (dev->iobase + XEL_TSR_OFFSET +
211                                 XEL_BUFFER_OFFSET, 0);
212                 }
213                 return -1;
214         }
215
216         /* Determine the expected TX buffer address */
217         baseaddress = (dev->iobase + emaclite->nexttxbuffertouse);
218
219         /* Determine if the expected buffer address is empty */
220         reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
221         if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
222                 && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
223                         & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
224
225                 if (emaclite->txpp)
226                         emaclite->nexttxbuffertouse ^= XEL_BUFFER_OFFSET;
227
228                 debug("Send packet from 0x%x\n", baseaddress);
229                 /* Write the frame to the buffer */
230                 xemaclite_alignedwrite(ptr, baseaddress, len);
231                 out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
232                         (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
233                 reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
234                 reg |= XEL_TSR_XMIT_BUSY_MASK;
235                 if ((reg & XEL_TSR_XMIT_IE_MASK) != 0)
236                         reg |= XEL_TSR_XMIT_ACTIVE_MASK;
237                 out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
238                 return 0;
239         }
240
241         if (emaclite->txpp) {
242                 /* Switch to second buffer */
243                 baseaddress ^= XEL_BUFFER_OFFSET;
244                 /* Determine if the expected buffer address is empty */
245                 reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
246                 if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
247                         && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
248                                 & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
249                         debug("Send packet from 0x%x\n", baseaddress);
250                         /* Write the frame to the buffer */
251                         xemaclite_alignedwrite(ptr, baseaddress, len);
252                         out_be32 (baseaddress + XEL_TPLR_OFFSET, (len &
253                                 (XEL_TPLR_LENGTH_MASK_HI |
254                                         XEL_TPLR_LENGTH_MASK_LO)));
255                         reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
256                         reg |= XEL_TSR_XMIT_BUSY_MASK;
257                         if ((reg & XEL_TSR_XMIT_IE_MASK) != 0)
258                                 reg |= XEL_TSR_XMIT_ACTIVE_MASK;
259                         out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
260                         return 0;
261                 }
262         }
263
264         puts("Error while sending frame\n");
265         return -1;
266 }
267
268 static int emaclite_recv(struct eth_device *dev)
269 {
270         u32 length;
271         u32 reg;
272         u32 baseaddress;
273         struct xemaclite *emaclite = dev->priv;
274
275         baseaddress = dev->iobase + emaclite->nextrxbuffertouse;
276         reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
277         debug("Testing data at address 0x%x\n", baseaddress);
278         if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
279                 if (emaclite->rxpp)
280                         emaclite->nextrxbuffertouse ^= XEL_BUFFER_OFFSET;
281         } else {
282
283                 if (!emaclite->rxpp) {
284                         debug("No data was available - address 0x%x\n",
285                                                                 baseaddress);
286                         return 0;
287                 } else {
288                         baseaddress ^= XEL_BUFFER_OFFSET;
289                         reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
290                         if ((reg & XEL_RSR_RECV_DONE_MASK) !=
291                                                 XEL_RSR_RECV_DONE_MASK) {
292                                 debug("No data was available - address 0x%x\n",
293                                                 baseaddress);
294                                 return 0;
295                         }
296                 }
297         }
298         /* Get the length of the frame that arrived */
299         switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) &
300                         0xFFFF0000 ) >> 16) {
301                 case 0x806:
302                         length = 42 + 20; /* FIXME size of ARP */
303                         debug("ARP Packet\n");
304                         break;
305                 case 0x800:
306                         length = 14 + 14 +
307                         (((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET +
308                                                 0x10))) & 0xFFFF0000) >> 16);
309                         /* FIXME size of IP packet */
310                         debug ("IP Packet\n");
311                         break;
312                 default:
313                         debug("Other Packet\n");
314                         length = PKTSIZE;
315                         break;
316         }
317
318         xemaclite_alignedread((u32 *) (baseaddress + XEL_RXBUFF_OFFSET),
319                         etherrxbuff, length);
320
321         /* Acknowledge the frame */
322         reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
323         reg &= ~XEL_RSR_RECV_DONE_MASK;
324         out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
325
326         debug("Packet receive from 0x%x, length %dB\n", baseaddress, length);
327         NetReceive((uchar *) etherrxbuff, length);
328         return length;
329
330 }
331
332 int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr,
333                                                         int txpp, int rxpp)
334 {
335         struct eth_device *dev;
336         struct xemaclite *emaclite;
337
338         dev = calloc(1, sizeof(*dev));
339         if (dev == NULL)
340                 return -1;
341
342         emaclite = calloc(1, sizeof(struct xemaclite));
343         if (emaclite == NULL) {
344                 free(dev);
345                 return -1;
346         }
347
348         dev->priv = emaclite;
349
350         emaclite->txpp = txpp;
351         emaclite->rxpp = rxpp;
352
353         sprintf(dev->name, "Xelite.%lx", base_addr);
354
355         dev->iobase = base_addr;
356         dev->init = emaclite_init;
357         dev->halt = emaclite_halt;
358         dev->send = emaclite_send;
359         dev->recv = emaclite_recv;
360
361         eth_register(dev);
362
363         return 1;
364 }
365
366 #ifdef CONFIG_OF_CONTROL
367 int xilinx_emaclite_init(bd_t *bis)
368 {
369         int offset = 0;
370         u32 ret = 0;
371         u32 reg;
372
373         do {
374                 offset = fdt_node_offset_by_compatible(gd->fdt_blob, offset,
375                                         "xlnx,xps-ethernetlite-1.00.a");
376                 if (offset != -1) {
377                         reg = fdtdec_get_addr(gd->fdt_blob, offset, "reg");
378                         if (reg != FDT_ADDR_T_NONE) {
379                                 u32 rxpp = fdtdec_get_int(gd->fdt_blob, offset,
380                                                         "xlnx,rx-ping-pong", 0);
381                                 u32 txpp = fdtdec_get_int(gd->fdt_blob, offset,
382                                                         "xlnx,tx-ping-pong", 0);
383                                 ret |= xilinx_emaclite_initialize(bis, reg,
384                                                                 txpp, rxpp);
385                         }
386                 }
387         } while (offset != -1);
388
389         return ret;
390 }
391 #endif