mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-30 00:21:06 +00:00
d3f871482f
The environment is the canonical storage location of the mac address, so we're killing off the global data location and moving everything to querying the env directly. The drivers that get converted here: 3c589 4xx_enet dc2114x dm9000x enc28j60 fsl_mcdmafec ks8695eth mcffec rtl8019 rtl8169 s3c4510b_eth xilinx_emac xilinx_emaclite Signed-off-by: Mike Frysinger <vapier@gentoo.org> CC: Ben Warren <biggerbadderben@gmail.com> CC: Rolf Offermanns <rof@sysgo.de> CC: Stefan Roese <sr@denx.de> CC: Sascha Hauer <saschahauer@web.de> CC: TsiChung Liew <Tsi-Chung.Liew@freescale.com> CC: Greg Ungerer <greg.ungerer@opengear.com> CC: Xue Ligong <lgxue@hotmail.com> CC: Masami Komiya <mkomiya@sonare.it> CC: Curt Brune <curt@cucy.com> CC: Michal SIMEK <monstr@monstr.eu>
354 lines
10 KiB
C
354 lines
10 KiB
C
/******************************************************************************
|
|
*
|
|
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
|
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
|
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
|
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
|
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
|
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
|
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
|
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
|
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
|
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
|
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
|
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* (C) Copyright 2007-2008 Michal Simek
|
|
* Michal SIMEK <monstr@monstr.eu>
|
|
*
|
|
* (c) Copyright 2003 Xilinx Inc.
|
|
* All rights reserved.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include <common.h>
|
|
#include <net.h>
|
|
#include <config.h>
|
|
#include <asm/io.h>
|
|
|
|
#undef 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 u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
|
|
|
|
/* hardcoded MAC address for the Xilinx EMAC Core when env is nowhere*/
|
|
#ifdef CONFIG_ENV_IS_NOWHERE
|
|
static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 };
|
|
#else
|
|
static u8 emacaddr[ENET_ADDR_LENGTH];
|
|
#endif
|
|
|
|
void xemaclite_alignedread (u32 * srcptr, void *destptr, unsigned bytecount)
|
|
{
|
|
unsigned int i;
|
|
u32 alignbuffer;
|
|
u32 *to32ptr;
|
|
u32 *from32ptr;
|
|
u8 *to8ptr;
|
|
u8 *from8ptr;
|
|
|
|
from32ptr = (u32 *) srcptr;
|
|
|
|
/* Word aligned buffer, no correction needed. */
|
|
to32ptr = (u32 *) destptr;
|
|
while (bytecount > 3) {
|
|
*to32ptr++ = *from32ptr++;
|
|
bytecount -= 4;
|
|
}
|
|
to8ptr = (u8 *) to32ptr;
|
|
|
|
alignbuffer = *from32ptr++;
|
|
from8ptr = (u8 *) & alignbuffer;
|
|
|
|
for (i = 0; i < bytecount; i++) {
|
|
*to8ptr++ = *from8ptr++;
|
|
}
|
|
}
|
|
|
|
void xemaclite_alignedwrite (void *srcptr, u32 destptr, unsigned bytecount)
|
|
{
|
|
unsigned i;
|
|
u32 alignbuffer;
|
|
u32 *to32ptr = (u32 *) destptr;
|
|
u32 *from32ptr;
|
|
u8 *to8ptr;
|
|
u8 *from8ptr;
|
|
|
|
from32ptr = (u32 *) srcptr;
|
|
while (bytecount > 3) {
|
|
|
|
*to32ptr++ = *from32ptr++;
|
|
bytecount -= 4;
|
|
}
|
|
|
|
alignbuffer = 0;
|
|
to8ptr = (u8 *) & alignbuffer;
|
|
from8ptr = (u8 *) from32ptr;
|
|
|
|
for (i = 0; i < bytecount; i++) {
|
|
*to8ptr++ = *from8ptr++;
|
|
}
|
|
|
|
*to32ptr++ = alignbuffer;
|
|
}
|
|
|
|
void eth_halt (void)
|
|
{
|
|
debug ("eth_halt\n");
|
|
}
|
|
|
|
int eth_init (bd_t * bis)
|
|
{
|
|
uchar enetaddr[6];
|
|
|
|
debug ("EmacLite Initialization Started\n");
|
|
memset (&emaclite, 0, sizeof (xemaclite));
|
|
emaclite.baseaddress = XILINX_EMACLITE_BASEADDR;
|
|
|
|
if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
|
|
memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
|
|
eth_setenv_enetaddr("ethaddr", enetaddr);
|
|
}
|
|
|
|
/*
|
|
* TX - TX_PING & TX_PONG initialization
|
|
*/
|
|
/* Restart PING TX */
|
|
out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
|
|
/* Copy MAC address */
|
|
xemaclite_alignedwrite (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 CONFIG_XILINX_EMACLITE_TX_PING_PONG
|
|
/* The same operation with PONG TX */
|
|
out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
|
|
xemaclite_alignedwrite (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 CONFIG_XILINX_EMACLITE_RX_PING_PONG
|
|
out_be32 (emaclite.baseaddress + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET,
|
|
XEL_RSR_RECV_IE_MASK);
|
|
#endif
|
|
|
|
debug ("EmacLite Initialization complete\n");
|
|
return 0;
|
|
}
|
|
|
|
int xemaclite_txbufferavailable (xemaclite * instanceptr)
|
|
{
|
|
u32 reg;
|
|
u32 txpingbusy;
|
|
u32 txpongbusy;
|
|
/*
|
|
* Read the other buffer register
|
|
* and determine if the other buffer is available
|
|
*/
|
|
reg = in_be32 (instanceptr->baseaddress +
|
|
instanceptr->nexttxbuffertouse + 0);
|
|
txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
|
|
XEL_TSR_XMIT_BUSY_MASK);
|
|
|
|
reg = in_be32 (instanceptr->baseaddress +
|
|
(instanceptr->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0);
|
|
txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
|
|
XEL_TSR_XMIT_BUSY_MASK);
|
|
|
|
return (!(txpingbusy && txpongbusy));
|
|
}
|
|
|
|
int eth_send (volatile void *ptr, int len) {
|
|
|
|
unsigned int reg;
|
|
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 CONFIG_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 */
|
|
reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
|
|
if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
|
|
&& ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
|
|
& XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
|
|
|
|
#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
|
|
emaclite.nexttxbuffertouse ^= XEL_BUFFER_OFFSET;
|
|
#endif
|
|
debug ("Send packet from 0x%x\n", baseaddress);
|
|
/* Write the frame to the buffer */
|
|
xemaclite_alignedwrite ((void *) ptr, baseaddress, len);
|
|
out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
|
|
(XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
|
|
reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
|
|
reg |= XEL_TSR_XMIT_BUSY_MASK;
|
|
if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) {
|
|
reg |= XEL_TSR_XMIT_ACTIVE_MASK;
|
|
}
|
|
out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
|
|
return 1;
|
|
}
|
|
#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
|
|
/* Switch to second buffer */
|
|
baseaddress ^= XEL_BUFFER_OFFSET;
|
|
/* Determine if the expected buffer address is empty */
|
|
reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
|
|
if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
|
|
&& ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
|
|
& XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
|
|
debug ("Send packet from 0x%x\n", baseaddress);
|
|
/* Write the frame to the buffer */
|
|
xemaclite_alignedwrite ((void *) ptr, baseaddress, len);
|
|
out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
|
|
(XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
|
|
reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
|
|
reg |= XEL_TSR_XMIT_BUSY_MASK;
|
|
if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) {
|
|
reg |= XEL_TSR_XMIT_ACTIVE_MASK;
|
|
}
|
|
out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
|
|
return 1;
|
|
}
|
|
#endif
|
|
puts ("Error while sending frame\n");
|
|
return 0;
|
|
}
|
|
|
|
int eth_rx (void)
|
|
{
|
|
unsigned int length;
|
|
unsigned int reg;
|
|
unsigned int baseaddress;
|
|
|
|
baseaddress = emaclite.baseaddress + emaclite.nextrxbuffertouse;
|
|
reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
|
|
debug ("Testing data at address 0x%x\n", baseaddress);
|
|
if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
|
|
#ifdef CONFIG_XILINX_EMACLITE_RX_PING_PONG
|
|
emaclite.nextrxbuffertouse ^= XEL_BUFFER_OFFSET;
|
|
#endif
|
|
} else {
|
|
#ifndef CONFIG_XILINX_EMACLITE_RX_PING_PONG
|
|
debug ("No data was available - address 0x%x\n", baseaddress);
|
|
return 0;
|
|
#else
|
|
baseaddress ^= XEL_BUFFER_OFFSET;
|
|
reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
|
|
if ((reg & XEL_RSR_RECV_DONE_MASK) !=
|
|
XEL_RSR_RECV_DONE_MASK) {
|
|
debug ("No data was available - address 0x%x\n",
|
|
baseaddress);
|
|
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 */
|
|
debug ("ARP Packet\n");
|
|
break;
|
|
case 0x800:
|
|
length = 14 + 14 +
|
|
(((in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0x10)) &
|
|
0xFFFF0000) >> 16); /* FIXME size of IP packet */
|
|
debug ("IP Packet\n");
|
|
break;
|
|
default:
|
|
debug ("Other Packet\n");
|
|
length = ENET_MAX_MTU;
|
|
break;
|
|
}
|
|
|
|
xemaclite_alignedread ((u32 *) (baseaddress + XEL_RXBUFF_OFFSET),
|
|
etherrxbuff, length);
|
|
|
|
/* Acknowledge the frame */
|
|
reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
|
|
reg &= ~XEL_RSR_RECV_DONE_MASK;
|
|
out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
|
|
|
|
debug ("Packet receive from 0x%x, length %dB\n", baseaddress, length);
|
|
NetReceive ((uchar *) etherrxbuff, length);
|
|
return 1;
|
|
|
|
}
|