diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/altera_tse.c | 942 | ||||
-rw-r--r-- | drivers/net/altera_tse.h | 494 | ||||
-rw-r--r-- | drivers/net/bfin_mac.c | 28 | ||||
-rw-r--r-- | drivers/net/bfin_mac.h | 3 | ||||
-rw-r--r-- | drivers/net/dm9000x.c | 12 | ||||
-rw-r--r-- | drivers/net/ethoc.c | 511 | ||||
-rw-r--r-- | drivers/net/fec_mxc.c | 8 | ||||
-rw-r--r-- | drivers/net/kirkwood_egiga.c | 24 | ||||
-rw-r--r-- | drivers/net/kirkwood_egiga.h | 2 | ||||
-rw-r--r-- | drivers/net/mcfmii.c | 45 | ||||
-rw-r--r-- | drivers/net/mpc512x_fec.c | 70 | ||||
-rw-r--r-- | drivers/net/mpc5xxx_fec.c | 41 | ||||
-rw-r--r-- | drivers/net/smc911x.c | 2 | ||||
-rw-r--r-- | drivers/net/tsec.c | 3 | ||||
-rw-r--r-- | drivers/qe/uec.c | 6 | ||||
-rw-r--r-- | drivers/qe/uec_phy.c | 47 |
17 files changed, 2078 insertions, 162 deletions
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1ec0ba1..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 @@ -39,6 +40,7 @@ COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o COBJS-$(CONFIG_EP93XX) += ep93xx_eth.o +COBJS-$(CONFIG_ETHOC) += ethoc.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c new file mode 100644 index 0000000..5c0c274 --- /dev/null +++ b/drivers/net/altera_tse.c @@ -0,0 +1,942 @@ +/* + * Altera 10/100/1000 triple speed ethernet mac driver + * + * Copyright (C) 2008 Altera Corporation. + * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * + * 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 <config.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <command.h> +#include <asm/cache.h> +#include <asm/dma-mapping.h> +#include <miiphy.h> +#include "altera_tse.h" + +/* 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 + */ +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 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 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; +} + +/* u-boot interface */ +static int tse_adjust_link(struct altera_tse_priv *priv) +{ + unsigned int refvar; + + refvar = priv->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; + } + priv->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; + volatile 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]; + + 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; + volatile struct alt_tse_mac *mac_dev = priv->mac_dev; + volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; + volatile 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_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) +{ + volatile struct 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) +{ + volatile struct 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; + volatile struct 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 + +/* + * 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; +} + +/* + * 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; + debug("%s: No PHY found\n", dev->name); + + return 0; + } else + debug("%s found\n", curphy->name); + priv->phyinfo = curphy; + + phy_run_commands(priv, priv->phyinfo->config); + + return 1; +} + +static int tse_set_mac_address(struct eth_device *dev) +{ + struct altera_tse_priv *priv = dev->priv; + volatile struct alt_tse_mac *mac_dev = priv->mac_dev; + + debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\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; + return 0; +} + +static int tse_eth_init(struct eth_device *dev, bd_t * bd) +{ + int dat; + struct altera_tse_priv *priv = dev->priv; + volatile struct 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_TX_FIFO - 16; + mac_dev->tx_sel_full_threshold = 0; + mac_dev->rx_sel_empty_threshold = + CONFIG_SYS_ALTERA_TSE_TX_FIFO - 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; + + /* 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; +} + +/* TSE init code */ +int altera_tse_initialize(u8 dev_num, int mac_base, + int sgdma_rx_base, int sgdma_tx_base) +{ + struct altera_tse_priv *priv; + struct eth_device *dev; + struct alt_sgdma_descriptor *rx_desc; + struct alt_sgdma_descriptor *tx_desc; + unsigned long dma_handle; + + 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; + } + tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), + &dma_handle); + 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 */ + priv->mac_dev = (volatile struct alt_tse_mac *)mac_base; + priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base; + priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base; + priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR; + priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS; + priv->rx_desc = rx_desc; + priv->tx_desc = tx_desc; + + /* init eth structure */ + dev->priv = priv; + dev->init = tse_eth_init; + dev->halt = tse_eth_halt; + dev->send = tse_eth_send; + dev->recv = tse_eth_rx; + dev->write_hwaddr = tse_set_mac_address; + sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num); + + 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 1; +} diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h new file mode 100644 index 0000000..c1cb79e --- /dev/null +++ b/drivers/net/altera_tse.h @@ -0,0 +1,494 @@ +/* + * Altera 10/100/1000 triple speed ethernet mac + * + * Copyright (C) 2008 Altera Corporation. + * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * + * 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 + +/* 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 */ + +struct alt_tse_mac { + 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]; +}; + +/* flags: TSE MII modes */ +/* GMII/MII = 0 */ +/* RGMII = 1 */ +/* RGMII_ID = 2 */ +/* RGMII_TXID = 3 */ +/* RGMII_RXID = 4 */ +/* SGMII = 5 */ +struct altera_tse_priv { + char devname[16]; + volatile struct alt_tse_mac *mac_dev; + volatile struct alt_sgdma_registers *sgdma_rx; + volatile 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/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index ec45b63..720e126 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -106,6 +106,7 @@ int bfin_EMAC_initialize(bd_t *bis) dev->halt = bfin_EMAC_halt; dev->send = bfin_EMAC_send; dev->recv = bfin_EMAC_recv; + dev->write_hwaddr = bfin_EMAC_setup_addr; eth_register(dev); @@ -303,6 +304,19 @@ static int bfin_miiphy_init(struct eth_device *dev, int *opmode) return 0; } +static int bfin_EMAC_setup_addr(struct eth_device *dev) +{ + *pEMAC_ADDRLO = + dev->enetaddr[0] | + dev->enetaddr[1] << 8 | + dev->enetaddr[2] << 16 | + dev->enetaddr[3] << 24; + *pEMAC_ADDRHI = + dev->enetaddr[4] | + dev->enetaddr[5] << 8; + return 0; +} + static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) { u32 opmode; @@ -318,7 +332,7 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd) return -1; /* Initialize EMAC address */ - bfin_EMAC_setup_addr(dev->enetaddr); + bfin_EMAC_setup_addr(dev); /* Initialize TX and RX buffer */ for (i = 0; i < PKTBUFSRX; i++) { @@ -376,18 +390,6 @@ static void bfin_EMAC_halt(struct eth_device *dev) } -void bfin_EMAC_setup_addr(uchar *enetaddr) -{ - *pEMAC_ADDRLO = - enetaddr[0] | - enetaddr[1] << 8 | - enetaddr[2] << 16 | - enetaddr[3] << 24; - *pEMAC_ADDRHI = - enetaddr[4] | - enetaddr[5] << 8; -} - ADI_ETHER_BUFFER *SetupRxBuffer(int no) { ADI_ETHER_FRAME_BUFFER *frmbuf; diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index 8f467a3..c731c17 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -60,7 +60,6 @@ static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd); static void bfin_EMAC_halt(struct eth_device *dev); static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, int length); static int bfin_EMAC_recv(struct eth_device *dev); - -void bfin_EMAC_setup_addr(uchar *enetaddr); +static int bfin_EMAC_setup_addr(struct eth_device *dev); #endif diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index a7fef56..f121286 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -117,12 +117,12 @@ static void DM9000_iow(int reg, u8 value); /* DM9000 network board routine ---------------------------- */ -#define DM9000_outb(d,r) ( *(volatile u8 *)r = d ) -#define DM9000_outw(d,r) ( *(volatile u16 *)r = d ) -#define DM9000_outl(d,r) ( *(volatile u32 *)r = d ) -#define DM9000_inb(r) (*(volatile u8 *)r) -#define DM9000_inw(r) (*(volatile u16 *)r) -#define DM9000_inl(r) (*(volatile u32 *)r) +#define DM9000_outb(d,r) outb(d, r) +#define DM9000_outw(d,r) outw(d, r) +#define DM9000_outl(d,r) outl(d, r) +#define DM9000_inb(r) inb(r) +#define DM9000_inw(r) inw(r) +#define DM9000_inl(r) inl(r) #ifdef CONFIG_DM9000_DEBUG static void diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c new file mode 100644 index 0000000..34cc47f --- /dev/null +++ b/drivers/net/ethoc.c @@ -0,0 +1,511 @@ +/* + * Opencore 10/100 ethernet mac driver + * + * Copyright (C) 2007-2008 Avionic Design Development GmbH + * Copyright (C) 2008-2009 Avionic Design GmbH + * Thierry Reding <thierry.reding@avionic-design.de> + * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * + * 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 <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> +#include <asm/io.h> +#include <asm/cache.h> + +/* register offsets */ +#define MODER 0x00 +#define INT_SOURCE 0x04 +#define INT_MASK 0x08 +#define IPGT 0x0c +#define IPGR1 0x10 +#define IPGR2 0x14 +#define PACKETLEN 0x18 +#define COLLCONF 0x1c +#define TX_BD_NUM 0x20 +#define CTRLMODER 0x24 +#define MIIMODER 0x28 +#define MIICOMMAND 0x2c +#define MIIADDRESS 0x30 +#define MIITX_DATA 0x34 +#define MIIRX_DATA 0x38 +#define MIISTATUS 0x3c +#define MAC_ADDR0 0x40 +#define MAC_ADDR1 0x44 +#define ETH_HASH0 0x48 +#define ETH_HASH1 0x4c +#define ETH_TXCTRL 0x50 + +/* mode register */ +#define MODER_RXEN (1 << 0) /* receive enable */ +#define MODER_TXEN (1 << 1) /* transmit enable */ +#define MODER_NOPRE (1 << 2) /* no preamble */ +#define MODER_BRO (1 << 3) /* broadcast address */ +#define MODER_IAM (1 << 4) /* individual address mode */ +#define MODER_PRO (1 << 5) /* promiscuous mode */ +#define MODER_IFG (1 << 6) /* interframe gap for incoming frames */ +#define MODER_LOOP (1 << 7) /* loopback */ +#define MODER_NBO (1 << 8) /* no back-off */ +#define MODER_EDE (1 << 9) /* excess defer enable */ +#define MODER_FULLD (1 << 10) /* full duplex */ +#define MODER_RESET (1 << 11) /* FIXME: reset (undocumented) */ +#define MODER_DCRC (1 << 12) /* delayed CRC enable */ +#define MODER_CRC (1 << 13) /* CRC enable */ +#define MODER_HUGE (1 << 14) /* huge packets enable */ +#define MODER_PAD (1 << 15) /* padding enabled */ +#define MODER_RSM (1 << 16) /* receive small packets */ + +/* interrupt source and mask registers */ +#define INT_MASK_TXF (1 << 0) /* transmit frame */ +#define INT_MASK_TXE (1 << 1) /* transmit error */ +#define INT_MASK_RXF (1 << 2) /* receive frame */ +#define INT_MASK_RXE (1 << 3) /* receive error */ +#define INT_MASK_BUSY (1 << 4) +#define INT_MASK_TXC (1 << 5) /* transmit control frame */ +#define INT_MASK_RXC (1 << 6) /* receive control frame */ + +#define INT_MASK_TX (INT_MASK_TXF | INT_MASK_TXE) +#define INT_MASK_RX (INT_MASK_RXF | INT_MASK_RXE) + +#define INT_MASK_ALL ( \ + INT_MASK_TXF | INT_MASK_TXE | \ + INT_MASK_RXF | INT_MASK_RXE | \ + INT_MASK_TXC | INT_MASK_RXC | \ + INT_MASK_BUSY \ + ) + +/* packet length register */ +#define PACKETLEN_MIN(min) (((min) & 0xffff) << 16) +#define PACKETLEN_MAX(max) (((max) & 0xffff) << 0) +#define PACKETLEN_MIN_MAX(min, max) (PACKETLEN_MIN(min) | \ + PACKETLEN_MAX(max)) + +/* transmit buffer number register */ +#define TX_BD_NUM_VAL(x) (((x) <= 0x80) ? (x) : 0x80) + +/* control module mode register */ +#define CTRLMODER_PASSALL (1 << 0) /* pass all receive frames */ +#define CTRLMODER_RXFLOW (1 << 1) /* receive control flow */ +#define CTRLMODER_TXFLOW (1 << 2) /* transmit control flow */ + +/* MII mode register */ +#define MIIMODER_CLKDIV(x) ((x) & 0xfe) /* needs to be an even number */ +#define MIIMODER_NOPRE (1 << 8) /* no preamble */ + +/* MII command register */ +#define MIICOMMAND_SCAN (1 << 0) /* scan status */ +#define MIICOMMAND_READ (1 << 1) /* read status */ +#define MIICOMMAND_WRITE (1 << 2) /* write control data */ + +/* MII address register */ +#define MIIADDRESS_FIAD(x) (((x) & 0x1f) << 0) +#define MIIADDRESS_RGAD(x) (((x) & 0x1f) << 8) +#define MIIADDRESS_ADDR(phy, reg) (MIIADDRESS_FIAD(phy) | \ + MIIADDRESS_RGAD(reg)) + +/* MII transmit data register */ +#define MIITX_DATA_VAL(x) ((x) & 0xffff) + +/* MII receive data register */ +#define MIIRX_DATA_VAL(x) ((x) & 0xffff) + +/* MII status register */ +#define MIISTATUS_LINKFAIL (1 << 0) +#define MIISTATUS_BUSY (1 << 1) +#define MIISTATUS_INVALID (1 << 2) + +/* TX buffer descriptor */ +#define TX_BD_CS (1 << 0) /* carrier sense lost */ +#define TX_BD_DF (1 << 1) /* defer indication */ +#define TX_BD_LC (1 << 2) /* late collision */ +#define TX_BD_RL (1 << 3) /* retransmission limit */ +#define TX_BD_RETRY_MASK (0x00f0) +#define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4) +#define TX_BD_UR (1 << 8) /* transmitter underrun */ +#define TX_BD_CRC (1 << 11) /* TX CRC enable */ +#define TX_BD_PAD (1 << 12) /* pad enable */ +#define TX_BD_WRAP (1 << 13) +#define TX_BD_IRQ (1 << 14) /* interrupt request enable */ +#define TX_BD_READY (1 << 15) /* TX buffer ready */ +#define TX_BD_LEN(x) (((x) & 0xffff) << 16) +#define TX_BD_LEN_MASK (0xffff << 16) + +#define TX_BD_STATS (TX_BD_CS | TX_BD_DF | TX_BD_LC | \ + TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR) + +/* RX buffer descriptor */ +#define RX_BD_LC (1 << 0) /* late collision */ +#define RX_BD_CRC (1 << 1) /* RX CRC error */ +#define RX_BD_SF (1 << 2) /* short frame */ +#define RX_BD_TL (1 << 3) /* too long */ +#define RX_BD_DN (1 << 4) /* dribble nibble */ +#define RX_BD_IS (1 << 5) /* invalid symbol */ +#define RX_BD_OR (1 << 6) /* receiver overrun */ +#define RX_BD_MISS (1 << 7) +#define RX_BD_CF (1 << 8) /* control frame */ +#define RX_BD_WRAP (1 << 13) +#define RX_BD_IRQ (1 << 14) /* interrupt request enable */ +#define RX_BD_EMPTY (1 << 15) +#define RX_BD_LEN(x) (((x) & 0xffff) << 16) + +#define RX_BD_STATS (RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \ + RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS) + +#define ETHOC_BUFSIZ 1536 +#define ETHOC_ZLEN 64 +#define ETHOC_BD_BASE 0x400 +#define ETHOC_TIMEOUT (HZ / 2) +#define ETHOC_MII_TIMEOUT (1 + (HZ / 5)) + +/** + * struct ethoc - driver-private device structure + * @num_tx: number of send buffers + * @cur_tx: last send buffer written + * @dty_tx: last buffer actually sent + * @num_rx: number of receive buffers + * @cur_rx: current receive buffer + */ +struct ethoc { + u32 num_tx; + u32 cur_tx; + u32 dty_tx; + u32 num_rx; + u32 cur_rx; +}; + +/** + * struct ethoc_bd - buffer descriptor + * @stat: buffer statistics + * @addr: physical memory address + */ +struct ethoc_bd { + u32 stat; + u32 addr; +}; + +static inline u32 ethoc_read(struct eth_device *dev, loff_t offset) +{ + return readl(dev->iobase + offset); +} + +static inline void ethoc_write(struct eth_device *dev, loff_t offset, u32 data) +{ + writel(data, dev->iobase + offset); +} + +static inline void ethoc_read_bd(struct eth_device *dev, int index, + struct ethoc_bd *bd) +{ + loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); + bd->stat = ethoc_read(dev, offset + 0); + bd->addr = ethoc_read(dev, offset + 4); +} + +static inline void ethoc_write_bd(struct eth_device *dev, int index, + const struct ethoc_bd *bd) +{ + loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); + ethoc_write(dev, offset + 0, bd->stat); + ethoc_write(dev, offset + 4, bd->addr); +} + +static int ethoc_set_mac_address(struct eth_device *dev) +{ + u8 *mac = dev->enetaddr; + + ethoc_write(dev, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) | + (mac[4] << 8) | (mac[5] << 0)); + ethoc_write(dev, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0)); + return 0; +} + +static inline void ethoc_ack_irq(struct eth_device *dev, u32 mask) +{ + ethoc_write(dev, INT_SOURCE, mask); +} + +static inline void ethoc_enable_rx_and_tx(struct eth_device *dev) +{ + u32 mode = ethoc_read(dev, MODER); + mode |= MODER_RXEN | MODER_TXEN; + ethoc_write(dev, MODER, mode); +} + +static inline void ethoc_disable_rx_and_tx(struct eth_device *dev) +{ + u32 mode = ethoc_read(dev, MODER); + mode &= ~(MODER_RXEN | MODER_TXEN); + ethoc_write(dev, MODER, mode); +} + +static int ethoc_init_ring(struct eth_device *dev) +{ + struct ethoc *priv = (struct ethoc *)dev->priv; + struct ethoc_bd bd; + int i; + + priv->cur_tx = 0; + priv->dty_tx = 0; + priv->cur_rx = 0; + + /* setup transmission buffers */ + bd.stat = TX_BD_IRQ | TX_BD_CRC; + + for (i = 0; i < priv->num_tx; i++) { + if (i == priv->num_tx - 1) + bd.stat |= TX_BD_WRAP; + + ethoc_write_bd(dev, i, &bd); + } + + bd.stat = RX_BD_EMPTY | RX_BD_IRQ; + + for (i = 0; i < priv->num_rx; i++) { + bd.addr = (u32)NetRxPackets[i]; + if (i == priv->num_rx - 1) + bd.stat |= RX_BD_WRAP; + + flush_dcache(bd.addr, PKTSIZE_ALIGN); + ethoc_write_bd(dev, priv->num_tx + i, &bd); + } + + return 0; +} + +static int ethoc_reset(struct eth_device *dev) +{ + u32 mode; + + /* TODO: reset controller? */ + + ethoc_disable_rx_and_tx(dev); + + /* TODO: setup registers */ + + /* enable FCS generation and automatic padding */ + mode = ethoc_read(dev, MODER); + mode |= MODER_CRC | MODER_PAD; + ethoc_write(dev, MODER, mode); + + /* set full-duplex mode */ + mode = ethoc_read(dev, MODER); + mode |= MODER_FULLD; + ethoc_write(dev, MODER, mode); + ethoc_write(dev, IPGT, 0x15); + + ethoc_ack_irq(dev, INT_MASK_ALL); + ethoc_enable_rx_and_tx(dev); + return 0; +} + +static int ethoc_init(struct eth_device *dev, bd_t * bd) +{ + struct ethoc *priv = (struct ethoc *)dev->priv; + printf("ethoc\n"); + + priv->num_tx = 1; + priv->num_rx = PKTBUFSRX; + ethoc_write(dev, TX_BD_NUM, priv->num_tx); + ethoc_init_ring(dev); + ethoc_reset(dev); + + return 0; +} + +static int ethoc_update_rx_stats(struct ethoc_bd *bd) +{ + int ret = 0; + + if (bd->stat & RX_BD_TL) { + debug("ETHOC: " "RX: frame too long\n"); + ret++; + } + + if (bd->stat & RX_BD_SF) { + debug("ETHOC: " "RX: frame too short\n"); + ret++; + } + + if (bd->stat & RX_BD_DN) + debug("ETHOC: " "RX: dribble nibble\n"); + + if (bd->stat & RX_BD_CRC) { + debug("ETHOC: " "RX: wrong CRC\n"); + ret++; + } + + if (bd->stat & RX_BD_OR) { + debug("ETHOC: " "RX: overrun\n"); + ret++; + } + + if (bd->stat & RX_BD_LC) { + debug("ETHOC: " "RX: late collision\n"); + ret++; + } + + return ret; +} + +static int ethoc_rx(struct eth_device *dev, int limit) +{ + struct ethoc *priv = (struct ethoc *)dev->priv; + int count; + + for (count = 0; count < limit; ++count) { + u32 entry; + struct ethoc_bd bd; + + entry = priv->num_tx + (priv->cur_rx % priv->num_rx); + ethoc_read_bd(dev, entry, &bd); + if (bd.stat & RX_BD_EMPTY) + break; + + debug("%s(): RX buffer %d, %x received\n", + __func__, priv->cur_rx, bd.stat); + if (ethoc_update_rx_stats(&bd) == 0) { + int size = bd.stat >> 16; + size -= 4; /* strip the CRC */ + NetReceive((void *)bd.addr, size); + } + + /* clear the buffer descriptor so it can be reused */ + flush_dcache(bd.addr, PKTSIZE_ALIGN); + bd.stat &= ~RX_BD_STATS; + bd.stat |= RX_BD_EMPTY; + ethoc_write_bd(dev, entry, &bd); + priv->cur_rx++; + } + + return count; +} + +static int ethoc_update_tx_stats(struct ethoc_bd *bd) +{ + if (bd->stat & TX_BD_LC) + debug("ETHOC: " "TX: late collision\n"); + + if (bd->stat & TX_BD_RL) + debug("ETHOC: " "TX: retransmit limit\n"); + + if (bd->stat & TX_BD_UR) + debug("ETHOC: " "TX: underrun\n"); + + if (bd->stat & TX_BD_CS) + debug("ETHOC: " "TX: carrier sense lost\n"); + + return 0; +} + +static void ethoc_tx(struct eth_device *dev) +{ + struct ethoc *priv = (struct ethoc *)dev->priv; + u32 entry = priv->dty_tx % priv->num_tx; + struct ethoc_bd bd; + + ethoc_read_bd(dev, entry, &bd); + if ((bd.stat & TX_BD_READY) == 0) + (void)ethoc_update_tx_stats(&bd); +} + +static int ethoc_send(struct eth_device *dev, volatile void *packet, int length) +{ + struct ethoc *priv = (struct ethoc *)dev->priv; + struct ethoc_bd bd; + u32 entry; + u32 pending; + int tmo; + + entry = priv->cur_tx % priv->num_tx; + ethoc_read_bd(dev, entry, &bd); + if (unlikely(length < ETHOC_ZLEN)) + bd.stat |= TX_BD_PAD; + else + bd.stat &= ~TX_BD_PAD; + bd.addr = (u32)packet; + + flush_dcache(bd.addr, length); + bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); + bd.stat |= TX_BD_LEN(length); + ethoc_write_bd(dev, entry, &bd); + + /* start transmit */ + bd.stat |= TX_BD_READY; + ethoc_write_bd(dev, entry, &bd); + + /* wait for transfer to succeed */ + tmo = get_timer(0) + 5 * CONFIG_SYS_HZ; + while (1) { + pending = ethoc_read(dev, INT_SOURCE); + ethoc_ack_irq(dev, pending & ~INT_MASK_RX); + if (pending & INT_MASK_BUSY) + debug("%s(): packet dropped\n", __func__); + + if (pending & INT_MASK_TX) { + ethoc_tx(dev); + break; + } + if (get_timer(0) >= tmo) { + debug("%s(): timed out\n", __func__); + return -1; + } + } + + debug("%s(): packet sent\n", __func__); + return 0; +} + +static void ethoc_halt(struct eth_device *dev) +{ + ethoc_disable_rx_and_tx(dev); +} + +static int ethoc_recv(struct eth_device *dev) +{ + u32 pending; + + pending = ethoc_read(dev, INT_SOURCE); + ethoc_ack_irq(dev, pending); + if (pending & INT_MASK_BUSY) + debug("%s(): packet dropped\n", __func__); + if (pending & INT_MASK_RX) { + debug("%s(): rx irq\n", __func__); + ethoc_rx(dev, PKTBUFSRX); + } + + return 0; +} + +int ethoc_initialize(u8 dev_num, int base_addr) +{ + struct ethoc *priv; + struct eth_device *dev; + + priv = malloc(sizeof(*priv)); + if (!priv) + return 0; + dev = malloc(sizeof(*dev)); + if (!dev) { + free(priv); + return 0; + } + + memset(dev, 0, sizeof(*dev)); + dev->priv = priv; + dev->iobase = base_addr; + dev->init = ethoc_init; + dev->halt = ethoc_halt; + dev->send = ethoc_send; + dev->recv = ethoc_recv; + dev->write_hwaddr = ethoc_set_mac_address; + sprintf(dev->name, "%s-%hu", "ETHOC", dev_num); + + eth_register(dev); + return 1; +} diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 8c4ade5..57f89a3 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -314,9 +314,9 @@ static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) { /* * The MX27 can store the mac address in internal eeprom - * This mechanism is not supported now by MX51 + * This mechanism is not supported now by MX51 or MX25 */ -#ifdef CONFIG_MX51 +#if defined(CONFIG_MX51) || defined(CONFIG_MX25) return -1; #else struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; @@ -325,7 +325,7 @@ static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) for (i = 0; i < 6; i++) mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]); - return is_valid_ether_addr(mac); + return !is_valid_ether_addr(mac); #endif } @@ -505,7 +505,6 @@ static int fec_init(struct eth_device *dev, bd_t* bd) miiphy_restart_aneg(dev); fec_open(dev); - fec_set_hwaddr(dev); return 0; } @@ -713,6 +712,7 @@ static int fec_probe(bd_t *bd) edev->send = fec_send; edev->recv = fec_recv; edev->halt = fec_halt; + edev->write_hwaddr = fec_set_hwaddr; fec->eth = (struct ethernet_regs *)IMX_FEC_BASE; fec->bd = bd; diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c index 2ad7fea..932792e 100644 --- a/drivers/net/kirkwood_egiga.c +++ b/drivers/net/kirkwood_egiga.c @@ -424,8 +424,6 @@ static int kwgbe_init(struct eth_device *dev) KWGBEREG_WR(regs->pxc, PRT_CFG_VAL); KWGBEREG_WR(regs->pxcx, PORT_CFG_EXTEND_VALUE); KWGBEREG_WR(regs->psc0, PORT_SERIAL_CONTROL_VALUE); - /* Disable port initially */ - KWGBEREG_BITS_SET(regs->psc0, KWGBE_SERIAL_PORT_EN); /* Assign port SDMA configuration */ KWGBEREG_WR(regs->sdc, PORT_SDMA_CFG_VALUE); @@ -438,6 +436,9 @@ static int kwgbe_init(struct eth_device *dev) KWGBEREG_WR(regs->psc0, KWGBE_MAX_RX_PACKET_9700BYTE | (KWGBEREG_RD(regs->psc0) & MRU_MASK)); + /* Enable port initially */ + KWGBEREG_BITS_SET(regs->psc0, KWGBE_SERIAL_PORT_EN); + /* * Set ethernet MTU for leaky bucket mechanism to 0 - this will * disable the leaky bucket mechanism . @@ -445,7 +446,7 @@ static int kwgbe_init(struct eth_device *dev) KWGBEREG_WR(regs->pmtu, 0); /* Assignment of Rx CRDB of given RXUQ */ - KWGBEREG_WR(regs->rxcdp[RXUQ].rxcdp, (u32) dkwgbe->p_rxdesc_curr); + KWGBEREG_WR(regs->rxcdp[RXUQ], (u32) dkwgbe->p_rxdesc_curr); /* Enable port Rx. */ KWGBEREG_WR(regs->rqc, (1 << RXUQ)); @@ -480,7 +481,7 @@ static int kwgbe_halt(struct eth_device *dev) stop_queue(®s->tqc); stop_queue(®s->rqc); - /* Enable port */ + /* Disable port */ KWGBEREG_BITS_RESET(regs->psc0, KWGBE_SERIAL_PORT_EN); /* Set port is not reset */ KWGBEREG_BITS_RESET(regs->psc1, 1 << 4); @@ -497,6 +498,16 @@ static int kwgbe_halt(struct eth_device *dev) return 0; } +static int kwgbe_write_hwaddr(struct eth_device *dev) +{ + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + + /* Programs net device MAC address after initialization */ + port_uc_addr_set(regs, dkwgbe->dev.enetaddr); + return 0; +} + static int kwgbe_send(struct eth_device *dev, volatile void *dataptr, int datasize) { @@ -525,7 +536,7 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr, p_txdesc->buf_ptr = (u8 *) p; p_txdesc->byte_cnt = datasize; - /* Apply send command using zeroth RXUQ */ + /* Apply send command using zeroth TXUQ */ KWGBEREG_WR(regs->tcqdp[TXUQ], (u32) p_txdesc); KWGBEREG_WR(regs->tqc, (1 << TXUQ)); @@ -606,7 +617,7 @@ static int kwgbe_recv(struct eth_device *dev) p_rxdesc_curr->buf_size = PKTSIZE_ALIGN; p_rxdesc_curr->byte_cnt = 0; - writel((unsigned)p_rxdesc_curr->nxtdesc_p, &dkwgbe->p_rxdesc_curr); + writel((unsigned)p_rxdesc_curr->nxtdesc_p, (u32) &dkwgbe->p_rxdesc_curr); return 0; } @@ -693,6 +704,7 @@ int kirkwood_egiga_initialize(bd_t * bis) dev->halt = (void *)kwgbe_halt; dev->send = (void *)kwgbe_send; dev->recv = (void *)kwgbe_recv; + dev->write_hwaddr = (void *)kwgbe_write_hwaddr; eth_register(dev); diff --git a/drivers/net/kirkwood_egiga.h b/drivers/net/kirkwood_egiga.h index 16d5214..30c773c 100644 --- a/drivers/net/kirkwood_egiga.h +++ b/drivers/net/kirkwood_egiga.h @@ -418,7 +418,7 @@ struct kwgbe_registers { u32 pmtbs; u8 pad14[0x60c - 0x4ec - 4]; struct kwgbe_rxcdp rxcdp[7]; - u32 rxcdp7; + struct kwgbe_rxdesc *rxcdp7; u32 rqc; struct kwgbe_txdesc *tcsdp; u8 pad15[0x6c0 - 0x684 - 4]; diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index 4acc29e..060bdd7 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -175,38 +175,39 @@ int mii_discover_phy(struct eth_device *dev) #ifdef ET_DEBUG printf("PHY type 0x%x pass %d type\n", phytype, pass); #endif - if (phytype != 0xffff) { - phyaddr = phyno; - phytype <<= 16; - phytype |= - mii_send(mk_mii_read(phyno, PHY_PHYIDR2)); + if (phytype == 0xffff) + continue; + phyaddr = phyno; + phytype <<= 16; + phytype |= + mii_send(mk_mii_read(phyno, PHY_PHYIDR2)); #ifdef ET_DEBUG - printf("PHY @ 0x%x pass %d\n", phyno, pass); + printf("PHY @ 0x%x pass %d\n", phyno, pass); #endif - for (i = 0; i < (sizeof(phyinfo) / sizeof(phy_info_t)); i++) { - if (phyinfo[i].phyid == phytype) { + for (i = 0; (i < (sizeof(phyinfo) / sizeof(phy_info_t))) + && (phyinfo[i].phyid != 0); i++) { + if (phyinfo[i].phyid == phytype) { #ifdef ET_DEBUG - printf("phyid %x - %s\n", - phyinfo[i].phyid, - phyinfo[i].strid); + printf("phyid %x - %s\n", + phyinfo[i].phyid, + phyinfo[i].strid); #endif - strcpy(info->phy_name, phyinfo[i].strid); - info->phyname_init = 1; - found = 1; - break; - } + strcpy(info->phy_name, phyinfo[i].strid); + info->phyname_init = 1; + found = 1; + break; } + } - if (!found) { + if (!found) { #ifdef ET_DEBUG - printf("0x%08x\n", phytype); + printf("0x%08x\n", phytype); #endif - strcpy(info->phy_name, "unknown"); - info->phyname_init = 1; - break; - } + strcpy(info->phy_name, "unknown"); + info->phyname_init = 1; + break; } } } diff --git a/drivers/net/mpc512x_fec.c b/drivers/net/mpc512x_fec.c index fb2c19a..c580c82 100644 --- a/drivers/net/mpc512x_fec.c +++ b/drivers/net/mpc512x_fec.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2003-2009 + * (C) Copyright 2003-2010 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * Derived from the MPC8xx FEC driver. @@ -25,10 +25,6 @@ DECLARE_GLOBAL_DATA_PTR; #error "CONFIG_MII has to be defined!" #endif -#if (DEBUG & 0x40) -static u32 local_crc32(char *string, unsigned int crc_value, int len); -#endif - int fec512x_miiphy_read(char *devname, u8 phyAddr, u8 regAddr, u16 * retVal); int fec512x_miiphy_write(char *devname, u8 phyAddr, u8 regAddr, u16 data); int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis); @@ -164,7 +160,7 @@ static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec) } /********************************************************************/ -static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, char *mac) +static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, unsigned char *mac) { u8 currByte; /* byte for which to compute the CRC */ int byte; /* loop - counter */ @@ -230,6 +226,12 @@ static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis) printf ("mpc512x_fec_init... Begin\n"); #endif + mpc512x_fec_set_hwaddr (fec, dev->enetaddr); + out_be32(&fec->eth->gaddr1, 0x00000000); + out_be32(&fec->eth->gaddr2, 0x00000000); + + mpc512x_fec_init_phy (dev, bis); + /* Set interrupt mask register */ out_be32(&fec->eth->imask, 0x00000000); @@ -615,8 +617,6 @@ int mpc512x_fec_initialize (bd_t * bis) volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR; mpc512x_fec_priv *fec; struct eth_device *dev; - int i; - char *tmp, *end, env_enetaddr[6]; void * bd; fec = (mpc512x_fec_priv *) malloc (sizeof(*fec)); @@ -667,25 +667,6 @@ int mpc512x_fec_initialize (bd_t * bis) */ out_be32(&fec->eth->ievent, 0xffffffff); - /* - * Try to set the mac address now. The fec mac address is - * a garbage after reset. When not using fec for booting - * the Linux fec driver will try to work with this garbage. - */ - tmp = getenv ("ethaddr"); - if (tmp) { - for (i=0; i<6; i++) { - env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0; - if (tmp) - tmp = (*end) ? end+1 : end; - } - mpc512x_fec_set_hwaddr (fec, env_enetaddr); - out_be32(&fec->eth->gaddr1, 0x00000000); - out_be32(&fec->eth->gaddr2, 0x00000000); - } - - mpc512x_fec_init_phy (dev, bis); - return 1; } @@ -775,39 +756,4 @@ int fec512x_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data) return 0; } -#if (DEBUG & 0x40) -static u32 local_crc32 (char *string, unsigned int crc_value, int len) -{ - int i; - char c; - unsigned int crc, count; - - /* - * crc32 algorithm - */ - /* - * crc = 0xffffffff; * The initialized value should be 0xffffffff - */ - crc = crc_value; - - for (i = len; --i >= 0;) { - c = *string++; - for (count = 0; count < 8; count++) { - if ((c & 0x01) ^ (crc & 0x01)) { - crc >>= 1; - crc = crc ^ 0xedb88320; - } else { - crc >>= 1; - } - c >>= 1; - } - } - - /* - * In big endian system, do byte swaping for crc value - */ - /**/ return crc; -} -#endif /* DEBUG */ - #endif /* CONFIG_MPC512x_FEC */ diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c index c2b1bbd..1681e26 100644 --- a/drivers/net/mpc5xxx_fec.c +++ b/drivers/net/mpc5xxx_fec.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2003-2005 + * (C) Copyright 2003-2010 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * This file is based on mpc4200fec.c, @@ -28,10 +28,6 @@ static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec); static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec); #endif /* DEBUG */ -#if (DEBUG & 0x40) -static uint32 local_crc32(char *string, unsigned int crc_value, int len); -#endif - typedef struct { uint8 data[1500]; /* actual data */ int length; /* actual length */ @@ -1019,38 +1015,3 @@ int fec5xxx_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 dat return 0; } - -#if (DEBUG & 0x40) -static uint32 local_crc32(char *string, unsigned int crc_value, int len) -{ - int i; - char c; - unsigned int crc, count; - - /* - * crc32 algorithm - */ - /* - * crc = 0xffffffff; * The initialized value should be 0xffffffff - */ - crc = crc_value; - - for (i = len; --i >= 0;) { - c = *string++; - for (count = 0; count < 8; count++) { - if ((c & 0x01) ^ (crc & 0x01)) { - crc >>= 1; - crc = crc ^ 0xedb88320; - } else { - crc >>= 1; - } - c >>= 1; - } - } - - /* - * In big endian system, do byte swaping for crc value - */ - /**/ return crc; -} -#endif /* DEBUG */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index cac08d0..f2fc88b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -220,7 +220,7 @@ static int smc911x_rx(struct eth_device *dev) smc911x_reg_write(dev, RX_CFG, 0); - tmplen = (pktlen + 2+ 3) / 4; + tmplen = (pktlen + 3) / 4; while (tmplen--) *data++ = pkt_data_pull(dev, RX_DATA_FIFO); diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index fd49eff..3e4c3bd 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -1082,7 +1082,8 @@ static void tsec_halt(struct eth_device *dev) regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); - while (!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))) ; + while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)) + != (IEVENT_GRSC | IEVENT_GTSC)) ; regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 27dc500..ccbf27d 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -595,8 +595,7 @@ static void phy_change(struct eth_device *dev) adjust_link(dev); } -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) /* * Find a device index from the devlist by name @@ -1388,8 +1387,7 @@ int uec_initialize(bd_t *bis, uec_info_t *uec_info) return err; } -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register(dev->name, uec_miiphy_read, uec_miiphy_write); #endif diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index fa48fea..3baffe4 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -93,6 +93,27 @@ static const struct fixed_phy_port fixed_phy_port[] = { CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */ }; +/*--------------------------------------------------------------------+ + * BitBang MII support for ethernet ports + * + * Based from MPC8560ADS implementation + *--------------------------------------------------------------------*/ +/* + * Example board header file to define bitbang ethernet ports: + * + * #define CONFIG_SYS_BITBANG_PHY_PORT(name) name, + * #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("FSL UEC0") +*/ +#ifndef CONFIG_SYS_BITBANG_PHY_PORTS +#define CONFIG_SYS_BITBANG_PHY_PORTS /* default is an empty array */ +#endif + +#if defined(CONFIG_BITBANGMII) +static const char *bitbang_phy_port[] = { + CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */ +}; +#endif /* CONFIG_BITBANGMII */ + static void config_genmii_advert (struct uec_mii_info *mii_info); static void genmii_setup_forced (struct uec_mii_info *mii_info); static void genmii_restart_aneg (struct uec_mii_info *mii_info); @@ -113,6 +134,19 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; u32 tmp_reg; + +#if defined(CONFIG_BITBANGMII) + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) { + if (strncmp(dev->name, bitbang_phy_port[i], + sizeof(dev->name)) == 0) { + (void)bb_miiphy_write(NULL, mii_id, regnum, value); + return; + } + } +#endif /* CONFIG_BITBANGMII */ + ug_regs = ugeth->uec_mii_regs; /* Stop the MII management read cycle */ @@ -140,6 +174,19 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) u32 tmp_reg; u16 value; + +#if defined(CONFIG_BITBANGMII) + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) { + if (strncmp(dev->name, bitbang_phy_port[i], + sizeof(dev->name)) == 0) { + (void)bb_miiphy_read(NULL, mii_id, regnum, &value); + return (value); + } + } +#endif /* CONFIG_BITBANGMII */ + ug_regs = ugeth->uec_mii_regs; /* Setting up the MII Mangement Address Register */ |