From 0c0a9cda1bde37106520476ed486bd67eb8d30ae Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 16 Jul 2007 00:31:07 +0200 Subject: [PATCH] [PATCH] Support for Xilinx EmacLite controller --- Makefile | 3 +- drivers/net/Makefile | 45 ++++ drivers/net/xilinx_emaclite.c | 378 ++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 drivers/net/Makefile create mode 100644 drivers/net/xilinx_emaclite.c diff --git a/Makefile b/Makefile index 2d2a68535b..146f647d2c 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,7 @@ ifeq ($(ARCH),m68k) CROSS_COMPILE = m68k-elf- endif ifeq ($(ARCH),microblaze) -CROSS_COMPILE = mb- +CROSS_COMPILE = microblaze-uclinux- endif ifeq ($(ARCH),blackfin) CROSS_COMPILE = bfin-uclinux- @@ -207,6 +207,7 @@ LIBS += dtt/libdtt.a LIBS += drivers/libdrivers.a LIBS += drivers/nand/libnand.a LIBS += drivers/nand_legacy/libnand_legacy.a +LIBS += drivers/net/libnetdrv.a ifeq ($(CPU),mpc83xx) LIBS += drivers/qe/qe.a endif diff --git a/drivers/net/Makefile b/drivers/net/Makefile new file mode 100644 index 0000000000..a10d0819f9 --- /dev/null +++ b/drivers/net/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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 $(TOPDIR)/config.mk + +LIB := $(obj)libnetdrv.a + +COBJS := xilinx_emaclite.o + +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c new file mode 100644 index 0000000000..7e69211af9 --- /dev/null +++ b/drivers/net/xilinx_emaclite.c @@ -0,0 +1,378 @@ +/* + * (C) Copyright 2007 Michal Simek + * + * Michal SIMEK + * + * 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 +#include +#include +#include + +#ifdef XILINX_EMACLITE_BASEADDR + +//#define DEBUG + +#define ENET_MAX_MTU PKTSIZE +#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN +#define ENET_ADDR_LENGTH 6 + +/* EmacLite constants */ +#define XEL_BUFFER_OFFSET 0x0800 /* Next buffer's offset */ +#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ +#define XEL_TSR_OFFSET 0x07FC /* Tx status */ +#define XEL_RSR_OFFSET 0x17FC /* Rx status */ +#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ + +/* Xmit complete */ +#define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL +/* Xmit interrupt enable bit */ +#define XEL_TSR_XMIT_IE_MASK 0x00000008UL +/* Buffer is active, SW bit only */ +#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000UL +/* Program the MAC address */ +#define XEL_TSR_PROGRAM_MASK 0x00000002UL +/* define for programming the MAC address into the EMAC Lite */ +#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK) + +/* Transmit packet length upper byte */ +#define XEL_TPLR_LENGTH_MASK_HI 0x0000FF00UL +/* Transmit packet length lower byte */ +#define XEL_TPLR_LENGTH_MASK_LO 0x000000FFUL + +/* Recv complete */ +#define XEL_RSR_RECV_DONE_MASK 0x00000001UL +/* Recv interrupt enable bit */ +#define XEL_RSR_RECV_IE_MASK 0x00000008UL + +typedef struct { + unsigned int BaseAddress; /* Base address for device (IPIF) */ + unsigned int NextTxBufferToUse; /* Next TX buffer to write to */ + unsigned int NextRxBufferToUse; /* Next RX buffer to read from */ + unsigned char DeviceId; /* Unique ID of device - for future */ +} XEmacLite; + +static XEmacLite EmacLite; + +static char etherrxbuff[PKTSIZE_ALIGN]; /* Receive buffer */ + +/* hardcoded MAC address for the Xilinx EMAC Core when env is nowhere*/ +#ifdef CFG_ENV_IS_NOWHERE +static u8 EMACAddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 }; +#endif + +void XEmacLite_AlignedRead (u32 * SrcPtr, void *DestPtr, unsigned ByteCount) +{ + unsigned i; + unsigned Length = ByteCount; + u32 AlignBuffer; + u32 *To32Ptr; + u32 *From32Ptr; + u8 *To8Ptr; + u8 *From8Ptr; + + From32Ptr = (u32 *) SrcPtr; + + /* Word aligned buffer, no correction needed. */ + To32Ptr = (u32 *) DestPtr; + while (Length > 3) { + *To32Ptr++ = *From32Ptr++; + Length -= 4; + } + To8Ptr = (u8 *) To32Ptr; + + AlignBuffer = *From32Ptr++; + From8Ptr = (u8 *) & AlignBuffer; + + for (i = 0; i < Length; i++) { + *To8Ptr++ = *From8Ptr++; + } +} + +void XEmacLite_AlignedWrite (void *SrcPtr, u32 * DestPtr, unsigned ByteCount) +{ + unsigned i; + unsigned Length = ByteCount; + u32 AlignBuffer; + u32 *To32Ptr; + u32 *From32Ptr; + u8 *To8Ptr; + u8 *From8Ptr; + To32Ptr = DestPtr; + + From32Ptr = (u32 *) SrcPtr; + while (Length > 3) { + + *To32Ptr++ = *From32Ptr++; + Length -= 4; + } + + AlignBuffer = 0; + To8Ptr = (u8 *) & AlignBuffer; + From8Ptr = (u8 *) From32Ptr; + + for (i = 0; i < Length; i++) { + *To8Ptr++ = *From8Ptr++; + } + + *To32Ptr++ = AlignBuffer; +} + +void eth_halt (void) +{ +#ifdef DEBUG + puts ("eth_halt\n"); +#endif +} + +int eth_init (bd_t * bis) +{ +#ifdef DEBUG + puts ("EmacLite Initialization Started\n"); +#endif + memset (&EmacLite, 0, sizeof (XEmacLite)); + EmacLite.BaseAddress = XILINX_EMACLITE_BASEADDR; + +#ifdef CFG_ENV_IS_NOWHERE + memcpy (bis->bi_enetaddr, EMACAddr, ENET_ADDR_LENGTH); +#endif +/* + * TX - TX_PING & TX_PONG initialization + */ + /* Restart PING TX */ + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, 0); + /* Copy MAC address */ + XEmacLite_AlignedWrite (bis->bi_enetaddr, + EmacLite.BaseAddress, ENET_ADDR_LENGTH); + /* Set the length */ + out_be32 (EmacLite.BaseAddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); + /* Update the MAC address in the EMAC Lite */ + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR); + /* Wait for EMAC Lite to finish with the MAC address update */ + while ((in_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET) & + XEL_TSR_PROG_MAC_ADDR) != 0) ; + +#ifdef XILINX_EMACLITE_TX_PING_PONG + /* The same operation with PONG TX */ + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0); + XEmacLite_AlignedWrite (bis->bi_enetaddr, + EmacLite.BaseAddress + XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH); + out_be32 (EmacLite.BaseAddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, + XEL_TSR_PROG_MAC_ADDR); + while ((in_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + + XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) ; +#endif + +/* + * RX - RX_PING & RX_PONG initialization + */ + /* Write out the value to flush the RX buffer */ + out_be32 (EmacLite.BaseAddress + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK); +#ifdef XILINX_EMACLITE_RX_PING_PONG + out_be32 (EmacLite.BaseAddress + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET, + XEL_RSR_RECV_IE_MASK); +#endif + +#ifdef DEBUG + puts ("EmacLite Initialization complete\n"); +#endif + return 0; +} + +int XEmacLite_TxBufferAvailable (XEmacLite * InstancePtr) +{ + u32 Register; + u32 TxPingBusy; + u32 TxPongBusy; + /* + * Read the other buffer register + * and determine if the other buffer is available + */ + Register = in_be32 (InstancePtr->BaseAddress + + InstancePtr->NextTxBufferToUse + 0); + TxPingBusy = ((Register & XEL_TSR_XMIT_BUSY_MASK) == + XEL_TSR_XMIT_BUSY_MASK); + + Register = in_be32 (InstancePtr->BaseAddress + + (InstancePtr->NextTxBufferToUse ^ XEL_TSR_OFFSET) + 0); + TxPongBusy = ((Register & XEL_TSR_XMIT_BUSY_MASK) == + XEL_TSR_XMIT_BUSY_MASK); + + return (!(TxPingBusy && TxPongBusy)); +} + +int eth_send (volatile void *ptr, int len) { + + unsigned int Register; + unsigned int BaseAddress; + + unsigned maxtry = 1000; + + if (len > ENET_MAX_MTU) + len = ENET_MAX_MTU; + + while (!XEmacLite_TxBufferAvailable (&EmacLite) && maxtry) { + udelay (10); + maxtry--; + } + + if (!maxtry) { + printf ("Error: Timeout waiting for ethernet TX buffer\n"); + /* Restart PING TX */ + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, 0); +#ifdef XILINX_EMACLITE_TX_PING_PONG + out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + + XEL_BUFFER_OFFSET, 0); +#endif + return 0; + } + + /* Determine the expected TX buffer address */ + BaseAddress = (EmacLite.BaseAddress + EmacLite.NextTxBufferToUse); + + /* Determine if the expected buffer address is empty */ + Register = in_be32 (BaseAddress + XEL_TSR_OFFSET); + if (((Register & XEL_TSR_XMIT_BUSY_MASK) == 0) + && ((in_be32 ((BaseAddress) + XEL_TSR_OFFSET) + & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { + +#ifdef XILINX_EMACLITE_TX_PING_PONG + EmacLite.NextTxBufferToUse ^= XEL_BUFFER_OFFSET; +#endif +#ifdef DEBUG + printf ("Send packet from 0x%x\n", BaseAddress); +#endif + /* Write the frame to the buffer */ + XEmacLite_AlignedWrite (ptr, (u32 *) BaseAddress, len); + out_be32 (BaseAddress + XEL_TPLR_OFFSET,(len & + (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO))); + Register = in_be32 (BaseAddress + XEL_TSR_OFFSET); + Register |= XEL_TSR_XMIT_BUSY_MASK; + if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) { + Register |= XEL_TSR_XMIT_ACTIVE_MASK; + } + out_be32 (BaseAddress + XEL_TSR_OFFSET, Register); + return 1; + } +#ifdef XILINX_EMACLITE_TX_PING_PONG + /* Switch to second buffer */ + BaseAddress ^= XEL_BUFFER_OFFSET; + /* Determine if the expected buffer address is empty */ + Register = in_be32 (BaseAddress + XEL_TSR_OFFSET); + if (((Register & XEL_TSR_XMIT_BUSY_MASK) == 0) + && ((in_be32 ((BaseAddress) + XEL_TSR_OFFSET) + & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { +#ifdef DEBUG + printf ("Send packet from 0x%x\n", BaseAddress); +#endif + /* Write the frame to the buffer */ + XEmacLite_AlignedWrite (ptr, (u32 *) BaseAddress, len); + out_be32 (BaseAddress + XEL_TPLR_OFFSET,(len & + (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO))); + Register = in_be32 (BaseAddress + XEL_TSR_OFFSET); + Register |= XEL_TSR_XMIT_BUSY_MASK; + if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) { + Register |= XEL_TSR_XMIT_ACTIVE_MASK; + } + out_be32 (BaseAddress + XEL_TSR_OFFSET, Register); + return 1; + } +#endif + puts ("Error while sending frame\n"); + return 0; +} + +int eth_rx (void) +{ + unsigned int Length; + unsigned int Register; + unsigned int BaseAddress; + + BaseAddress = EmacLite.BaseAddress + EmacLite.NextRxBufferToUse; + Register = in_be32 (BaseAddress + XEL_RSR_OFFSET); +#ifdef DEBUG +// printf ("Testing data at address 0x%x\n", BaseAddress); +#endif + if ((Register & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { +#ifdef XILINX_EMACLITE_RX_PING_PONG + EmacLite.NextRxBufferToUse ^= XEL_BUFFER_OFFSET; +#endif + } else { +#ifndef XILINX_EMACLITE_RX_PING_PONG +#ifdef DEBUG +// printf ("No data was available - address 0x%x\n", BaseAddress); +#endif + return 0; +#else + BaseAddress ^= XEL_BUFFER_OFFSET; + Register = in_be32 (BaseAddress + XEL_RSR_OFFSET); + if ((Register & XEL_RSR_RECV_DONE_MASK) != + XEL_RSR_RECV_DONE_MASK) { +#ifdef DEBUG +// printf ("No data was available - address 0x%x\n", +// BaseAddress); +#endif + return 0; + } +#endif + } + /* Get the length of the frame that arrived */ + switch(((in_be32(BaseAddress + XEL_RXBUFF_OFFSET + 0xC)) & + 0xFFFF0000 ) >> 16) { + case 0x806: + Length = 42 + 20; /* FIXME size of ARP */ +#ifdef DEBUG + puts ("ARP Packet\n"); +#endif + break; + case 0x800: + Length = 14 + 14 + + (((in_be32(BaseAddress + XEL_RXBUFF_OFFSET + 0x10)) & + 0xFFFF0000) >> 16); /* FIXME size of IP packet */ +#ifdef DEBUG + puts("IP Packet\n"); +#endif + break; + default: +#ifdef DEBUG + puts("Other Packet\n"); +#endif + Length = ENET_MAX_MTU; + break; + } + + XEmacLite_AlignedRead ((BaseAddress + XEL_RXBUFF_OFFSET), + etherrxbuff, Length); + + /* Acknowledge the frame */ + Register = in_be32 (BaseAddress + XEL_RSR_OFFSET); + Register &= ~XEL_RSR_RECV_DONE_MASK; + out_be32 (BaseAddress + XEL_RSR_OFFSET, Register); + +#ifdef DEBUG + printf ("Packet receive from 0x%x, length %dB\n", BaseAddress, Length); +#endif + NetReceive ((uchar *) etherrxbuff, Length); + return 1; + +} +#endif -- 2.39.5