All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <monstr@seznam.cz>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH 2/4] emaclite
Date: Sun, 5 Aug 2007 20:56:28 +0200	[thread overview]
Message-ID: <001801c7d792$54b4ca80$0500a8c0@monstrone> (raw)
In-Reply-To: 0a6b01c7d77e$905d8e50$0500a8c0@monstrone

Signed-off-by: Michal Simek <monstr@monstr.eu>

Emaclite driver for Microblaze

diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index e69de29..99e7035 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -0,0 +1,378 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * 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 <common.h>
+#include <net.h>
+#include <config.h>
+#include <asm/io.h>
+
+#ifdef XILINX_EMACLITE_BASEADDR
+
+#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 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

  parent reply	other threads:[~2007-08-05 18:56 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-05 13:38 [U-Boot-Users] Microblaze: PULL request Michal Simek
2007-08-05 14:47 ` Grant Likely
2007-08-05 14:52   ` Grant Likely
2007-08-05 15:13   ` Michal Simek
2007-08-05 16:12     ` Grant Likely
2007-08-05 16:34       ` Michal Simek
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 1/4] emac Michal Simek
2007-08-05 20:07           ` Wolfgang Denk
2007-08-06 20:11             ` Michal Simek
2007-08-05 22:28           ` Grant Likely
2007-08-05 18:56         ` Michal Simek [this message]
2007-08-05 20:05           ` [U-Boot-Users] [PATCH 2/4] emaclite Wolfgang Denk
2007-08-06 20:00             ` Michal Simek
2007-08-06 20:54               ` Wolfgang Denk
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 3/4] microblaze changes Michal Simek
2007-08-05 20:08           ` Wolfgang Denk
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 4/4] romfs Michal Simek
2007-08-05 20:38           ` Wolfgang Denk
2007-08-05 20:01         ` [U-Boot-Users] Microblaze: PULL request Wolfgang Denk
2007-08-05 22:25           ` Grant Likely
2007-08-05 22:27             ` Wolfgang Denk
2007-08-05 22:32               ` Grant Likely
2007-08-06 17:03                 ` Michal Simek
2007-08-05 19:59     ` Wolfgang Denk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='001801c7d792$54b4ca80$0500a8c0@monstrone' \
    --to=monstr@seznam.cz \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.