From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ben Warren Date: Sun, 04 Apr 2010 23:19:14 -0700 Subject: [U-Boot] [PATCH v4 tabify] net: add altera triple speeds ethernet mac driver In-Reply-To: <1269765146-21288-1-git-send-email-thomas@wytron.com.tw> References: <1269412366-9206-1-git-send-email-thomas@wytron.com.tw> <1269765146-21288-1-git-send-email-thomas@wytron.com.tw> Message-ID: <4BB980E2.2040901@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Thomas, On 3/28/2010 1:32 AM, Thomas Chou wrote: > This driver supports the Altera triple speeds 10/100/1000 ethernet > mac. > > Signed-off-by: Thomas Chou > --- > drivers/net/Makefile | 1 + > drivers/net/altera_tse.c | 978 ++++++++++++++++++++++++++++++++++++++++++++++ > drivers/net/altera_tse.h | 512 ++++++++++++++++++++++++ > include/netdev.h | 1 + > 4 files changed, 1492 insertions(+), 0 deletions(-) > create mode 100644 drivers/net/altera_tse.c > create mode 100644 drivers/net/altera_tse.h > > diff --git a/drivers/net/Makefile b/drivers/net/Makefile > index 0e68e52..b75c02f 100644 > --- a/drivers/net/Makefile > +++ b/drivers/net/Makefile > @@ -27,6 +27,7 @@ LIB := $(obj)libnet.a > > COBJS-$(CONFIG_DRIVER_3C589) += 3c589.o > COBJS-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o > +COBJS-$(CONFIG_ALTERA_TSE) += altera_tse.o > COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o > COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o > COBJS-$(CONFIG_BCM570x) += bcm570x.o bcm570x_autoneg.o 5701rls.o > diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c > new file mode 100644 > index 0000000..7a2cb66 > --- /dev/null > +++ b/drivers/net/altera_tse.c > @@ -0,0 +1,978 @@ > +/* > + * Altera 10/100/1000 triple speed ethernet mac driver > + * > + * Copyright (C) 2008 Altera Corporation. > + * Copyright (C) 2010 Thomas Chou > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "altera_tse.h" > + > +static int tse_eth_send(struct eth_device *dev, volatile void *packet, > + int length); > +static int tse_eth_rx(struct eth_device *dev); > +static void tse_eth_halt(struct eth_device *dev); > +static void tse_eth_reset(struct eth_device *dev); > +static int tse_eth_init(struct eth_device *dev, bd_t *bd); > + > +static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum); > +static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, > + unsigned int value); > Are these prototypes really needed? If so, please re-order the code so they're not. > +#define read_phy_reg(priv, regnum) tse_mdio_read(priv, regnum) > +#define write_phy_reg(priv, regnum, value) tse_mdio_write(priv, regnum, value) > +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)&& !defined(BITBANGMII) > +static int altera_tse_miiphy_write(char *devname, unsigned char addr, > + unsigned char reg, unsigned short value); > +static int altera_tse_miiphy_read(char *devname, unsigned char addr, > + unsigned char reg, unsigned short *value); > +#endif > + > +static int tse_adjust_link(struct altera_tse_priv *priv); > + > +static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv); > +static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv); > +static uint mii_m88e1111s_setmode_sr(uint mii_reg, > + struct altera_tse_priv *priv); > +static uint mii_m88e1111s_setmode_cr(uint mii_reg, > + struct altera_tse_priv *priv); > +static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv); > + > +static struct phy_info *get_phy_info(struct eth_device *dev); > +static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd); > +static int init_phy(struct eth_device *dev); > + > +/* sgdma debug - print descriptor */ > +static void alt_sgdma_print_desc(volatile struct alt_sgdma_descriptor *desc) > +{ > + debug("SGDMA DEBUG :\n"); > + debug("desc->source : 0x%x \n", (unsigned int)desc->source); > + debug("desc->destination : 0x%x \n", (unsigned int)desc->destination); > + debug("desc->next : 0x%x \n", (unsigned int)desc->next); > + debug("desc->source_pad : 0x%x \n", (unsigned int)desc->source_pad); > + debug("desc->destination_pad : 0x%x \n", > + (unsigned int)desc->destination_pad); > + debug("desc->next_pad : 0x%x \n", (unsigned int)desc->next_pad); > + debug("desc->bytes_to_transfer : 0x%x \n", > + (unsigned int)desc->bytes_to_transfer); > + debug("desc->actual_bytes_transferred : 0x%x \n", > + (unsigned int)desc->actual_bytes_transferred); > + debug("desc->descriptor_status : 0x%x \n", > + (unsigned int)desc->descriptor_status); > + debug("desc->descriptor_control : 0x%x \n", > + (unsigned int)desc->descriptor_control); > +} > + > +/* This is a generic routine that the SGDMA mode-specific routines > + * call to populate a descriptor. > + * arg1 :pointer to first SGDMA descriptor. > + * arg2 :pointer to next SGDMA descriptor. > + * arg3 :Address to where data to be written. > + * arg4 :Address from where data to be read. > + * arg5 :no of byte to transaction. > + * arg6 :variable indicating to generate start of packet or not > + * arg7 :read fixed > + * arg8 :write fixed > + * arg9 :read burst > + * arg10 :write burst > + * arg11 :atlantic_channel number > + */ > 11 arguments??? Seriously??? > +static void alt_sgdma_construct_descriptor_burst( > + volatile struct alt_sgdma_descriptor *desc, > + volatile struct alt_sgdma_descriptor *next, > + unsigned int *read_addr, > + unsigned int *write_addr, > + unsigned short length_or_eop, > + int generate_eop, > + int read_fixed, > + int write_fixed_or_sop, > + int read_burst, > + int write_burst, > + unsigned char atlantic_channel) > +{ > + /* > + * Mark the "next" descriptor as "not" owned by hardware. This prevents > + * The SGDMA controller from continuing to process the chain. This is > + * done as a single IO write to bypass cache, without flushing > + * the entire descriptor, since only the 8-bit descriptor status must > + * be flushed. > + */ > + if (!next) > + debug("Next descriptor not defined!!\n"); > + > + next->descriptor_control = (next->descriptor_control& > + ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK); > + > + desc->source = (unsigned int *)((unsigned int)read_addr& 0x1FFFFFFF); > + desc->destination = > + (unsigned int *)((unsigned int)write_addr& 0x1FFFFFFF); > + desc->next = (unsigned int *)((unsigned int)next& 0x1FFFFFFF); > + desc->source_pad = 0x0; > + desc->destination_pad = 0x0; > + desc->next_pad = 0x0; > + desc->bytes_to_transfer = length_or_eop; > + desc->actual_bytes_transferred = 0; > + desc->descriptor_status = 0x0; > + > + /* SGDMA burst not currently supported */ > + desc->read_burst = 0; > + desc->write_burst = 0; > + > + /* > + * Set the descriptor control block as follows: > + * - Set "owned by hardware" bit > + * - Optionally set "generate EOP" bit > + * - Optionally set the "read from fixed address" bit > + * - Optionally set the "write to fixed address bit (which serves > + * serves as a "generate SOP" control bit in memory-to-stream mode). > + * - Set the 4-bit atlantic channel, if specified > + * > + * Note that this step is performed after all other descriptor information > + * has been filled out so that, if the controller already happens to be > + * pointing at this descriptor, it will not run (via the "owned by > + * hardware" bit) until all other descriptor information has been set up. > + */ > + > + desc->descriptor_control = > + ((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) | > + (generate_eop ? > + ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) | > + (read_fixed ? > + ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) | > + (write_fixed_or_sop ? > + ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) | > + (atlantic_channel ? ((atlantic_channel& 0x0F)<< 3) : 0) > + ); > +} > + > +static int alt_sgdma_do_sync_transfer(volatile struct alt_sgdma_registers *dev, > + volatile struct alt_sgdma_descriptor *desc) > +{ > + unsigned int status; > + int counter = 0; > + > + /* Wait for any pending transfers to complete */ > + alt_sgdma_print_desc(desc); > + status = dev->status; > + > + counter = 0; > + while (dev->status& ALT_SGDMA_STATUS_BUSY_MSK) { > + if (counter++> ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + break; > + } > + > + if (counter>= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + debug("Timeout waiting sgdma in do sync!\n"); > + > + /* > + * Clear any (previous) status register information > + * that might occlude our error checking later. > + */ > + dev->status = 0xFF; > + > + /* Point the controller at the descriptor */ > + dev->next_descriptor_pointer = (unsigned int)desc& 0x1FFFFFFF; > + debug("next desc in sgdma 0x%x\n", > + (unsigned int)dev->next_descriptor_pointer); > + > + /* > + * Set up SGDMA controller to: > + * - Disable interrupt generation > + * - Run once a valid descriptor is written to controller > + * - Stop on an error with any particular descriptor > + */ > + dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | > + ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); > + > + /* Wait for the descriptor (chain) to complete */ > + status = dev->status; > + debug("wait for sgdma...."); > + while (dev->status& ALT_SGDMA_STATUS_BUSY_MSK) > + ; > + debug("done\n"); > + > + /* Clear Run */ > + dev->control = (dev->control& (~ALT_SGDMA_CONTROL_RUN_MSK)); > + > + /* Get& clear status register contents */ > + status = dev->status; > + dev->status = 0xFF; > + > + /* we really should check if the transfer completes properly */ > + debug("tx sgdma status = 0x%x", status); > + return 0; > +} > + > +static int alt_sgdma_do_async_transfer(volatile struct alt_sgdma_registers *dev, > + volatile struct alt_sgdma_descriptor *desc) > +{ > + unsigned int status; > + int counter = 0; > + > + /* Wait for any pending transfers to complete */ > + alt_sgdma_print_desc(desc); > + status = dev->status; > + > + counter = 0; > + while (dev->status& ALT_SGDMA_STATUS_BUSY_MSK) { > + if (counter++> ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + break; > + } > + > + if (counter>= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + debug("Timeout waiting sgdma in do async!\n"); > + > + /* > + * Clear any (previous) status register information > + * that might occlude our error checking later. > + */ > + dev->status = 0xFF; > + > + /* Point the controller at the descriptor */ > + dev->next_descriptor_pointer = (unsigned int)desc& 0x1FFFFFFF; > + > + /* > + * Set up SGDMA controller to: > + * - Disable interrupt generation > + * - Run once a valid descriptor is written to controller > + * - Stop on an error with any particular descriptor > + */ > + dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | > + ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); > + > + /* we really should check if the transfer completes properly */ > + return 0; > +} > + > +/* TSE init code */ > +int altera_tse_init(bd_t *bis, int num_tses) > The naming convention that we use is xxx_initialize(), or xxx_register(), although I prefer the former. If you're not using *bis, don't pass it in. > +{ > + struct altera_tse_priv *priv; > + struct eth_device *dev; > + struct alt_sgdma_descriptor *rx_desc; > + struct alt_sgdma_descriptor *tx_desc; > + int num; > + unsigned long dma_handle; > + > + puts("Altera TSE\n"); > + > + for (num = 0; num< num_tses; num++) { > You don't use the 'num' variable. As such, this driver doesn't support more than one instance. Once you add true multi-instance support, the preferred way to do this is to call this function for each instance, passing in the appropriate addressing information. > + dev = (struct eth_device *)malloc(sizeof *dev); > + > + if (NULL == dev) > + return 0; > + > + memset(dev, 0, sizeof *dev); > + > + priv = malloc(sizeof(*priv)); > + > + if (!priv) { > + free(dev); > + return 0; > + } > +#if CONFIG_SYS_ALTERA_TSE_0_HAS_DESC_MEM > + tx_desc = (void *)CONFIG_SYS_ALTERA_TSE_0_DESC_MEM_BASE; > +#else > + tx_desc = > + dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), > + &dma_handle); > +#endif > + rx_desc = tx_desc + 2; > + debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc); > + debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc); > + > + if (!tx_desc) { > + free(priv); > + free(dev); > + return 0; > + } > + memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1)); > + memset(tx_desc, 0, (sizeof *tx_desc) * 2); > + > + /* initialize tse priv */ > + SET_ALTERA_TSE_INFO(priv, 0); > + priv->rx_desc = rx_desc; > + priv->tx_desc = tx_desc; > + > + /* init eth structure */ > + sprintf(dev->name, priv->devname); > + dev->iobase = 0; > + dev->priv = priv; > + dev->init = tse_eth_init; > + dev->halt = tse_eth_halt; > + dev->send = tse_eth_send; > + dev->recv = tse_eth_rx; > + > + eth_register(dev); > + > +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)&& !defined(BITBANGMII) > + miiphy_register(dev->name, altera_tse_miiphy_read, > + altera_tse_miiphy_write); > +#endif > + > + init_phy(dev); > > + } > + > + return num_tses; > This return value is meaningless, as mentioned above. > +} > + > +/* u-boot interface */ > +static int tse_adjust_link(struct altera_tse_priv *priv) > +{ > + unsigned int refvar; > + alt_tse_mac *mac_dev = priv->mac_dev; > + > + refvar = mac_dev->command_config.image; > + > + if (!(priv->duplexity)) > + refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; > + else > + refvar&= ~ALTERA_TSE_CMD_HD_ENA_MSK; > + > + switch (priv->speed) { > + case 1000: > + refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; > + refvar&= ~ALTERA_TSE_CMD_ENA_10_MSK; > + break; > + case 100: > + refvar&= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; > + refvar&= ~ALTERA_TSE_CMD_ENA_10_MSK; > + break; > + case 10: > + refvar&= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; > + refvar |= ALTERA_TSE_CMD_ENA_10_MSK; > + break; > + } > + mac_dev->command_config.image = refvar; > + > + return 0; > +} > + > +static int tse_eth_send(struct eth_device *dev, > + volatile void *packet, int length) > +{ > + struct altera_tse_priv *priv = dev->priv; > + struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; > + volatile struct alt_sgdma_descriptor *tx_desc = > + (volatile struct alt_sgdma_descriptor *)priv->tx_desc; > + > + volatile struct alt_sgdma_descriptor *tx_desc_cur = > + (volatile struct alt_sgdma_descriptor *)&tx_desc[0]; > + > + flush_dcache((unsigned long)packet, length); > + alt_sgdma_construct_descriptor_burst( > + (volatile struct alt_sgdma_descriptor *)&tx_desc[0], > + (volatile struct alt_sgdma_descriptor *)&tx_desc[1], > + (unsigned int *)packet, /* read addr */ > + (unsigned int *)0, > + length, /* length or EOP ,will change for each tx */ > + 0x1, /* gen eop */ > + 0x0, /* read fixed */ > + 0x1, /* write fixed or sop */ > + 0x0, /* read burst */ > + 0x0, /* write burst */ > + 0x0 /* channel */ > + ); > + debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length); > + > + /* send the packet */ > + debug("sending packet\n"); > + alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur); > + debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred); > + return tx_desc_cur->actual_bytes_transferred; > +} > + > +static int tse_eth_rx(struct eth_device *dev) > +{ > + int packet_length = 0; > + struct altera_tse_priv *priv = dev->priv; > + volatile struct alt_sgdma_descriptor *rx_desc = > + (volatile struct alt_sgdma_descriptor *)priv->rx_desc; > + volatile struct alt_sgdma_descriptor *rx_desc_cur =&rx_desc[0]; > + debug("eth_rx: sgdma status = 0x%x\n", rx_sgdma->status); > + debug("eth_rx: sgdma control = 0x%x\n", rx_sgdma->control); > + debug("mac rx errors : %d\n", mac_dev->ifInErrors); > + > + if (rx_desc_cur->descriptor_status& > + ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { > + debug("got packet\n"); > + packet_length = rx_desc->actual_bytes_transferred; > + NetReceive(NetRxPackets[0], packet_length); > + > + /* start descriptor again */ > + flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); > + alt_sgdma_construct_descriptor_burst( > + (volatile struct alt_sgdma_descriptor *)&rx_desc[0], > + (volatile struct alt_sgdma_descriptor *)&rx_desc[1], > + (unsigned int)0x0, /* read addr */ > + (unsigned int *)NetRxPackets[0], > + 0x0, /* length or EOP */ > + 0x0, /* gen eop */ > + 0x0, /* read fixed */ > + 0x0, /* write fixed or sop */ > + 0x0, /* read burst */ > + 0x0, /* write burst */ > + 0x0 /* channel */ > + ); > + > + /* setup the sgdma */ > + alt_sgdma_do_async_transfer(priv->sgdma_rx,&rx_desc[0]); > + } > + > + return -1; > +} > + > +static void tse_eth_halt(struct eth_device *dev) > +{ > + /* don't do anything! */ > + /* this gets called after each uboot */ > + /* network command. don't need to reset the thing all of the time */ > +} > + > +static void tse_eth_reset(struct eth_device *dev) > +{ > + /* stop sgdmas, disable tse receive */ > + struct altera_tse_priv *priv = dev->priv; > + alt_tse_mac *mac_dev = priv->mac_dev; > + struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; > + struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; > + int counter; > + volatile struct alt_sgdma_descriptor *rx_desc = > + (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0]; > + > + /* clear rx desc& wait for sgdma to complete */ > + rx_desc->descriptor_control = 0; > + rx_sgdma->control = 0; > + counter = 0; > + while (rx_sgdma->status& ALT_SGDMA_STATUS_BUSY_MSK) { > + if (counter++> ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + break; > + } > + > + if (counter>= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { > + debug("Timeout waiting for rx sgdma!\n"); > + rx_sgdma->control&= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; > + rx_sgdma->control&= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; > + } > + > + counter = 0; > + tx_sgdma->control = 0; > + while (tx_sgdma->status& ALT_SGDMA_STATUS_BUSY_MSK) { > + if (counter++> ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) > + break; > + } > + > + if (counter>= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { > + debug("Timeout waiting for tx sgdma!\n"); > + tx_sgdma->control&= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; > + tx_sgdma->control&= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; > + } > + /* reset the mac */ > + mac_dev->command_config.bits.transmit_enable = 1; > + mac_dev->command_config.bits.receive_enable = 1; > + mac_dev->command_config.bits.software_reset = 1; > + > + counter = 0; > + while (mac_dev->command_config.bits.software_reset) { > + if (counter++> ALT_TSE_SW_RESET_WATCHDOG_CNTR) > + break; > + } > + > + if (counter>= ALT_TSE_SW_RESET_WATCHDOG_CNTR) > + debug("TSEMAC SW reset bit never cleared!\n"); > +} > + > +static int tse_eth_init(struct eth_device *dev, bd_t * bd) > +{ > + int dat; > + struct altera_tse_priv *priv = dev->priv; > + alt_tse_mac *mac_dev = priv->mac_dev; > + volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; > + volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; > + volatile struct alt_sgdma_descriptor *rx_desc_cur = > + (volatile struct alt_sgdma_descriptor *)&rx_desc[0]; > + > + /* stop controller */ > + debug("Reseting TSE& SGDMAs\n"); > + tse_eth_reset(dev); > + > + /* start the phy */ > + debug("Configuring PHY\n"); > + phy_run_commands(priv, priv->phyinfo->startup); > + > + /* need to create sgdma */ > + debug("Configuring tx desc\n"); > + alt_sgdma_construct_descriptor_burst( > + (volatile struct alt_sgdma_descriptor *)&tx_desc[0], > + (volatile struct alt_sgdma_descriptor *)&tx_desc[1], > + (unsigned int *)NULL, /* read addr */ > + (unsigned int *)0, > + 0, /* length or EOP ,will change for each tx */ > + 0x1, /* gen eop */ > + 0x0, /* read fixed */ > + 0x1, /* write fixed or sop */ > + 0x0, /* read burst */ > + 0x0, /* write burst */ > + 0x0 /* channel */ > + ); > + debug("Configuring rx desc\n"); > + flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); > + alt_sgdma_construct_descriptor_burst( > + (volatile struct alt_sgdma_descriptor *)&rx_desc[0], > + (volatile struct alt_sgdma_descriptor *)&rx_desc[1], > + (unsigned int)0x0, /* read addr */ > + (unsigned int *)NetRxPackets[0], > + 0x0, /* length or EOP */ > + 0x0, /* gen eop */ > + 0x0, /* read fixed */ > + 0x0, /* write fixed or sop */ > + 0x0, /* read burst */ > + 0x0, /* write burst */ > + 0x0 /* channel */ > + ); > + /* start rx async transfer */ > + debug("Starting rx sgdma\n"); > + alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur); > + > + /* start TSE */ > + debug("Configuring TSE Mac\n"); > + /* Initialize MAC registers */ > + mac_dev->max_frame_length = PKTSIZE_ALIGN; > + mac_dev->rx_almost_empty_threshold = 8; > + mac_dev->rx_almost_full_threshold = 8; > + mac_dev->tx_almost_empty_threshold = 8; > + mac_dev->tx_almost_full_threshold = 3; > + mac_dev->tx_sel_empty_threshold = > + CONFIG_SYS_ALTERA_TSE_0_TXFIFO_DEPTH - 16; > + mac_dev->tx_sel_full_threshold = 0; > + mac_dev->rx_sel_empty_threshold = > + CONFIG_SYS_ALTERA_TSE_0_RXFIFO_DEPTH - 16; > + mac_dev->rx_sel_full_threshold = 0; > + > + /* NO Shift */ > + mac_dev->rx_cmd_stat.bits.rx_shift16 = 0; > + mac_dev->tx_cmd_stat.bits.tx_shift16 = 0; > + > + /* enable MAC */ > + dat = 0; > + dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; > + > + mac_dev->command_config.image = dat; > + > + /* Set the MAC address */ > + debug("Setting MAC address to 0x%x%x%x%x%x%x\n", > + dev->enetaddr[5], dev->enetaddr[4], > + dev->enetaddr[3], dev->enetaddr[2], > + dev->enetaddr[1], dev->enetaddr[0]); > + mac_dev->mac_addr_0 = ((dev->enetaddr[3])<< 24 | > + (dev->enetaddr[2])<< 16 | > + (dev->enetaddr[1])<< 8 | (dev->enetaddr[0])); > + > + mac_dev->mac_addr_1 = ((dev->enetaddr[5]<< 8 | > + (dev->enetaddr[4]))& 0xFFFF); > + > + /* Set the MAC address */ > + mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0; > + mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1; > + > + /* Set the MAC address */ > + mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0; > + mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1; > + > + /* Set the MAC address */ > + mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0; > + mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1; > + > + /* Set the MAC address */ > + mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0; > + mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1; > + > Please put the MAC address programming code in a separate function, taking a eth_dev * as parameter. It may save you work later. > + /* configure the TSE core */ > + /* -- output clocks, */ > + /* -- and later config stuff for SGMII */ > + if (priv->link) { > + debug("Adjusting TSE to link speed\n"); > + tse_adjust_link(priv); > + } > + > + return priv->link ? 0 : -1; > +} > + > +/* > + * PHY& MDIO code > + * Need to add SGMII stuff > + * > + */ > + > +static struct phy_info phy_info_M88E1111S = { > + 0x01410cc, > + "Marvell 88E1111S", > + 4, > + (struct phy_cmd[]){ /* config */ > + /* Reset and configure the PHY */ > + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, > + {MIIM_88E1111_PHY_EXT_SR, 0x848f, > + &mii_m88e1111s_setmode_sr}, > + /* Delay RGMII TX and RX */ > + {MIIM_88E1111_PHY_EXT_CR, 0x0cd2, > + &mii_m88e1111s_setmode_cr}, > + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, > + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, > + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, > + {MIIM_CONTROL, MIIM_CONTROL_INIT,&mii_cr_init}, > + {miim_end,} > + }, > + (struct phy_cmd[]){ /* startup */ > + /* Status is read once to clear old link state */ > + {MIIM_STATUS, miim_read, NULL}, > + /* Auto-negotiate */ > + {MIIM_STATUS, miim_read,&mii_parse_sr}, > + /* Read the status */ > + {MIIM_88E1011_PHY_STATUS, miim_read, > + &mii_parse_88E1011_psr}, > + {miim_end,} > + }, > + (struct phy_cmd[]){ /* shutdown */ > + {miim_end,} > + }, > +}; > + > +/* a generic flavor. */ > +static struct phy_info phy_info_generic = { > + 0, > + "Unknown/Generic PHY", > + 32, > + (struct phy_cmd[]){ /* config */ > + {PHY_BMCR, PHY_BMCR_RESET, NULL}, > + {PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG, NULL}, > + {miim_end,} > + }, > + (struct phy_cmd[]){ /* startup */ > + {PHY_BMSR, miim_read, NULL}, > + {PHY_BMSR, miim_read,&mii_parse_sr}, > + {miim_end,} > + }, > + (struct phy_cmd[]){ /* shutdown */ > + {miim_end,} > + } > +}; > + > +static struct phy_info *phy_info[] = { > + &phy_info_M88E1111S, > + NULL > +}; > + > + /* Grab the identifier of the device's PHY, and search through > + * all of the known PHYs to see if one matches. If so, return > + * it, if not, return NULL > + */ > +static struct phy_info *get_phy_info(struct eth_device *dev) > +{ > + struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; > + uint phy_reg, phy_ID; > + int i; > + struct phy_info *theInfo = NULL; > + > + /* Grab the bits from PHYIR1, and put them in the upper half */ > + phy_reg = tse_mdio_read(priv, MIIM_PHYIR1); > + phy_ID = (phy_reg& 0xffff)<< 16; > + > + /* Grab the bits from PHYIR2, and put them in the lower half */ > + phy_reg = tse_mdio_read(priv, MIIM_PHYIR2); > + phy_ID |= (phy_reg& 0xffff); > + > + /* loop through all the known PHY types, and find one that */ > + /* matches the ID we read from the PHY. */ > + for (i = 0; phy_info[i]; i++) { > + if (phy_info[i]->id == (phy_ID>> phy_info[i]->shift)) { > + theInfo = phy_info[i]; > + break; > + } > + } > + > + if (theInfo == NULL) { > + theInfo =&phy_info_generic; > + debug("%s: No support for PHY id %x; assuming generic\n", > + dev->name, phy_ID); > + } else > + debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); > + > + return theInfo; > +} > + > +/* Execute the given series of commands on the given device's > + * PHY, running functions as necessary > + */ > +static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd) > +{ > + int i; > + uint result; > + > + for (i = 0; cmd->mii_reg != miim_end; i++) { > + if (cmd->mii_data == miim_read) { > + result = tse_mdio_read(priv, cmd->mii_reg); > + > + if (cmd->funct != NULL) > + (*(cmd->funct)) (result, priv); > + > + } else { > + if (cmd->funct != NULL) > + result = (*(cmd->funct)) (cmd->mii_reg, priv); > + else > + result = cmd->mii_data; > + > + tse_mdio_write(priv, cmd->mii_reg, result); > + > + } > + cmd++; > + } > +} > + > +/* Phy init code */ > +static int init_phy(struct eth_device *dev) > +{ > + struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; > + struct phy_info *curphy; > + > + /* Get the cmd structure corresponding to the attached > + * PHY */ > + curphy = get_phy_info(dev); > + > + if (curphy == NULL) { > + priv->phyinfo = NULL; > + printf("%s: No PHY found\n", dev->name); > + > + return 0; > + } else > + printf("%s found\n", curphy->name); > + priv->phyinfo = curphy; > + > + phy_run_commands(priv, priv->phyinfo->config); > + > + return 1; > +} > + > +/* > + * Also copied from tsec.c > + */ > +/* Parse the status register for link, and then do > + * auto-negotiation > + */ > +static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv) > +{ > + /* > + * Wait if the link is up, and autonegotiation is in progress > + * (ie - we're capable and it's not done) > + */ > + mii_reg = tse_mdio_read(priv, MIIM_STATUS); > + > + if (!(mii_reg& MIIM_STATUS_LINK)&& (mii_reg& PHY_BMSR_AUTN_ABLE) > + && !(mii_reg& PHY_BMSR_AUTN_COMP)) { > + int i = 0; > + > + puts("Waiting for PHY auto negotiation to complete"); > + while (!(mii_reg& PHY_BMSR_AUTN_COMP)) { > + /* > + * Timeout reached ? > + */ > + if (i> PHY_AUTONEGOTIATE_TIMEOUT) { > + puts(" TIMEOUT !\n"); > + priv->link = 0; > + return 0; > + } > + > + if ((i++ % 1000) == 0) > + putc('.'); > + udelay(1000); /* 1 ms */ > + mii_reg = tse_mdio_read(priv, MIIM_STATUS); > + } > + puts(" done\n"); > + priv->link = 1; > + udelay(500000); /* another 500 ms (results in faster booting) */ > + } else { > + if (mii_reg& MIIM_STATUS_LINK) { > + debug("Link is up\n"); > + priv->link = 1; > + } else { > + debug("Link is down\n"); > + priv->link = 0; > + } > + } > + > + return 0; > +} > + > +/* Parse the 88E1011's status register for speed and duplex > + * information > + */ > +static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv) > +{ > + uint speed; > + > + mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); > + > + if ((mii_reg& MIIM_88E1011_PHYSTAT_LINK)&& > + !(mii_reg& MIIM_88E1011_PHYSTAT_SPDDONE)) { > + int i = 0; > + > + puts("Waiting for PHY realtime link"); > + while (!(mii_reg& MIIM_88E1011_PHYSTAT_SPDDONE)) { > + /* Timeout reached ? */ > + if (i> PHY_AUTONEGOTIATE_TIMEOUT) { > + puts(" TIMEOUT !\n"); > + priv->link = 0; > + break; > + } > + > + if ((i++ == 1000) == 0) { > + i = 0; > + puts("."); > + } > + udelay(1000); /* 1 ms */ > + mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); > + } > + puts(" done\n"); > + udelay(500000); /* another 500 ms (results in faster booting) */ > + } else { > + if (mii_reg& MIIM_88E1011_PHYSTAT_LINK) > + priv->link = 1; > + else > + priv->link = 0; > + } > + > + if (mii_reg& MIIM_88E1011_PHYSTAT_DUPLEX) > + priv->duplexity = 1; > + else > + priv->duplexity = 0; > + > + speed = (mii_reg& MIIM_88E1011_PHYSTAT_SPEED); > + > + switch (speed) { > + case MIIM_88E1011_PHYSTAT_GBIT: > + priv->speed = 1000; > + debug("PHY Speed is 1000Mbit\n"); > + break; > + case MIIM_88E1011_PHYSTAT_100: > + debug("PHY Speed is 100Mbit\n"); > + priv->speed = 100; > + break; > + default: > + debug("PHY Speed is 10Mbit\n"); > + priv->speed = 10; > + } > + > + return 0; > +} > + > +static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv) > +{ > + uint mii_data = tse_mdio_read(priv, mii_reg); > + mii_data&= 0xfff0; > + mii_data |= 0xb; > + return mii_data; > +} > + > +static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv) > +{ > + uint mii_data = tse_mdio_read(priv, mii_reg); > + mii_data&= ~0x82; > + mii_data |= 0x82; > + return mii_data; > +} > + > +/* > + * Returns which value to write to the control register. > + * For 10/100, the value is slightly different > + */ > +static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv) > +{ > + return MIIM_CONTROL_INIT; > +} > + > +static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) > +{ > + alt_tse_mac *mac_dev; > + unsigned int *mdio_regs; > + unsigned int data; > + u16 value; > + > + mac_dev = priv->mac_dev; > + > + /* set mdio address */ > + mac_dev->mdio_phy1_addr = priv->phyaddr; > + mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; > + > + /* get the data */ > + data = mdio_regs[regnum]; > + > + value = data& 0xffff; > + > + return value; > +} > + > +static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, > + unsigned int value) > +{ > + alt_tse_mac *mac_dev; > + unsigned int *mdio_regs; > + unsigned int data; > + > + mac_dev = priv->mac_dev; > + > + /* set mdio address */ > + mac_dev->mdio_phy1_addr = priv->phyaddr; > + mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; > + > + /* get the data */ > + data = (unsigned int)value; > + > + mdio_regs[regnum] = data; > + > + return 0; > +} > + > +/* MDIO access to phy */ > +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)&& !defined(BITBANGMII) > +static int altera_tse_miiphy_write(char *devname, unsigned char addr, > + unsigned char reg, unsigned short value) > +{ > + struct eth_device *dev; > + struct altera_tse_priv *priv; > + dev = eth_get_dev_by_name(devname); > + priv = dev->priv; > + > + tse_mdio_write(priv, (uint) reg, (uint) value); > + > + return 0; > +} > + > +static int altera_tse_miiphy_read(char *devname, unsigned char addr, > + unsigned char reg, unsigned short *value) > +{ > + struct eth_device *dev; > + struct altera_tse_priv *priv; > + alt_tse_mac *mac_dev; > + unsigned int *mdio_regs; > + > + dev = eth_get_dev_by_name(devname); > + priv = dev->priv; > + > + mac_dev = priv->mac_dev; > + mac_dev->mdio_phy1_addr = (int)addr; > + mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; > + > + *value = 0xffff& mdio_regs[reg]; > + > + return 0; > + > +} > +#endif > diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h > new file mode 100644 > index 0000000..1b9a956 > --- /dev/null > +++ b/drivers/net/altera_tse.h > @@ -0,0 +1,512 @@ > +/* > + * Altera 10/100/1000 triple speed ethernet mac > + * > + * Copyright (C) 2008 Altera Corporation. > + * Copyright (C) 2010 Thomas Chou > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > +#ifndef _ALTERA_TSE_H_ > +#define _ALTERA_TSE_H_ > + > +#define __packed_1_ __attribute__ ((packed, aligned(1))) > + > +/* PHY Stuff */ > +#define miim_end -2 > +#define miim_read -1 > + > +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */ > + > +#ifndef CONFIG_SYS_TBIPA_VALUE > +#define CONFIG_SYS_TBIPA_VALUE 0x1f > +#endif > +#define MIIMCFG_INIT_VALUE 0x00000003 > +#define MIIMCFG_RESET 0x80000000 > + > +#define MIIMIND_BUSY 0x00000001 > +#define MIIMIND_NOTVALID 0x00000004 > + > +#define MIIM_CONTROL 0x00 > +#define MIIM_CONTROL_RESET 0x00009140 > +#define MIIM_CONTROL_INIT 0x00001140 > +#define MIIM_CONTROL_RESTART 0x00001340 > +#define MIIM_ANEN 0x00001000 > + > +#define MIIM_CR 0x00 > +#define MIIM_CR_RST 0x00008000 > +#define MIIM_CR_INIT 0x00001000 > + > +#define MIIM_STATUS 0x1 > +#define MIIM_STATUS_AN_DONE 0x00000020 > +#define MIIM_STATUS_LINK 0x0004 > +#define PHY_BMSR_AUTN_ABLE 0x0008 > +#define PHY_BMSR_AUTN_COMP 0x0020 > + > +#define MIIM_PHYIR1 0x2 > +#define MIIM_PHYIR2 0x3 > + > +#define MIIM_ANAR 0x4 > +#define MIIM_ANAR_INIT 0x1e1 > + > +#define MIIM_TBI_ANLPBPA 0x5 > +#define MIIM_TBI_ANLPBPA_HALF 0x00000040 > +#define MIIM_TBI_ANLPBPA_FULL 0x00000020 > + > +#define MIIM_TBI_ANEX 0x6 > +#define MIIM_TBI_ANEX_NP 0x00000004 > +#define MIIM_TBI_ANEX_PRX 0x00000002 > + > +#define MIIM_GBIT_CONTROL 0x9 > +#define MIIM_GBIT_CONTROL_INIT 0xe00 > + > +#define MIIM_EXT_PAGE_ACCESS 0x1f > + > +/* 88E1011 PHY Status Register */ > +#define MIIM_88E1011_PHY_STATUS 0x11 > +#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 > +#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 > +#define MIIM_88E1011_PHYSTAT_100 0x4000 > +#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 > +#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800 > +#define MIIM_88E1011_PHYSTAT_LINK 0x0400 > + > +#define MIIM_88E1011_PHY_SCR 0x10 > +#define MIIM_88E1011_PHY_MDI_X_AUTO 0x0060 > + > +#define MIIM_88E1111_PHY_EXT_CR 0x14 > +#define MIIM_88E1111_PHY_EXT_SR 0x1b > + > +/* 88E1111 PHY LED Control Register */ > +#define MIIM_88E1111_PHY_LED_CONTROL 24 > +#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 > +#define MIIM_88E1111_PHY_LED_COMBINE 0x411C > + > +#define MIIM_READ_COMMAND 0x00000001 > + > +/* struct phy_info: a structure which defines attributes for a PHY > + * id will contain a number which represents the PHY. During > + * startup, the driver will poll the PHY to find out what its > + * UID--as defined by registers 2 and 3--is. The 32-bit result > + * gotten from the PHY will be shifted right by "shift" bits to > + * discard any bits which may change based on revision numbers > + * unimportant to functionality > + * > + * The struct phy_cmd entries represent pointers to an arrays of > + * commands which tell the driver what to do to the PHY. > + */ > +struct phy_info { > + uint id; > + char *name; > + uint shift; > + /* Called to configure the PHY, and modify the controller > + * based on the results */ > + struct phy_cmd *config; > + > + /* Called when starting up the controller */ > + struct phy_cmd *startup; > + > + /* Called when bringing down the controller */ > + struct phy_cmd *shutdown; > +}; > + > +/* SGDMA Stuff */ > +#define ALT_SGDMA_STATUS_ERROR_MSK (0x00000001) > +#define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK (0x00000002) > +#define ALT_SGDMA_STATUS_DESC_COMPLETED_MSK (0x00000004) > +#define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK (0x00000008) > +#define ALT_SGDMA_STATUS_BUSY_MSK (0x00000010) > + > +#define ALT_SGDMA_CONTROL_IE_ERROR_MSK (0x00000001) > +#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK (0x00000002) > +#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK (0x00000004) > +#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK (0x00000008) > +#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK (0x00000010) > +#define ALT_SGDMA_CONTROL_RUN_MSK (0x00000020) > +#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK (0x00000040) > +#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK (0x00000080) > +#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK (0x0000FF00) > +#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK (0x00010000) > +#define ALT_SGDMA_CONTROL_PARK_MSK (0x00020000) > +#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK (0x80000000) > + > +#define ALTERA_TSE_SGDMA_INTR_MASK (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \ > + | ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \ > + | ALT_SGDMA_CONTROL_IE_GLOBAL_MSK) > + > +/* > + * Descriptor control bit masks& offsets > + * > + * Note: The control byte physically occupies bits [31:24] in memory. > + * The following bit-offsets are expressed relative to the LSB of > + * the control register bitfield. > + */ > +#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK (0x00000001) > +#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK (0x00000002) > +#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK (0x00000004) > +#define ALT_SGDMA_DESCRIPTOR_CONTROL_ATLANTIC_CHANNEL_MSK (0x00000008) > +#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK (0x00000080) > + > +/* > + * Descriptor status bit masks& offsets > + * > + * Note: The status byte physically occupies bits [23:16] in memory. > + * The following bit-offsets are expressed relative to the LSB of > + * the status register bitfield. > + */ > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK (0x00000001) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK (0x00000002) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK (0x00000004) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK (0x00000008) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK (0x00000010) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK (0x00000020) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK (0x00000040) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK (0x00000080) > +#define ALT_SGDMA_DESCRIPTOR_STATUS_ERROR_MSK (0x0000007F) > + > +/* > + * The SGDMA controller buffer descriptor allocates > + * 64 bits for each address. To support ANSI C, the > + * struct implementing a descriptor places 32-bits > + * of padding directly above each address; each pad must > + * be cleared when initializing a descriptor. > + */ > + > +/* > + * Buffer Descriptor data structure > + * > + */ > +struct alt_sgdma_descriptor { > + unsigned int *source; /* the address of data to be read. */ > + unsigned int source_pad; > + > + unsigned int *destination; /* the address to write data */ > + unsigned int destination_pad; > + > + unsigned int *next; /* the next descriptor in the list. */ > + unsigned int next_pad; > + > + unsigned short bytes_to_transfer; /* the number of bytes to transfer */ > + unsigned char read_burst; > + unsigned char write_burst; > + > + unsigned short actual_bytes_transferred;/* bytes transferred by DMA */ > + unsigned char descriptor_status; > + unsigned char descriptor_control; > + > +} __packed_1_; > + > +/* SG-DMA Control/Status Slave registers map */ > + > +struct alt_sgdma_registers { > + unsigned int status; > + unsigned int status_pad[3]; > + unsigned int control; > + unsigned int control_pad[3]; > + unsigned int next_descriptor_pointer; > + unsigned int descriptor_pad[3]; > +}; > + > +/* TSE Stuff */ > +#define ALTERA_TSE_CMD_TX_ENA_MSK (0x00000001) > +#define ALTERA_TSE_CMD_RX_ENA_MSK (0x00000002) > +#define ALTERA_TSE_CMD_XON_GEN_MSK (0x00000004) > +#define ALTERA_TSE_CMD_ETH_SPEED_MSK (0x00000008) > +#define ALTERA_TSE_CMD_PROMIS_EN_MSK (0x00000010) > +#define ALTERA_TSE_CMD_PAD_EN_MSK (0x00000020) > +#define ALTERA_TSE_CMD_CRC_FWD_MSK (0x00000040) > +#define ALTERA_TSE_CMD_PAUSE_FWD_MSK (0x00000080) > +#define ALTERA_TSE_CMD_PAUSE_IGNORE_MSK (0x00000100) > +#define ALTERA_TSE_CMD_TX_ADDR_INS_MSK (0x00000200) > +#define ALTERA_TSE_CMD_HD_ENA_MSK (0x00000400) > +#define ALTERA_TSE_CMD_EXCESS_COL_MSK (0x00000800) > +#define ALTERA_TSE_CMD_LATE_COL_MSK (0x00001000) > +#define ALTERA_TSE_CMD_SW_RESET_MSK (0x00002000) > +#define ALTERA_TSE_CMD_MHASH_SEL_MSK (0x00004000) > +#define ALTERA_TSE_CMD_LOOPBACK_MSK (0x00008000) > +/* Bits (18:16) = address select */ > +#define ALTERA_TSE_CMD_TX_ADDR_SEL_MSK (0x00070000) > +#define ALTERA_TSE_CMD_MAGIC_ENA_MSK (0x00080000) > +#define ALTERA_TSE_CMD_SLEEP_MSK (0x00100000) > +#define ALTERA_TSE_CMD_WAKEUP_MSK (0x00200000) > +#define ALTERA_TSE_CMD_XOFF_GEN_MSK (0x00400000) > +#define ALTERA_TSE_CMD_CNTL_FRM_ENA_MSK (0x00800000) > +#define ALTERA_TSE_CMD_NO_LENGTH_CHECK_MSK (0x01000000) > +#define ALTERA_TSE_CMD_ENA_10_MSK (0x02000000) > +#define ALTERA_TSE_CMD_RX_ERR_DISC_MSK (0x04000000) > +/* Bits (30..27) reserved */ > +#define ALTERA_TSE_CMD_CNT_RESET_MSK (0x80000000) > + > +#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 (0x00040000) > +#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC (0x00020000) > + > +#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 (0x02000000) > + > +#define ALT_TSE_SW_RESET_WATCHDOG_CNTR 10000 > +#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR 90000000 > + > +#define SET_ALTERA_TSE_INFO(x, num) \ > +{ \ > + sprintf(x->devname, CONFIG_SYS_ALTERA_TSE_##num##_NAME); \ > + x->mac_dev = (alt_tse_mac *) CONFIG_SYS_ALTERA_TSE_##num##_BASE; \ > + x->sgdma_rx = (struct alt_sgdma_registers *) \ > + CONFIG_SYS_ALTERA_TSE_##num##_SGDMA_RX_BASE; \ > + x->sgdma_tx = (struct alt_sgdma_registers *) \ > + CONFIG_SYS_ALTERA_TSE_##num##_SGDMA_TX_BASE; \ > + x->rx_sgdma_irq = (unsigned int) \ > + CONFIG_SYS_ALTERA_TSE_##num##_SGDMA_RX_IRQ; \ > + x->tx_sgdma_irq = (unsigned int) \ > + CONFIG_SYS_ALTERA_TSE_##num##_SGDMA_TX_IRQ; \ > + x->has_descriptor_mem = (unsigned int) \ > + CONFIG_SYS_ALTERA_TSE_##num##_HAS_DESC_MEM; \ > + x->descriptor_mem_base = (unsigned int) \ > + CONFIG_SYS_ALTERA_TSE_##num##_DESC_MEM_BASE; \ > + x->descriptor_mem_size = (unsigned int) \ > + CONFIG_SYS_ALTERA_TSE_##num##_DESC_MEM_SPAN; \ > + x->phyaddr = (unsigned int) CONFIG_SYS_ALTERA_TSE_##num##_PHY_ADDR; \ > + x->flags = (unsigned int) CONFIG_SYS_ALTERA_TSE_##num##_FLAGS; \ > + x->link = (unsigned int) 0; \ > + x->duplexity = (unsigned int) 0; \ > + x->speed = (unsigned int) 0; \ > +} > + > +/* Command_Config Register Bit Definitions */ > + > +typedef volatile union __alt_tse_command_config { > + unsigned int image; > + struct { > + unsigned int > + transmit_enable:1, /* bit 0 */ > + receive_enable:1, /* bit 1 */ > + pause_frame_xon_gen:1, /* bit 2 */ > + ethernet_speed:1, /* bit 3 */ > + promiscuous_enable:1, /* bit 4 */ > + pad_enable:1, /* bit 5 */ > + crc_forward:1, /* bit 6 */ > + pause_frame_forward:1, /* bit 7 */ > + pause_frame_ignore:1, /* bit 8 */ > + set_mac_address_on_tx:1, /* bit 9 */ > + halfduplex_enable:1, /* bit 10 */ > + excessive_collision:1, /* bit 11 */ > + late_collision:1, /* bit 12 */ > + software_reset:1, /* bit 13 */ > + multicast_hash_mode_sel:1, /* bit 14 */ > + loopback_enable:1, /* bit 15 */ > + src_mac_addr_sel_on_tx:3, /* bit 18:16 */ > + magic_packet_detect:1, /* bit 19 */ > + sleep_mode_enable:1, /* bit 20 */ > + wake_up_request:1, /* bit 21 */ > + pause_frame_xoff_gen:1, /* bit 22 */ > + control_frame_enable:1, /* bit 23 */ > + payload_len_chk_disable:1, /* bit 24 */ > + enable_10mbps_intf:1, /* bit 25 */ > + rx_error_discard_enable:1, /* bit 26 */ > + reserved_bits:4, /* bit 30:27 */ > + self_clear_counter_reset:1; /* bit 31 */ > + } __packed_1_ bits; > +} __packed_1_ alt_tse_command_config; > + > +/* Tx_Cmd_Stat Register Bit Definitions */ > + > +typedef volatile union __alt_tse_tx_cmd_stat { > + unsigned int image; > + struct { > + unsigned int reserved_lsbs:17, /* bit 16:0 */ > + omit_crc:1, /* bit 17 */ > + tx_shift16:1, /* bit 18 */ > + reserved_msbs:13; /* bit 31:19 */ > + > + } __packed_1_ bits; > +} alt_tse_tx_cmd_stat; > + > +/* Rx_Cmd_Stat Register Bit Definitions */ > + > +typedef volatile union __alt_tse_rx_cmd_stat { > + unsigned int image; > + struct { > + unsigned int reserved_lsbs:25, /* bit 24:0 */ > + rx_shift16:1, /* bit 25 */ > + reserved_msbs:6; /* bit 31:26 */ > + > + } __packed_1_ bits; > +} alt_tse_rx_cmd_stat; > + > +struct alt_tse_mdio { > + unsigned int control; /*PHY device operation control register */ > + unsigned int status; /*PHY device operation status register */ > + unsigned int phy_id1; /*Bits 31:16 of PHY identifier. */ > + unsigned int phy_id2; /*Bits 15:0 of PHY identifier. */ > + unsigned int auto_negotiation_advertisement; > + unsigned int remote_partner_base_page_ability; > + > + unsigned int reg6; > + unsigned int reg7; > + unsigned int reg8; > + unsigned int reg9; > + unsigned int rega; > + unsigned int regb; > + unsigned int regc; > + unsigned int regd; > + unsigned int rege; > + unsigned int regf; > + unsigned int reg10; > + unsigned int reg11; > + unsigned int reg12; > + unsigned int reg13; > + unsigned int reg14; > + unsigned int reg15; > + unsigned int reg16; > + unsigned int reg17; > + unsigned int reg18; > + unsigned int reg19; > + unsigned int reg1a; > + unsigned int reg1b; > + unsigned int reg1c; > + unsigned int reg1d; > + unsigned int reg1e; > + unsigned int reg1f; > +}; > + > +/* MAC register Space */ > + > +typedef volatile struct { > + unsigned int megacore_revision; > + unsigned int scratch_pad; > + alt_tse_command_config command_config; > + unsigned int mac_addr_0; > + unsigned int mac_addr_1; > + unsigned int max_frame_length; > + unsigned int pause_quanta; > + unsigned int rx_sel_empty_threshold; > + unsigned int rx_sel_full_threshold; > + unsigned int tx_sel_empty_threshold; > + unsigned int tx_sel_full_threshold; > + unsigned int rx_almost_empty_threshold; > + unsigned int rx_almost_full_threshold; > + unsigned int tx_almost_empty_threshold; > + unsigned int tx_almost_full_threshold; > + unsigned int mdio_phy0_addr; > + unsigned int mdio_phy1_addr; > + > + /* only if 100/1000 BaseX PCS, reserved otherwise */ > + unsigned int reservedx44[5]; > + > + unsigned int reg_read_access_status; > + unsigned int min_tx_ipg_length; > + > + /* IEEE 802.3 oEntity Managed Object Support */ > + unsigned int aMACID_1; /*The MAC addresses */ > + unsigned int aMACID_2; > + unsigned int aFramesTransmittedOK; > + unsigned int aFramesReceivedOK; > + unsigned int aFramesCheckSequenceErrors; > + unsigned int aAlignmentErrors; > + unsigned int aOctetsTransmittedOK; > + unsigned int aOctetsReceivedOK; > + > + /* IEEE 802.3 oPausedEntity Managed Object Support */ > + unsigned int aTxPAUSEMACCtrlFrames; > + unsigned int aRxPAUSEMACCtrlFrames; > + > + /* IETF MIB (MIB-II) Object Support */ > + unsigned int ifInErrors; > + unsigned int ifOutErrors; > + unsigned int ifInUcastPkts; > + unsigned int ifInMulticastPkts; > + unsigned int ifInBroadcastPkts; > + unsigned int ifOutDiscards; > + unsigned int ifOutUcastPkts; > + unsigned int ifOutMulticastPkts; > + unsigned int ifOutBroadcastPkts; > + > + /* IETF RMON MIB Object Support */ > + unsigned int etherStatsDropEvent; > + unsigned int etherStatsOctets; > + unsigned int etherStatsPkts; > + unsigned int etherStatsUndersizePkts; > + unsigned int etherStatsOversizePkts; > + unsigned int etherStatsPkts64Octets; > + unsigned int etherStatsPkts65to127Octets; > + unsigned int etherStatsPkts128to255Octets; > + unsigned int etherStatsPkts256to511Octets; > + unsigned int etherStatsPkts512to1023Octets; > + unsigned int etherStatsPkts1024to1518Octets; > + > + unsigned int etherStatsPkts1519toXOctets; > + unsigned int etherStatsJabbers; > + unsigned int etherStatsFragments; > + > + unsigned int reservedxE4; > + > + /*FIFO control register. */ > + alt_tse_tx_cmd_stat tx_cmd_stat; > + alt_tse_rx_cmd_stat rx_cmd_stat; > + > + unsigned int ipaccTxConf; > + unsigned int ipaccRxConf; > + unsigned int ipaccRxStat; > + unsigned int ipaccRxStatSum; > + > + /*Multicast address resolution table */ > + unsigned int hash_table[64]; > + > + /*Registers 0 to 31 within PHY device 0/1 */ > + struct alt_tse_mdio mdio_phy0; > + struct alt_tse_mdio mdio_phy1; > + > + /*4 Supplemental MAC Addresses */ > + unsigned int supp_mac_addr_0_0; > + unsigned int supp_mac_addr_0_1; > + unsigned int supp_mac_addr_1_0; > + unsigned int supp_mac_addr_1_1; > + unsigned int supp_mac_addr_2_0; > + unsigned int supp_mac_addr_2_1; > + unsigned int supp_mac_addr_3_0; > + unsigned int supp_mac_addr_3_1; > + > + unsigned int reservedx320[56]; > +} alt_tse_mac; > + > +struct altera_tse_priv { > + char devname[16]; > + alt_tse_mac *mac_dev; > + struct alt_sgdma_registers *sgdma_rx; > + struct alt_sgdma_registers *sgdma_tx; > + unsigned int rx_sgdma_irq; > + unsigned int tx_sgdma_irq; > + unsigned int has_descriptor_mem; > + unsigned int descriptor_mem_base; > + unsigned int descriptor_mem_size; > + volatile struct alt_sgdma_descriptor *rx_desc; > + volatile struct alt_sgdma_descriptor *tx_desc; > + volatile unsigned char *rx_buf; > + struct phy_info *phyinfo; > + unsigned int phyaddr; > + unsigned int flags; > + unsigned int link; > + unsigned int duplexity; > + unsigned int speed; > +}; > + > +/* Phy stuff continued */ > +/* > + * struct phy_cmd: A command for reading or writing a PHY register > + * > + * mii_reg: The register to read or write > + * > + * mii_data: For writes, the value to put in the register. > + * A value of -1 indicates this is a read. > + * > + * funct: A function pointer which is invoked for each command. > + * For reads, this function will be passed the value read > + * from the PHY, and process it. > + * For writes, the result of this function will be written > + * to the PHY register > + */ > +struct phy_cmd { > + uint mii_reg; > + uint mii_data; > + uint(*funct) (uint mii_reg, struct altera_tse_priv *priv); > +}; > +#endif /* _ALTERA_TSE_H_ */ > diff --git a/include/netdev.h b/include/netdev.h > index f008323..55521f3 100644 > --- a/include/netdev.h > +++ b/include/netdev.h > @@ -42,6 +42,7 @@ int cpu_eth_init(bd_t *bis); > > /* Driver initialization prototypes */ > int au1x00_enet_initialize(bd_t*); > +int altera_tse_init(bd_t *bis, int num_tses); > Alphabetical order, please. > int at91emac_register(bd_t *bis, unsigned long iobase); > int bfin_EMAC_initialize(bd_t *bis); > int cs8900_initialize(u8 dev_num, int base_addr); > regards, Ben