diff options
Diffstat (limited to 'drivers/net/greth.c')
-rw-r--r-- | drivers/net/greth.c | 677 |
1 files changed, 0 insertions, 677 deletions
diff --git a/drivers/net/greth.c b/drivers/net/greth.c deleted file mode 100644 index aa5d7114a5..0000000000 --- a/drivers/net/greth.c +++ /dev/null @@ -1,677 +0,0 @@ -/* Gaisler.com GRETH 10/100/1000 Ethernet MAC driver - * - * Driver use polling mode (no Interrupt) - * - * (C) Copyright 2007 - * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* #define DEBUG */ - -#include <common.h> -#include <command.h> -#include <errno.h> -#include <net.h> -#include <netdev.h> -#include <malloc.h> -#include <asm/processor.h> -#include <ambapp.h> -#include <asm/leon.h> - -#include <grlib/greth.h> - -/* Default to 3s timeout on autonegotiation */ -#ifndef GRETH_PHY_TIMEOUT_MS -#define GRETH_PHY_TIMEOUT_MS 3000 -#endif - -/* Default to PHY adrress 0 not not specified */ -#ifdef CONFIG_SYS_GRLIB_GRETH_PHYADDR -#define GRETH_PHY_ADR_DEFAULT CONFIG_SYS_GRLIB_GRETH_PHYADDR -#else -#define GRETH_PHY_ADR_DEFAULT 0 -#endif - -/* Let board select which GRETH to use as network interface, set - * this to zero if only one GRETH is available. - */ -#ifndef CONFIG_SYS_GRLIB_GRETH_INDEX -#define CONFIG_SYS_GRLIB_GRETH_INDEX 0 -#endif - -/* ByPass Cache when reading regs */ -#define GRETH_REGLOAD(addr) SPARC_NOCACHE_READ(addr) -/* Write-through cache ==> no bypassing needed on writes */ -#define GRETH_REGSAVE(addr,data) (*(volatile unsigned int *)(addr) = (data)) -#define GRETH_REGORIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)|data) -#define GRETH_REGANDIN(addr,data) GRETH_REGSAVE(addr,GRETH_REGLOAD(addr)&data) - -#define GRETH_RXBD_CNT 4 -#define GRETH_TXBD_CNT 1 - -#define GRETH_RXBUF_SIZE 1540 -#define GRETH_BUF_ALIGN 4 -#define GRETH_RXBUF_EFF_SIZE \ - ( (GRETH_RXBUF_SIZE&~(GRETH_BUF_ALIGN-1))+GRETH_BUF_ALIGN ) - -typedef struct { - greth_regs *regs; - int irq; - struct eth_device *dev; - - /* Hardware info */ - unsigned char phyaddr; - int gbit_mac; - - /* Current operating Mode */ - int gb; /* GigaBit */ - int fd; /* Full Duplex */ - int sp; /* 10/100Mbps speed (1=100,0=10) */ - int auto_neg; /* Auto negotiate done */ - - unsigned char hwaddr[6]; /* MAC Address */ - - /* Descriptors */ - greth_bd *rxbd_base, *rxbd_max; - greth_bd *txbd_base, *txbd_max; - - greth_bd *rxbd_curr; - - /* rx buffers in rx descriptors */ - void *rxbuf_base; /* (GRETH_RXBUF_SIZE+ALIGNBYTES) * GRETH_RXBD_CNT */ - - /* unused for gbit_mac, temp buffer for sending packets with unligned - * start. - * Pointer to packet allocated with malloc. - */ - void *txbuf; - - struct { - /* rx status */ - unsigned int rx_packets, - rx_crc_errors, rx_frame_errors, rx_length_errors, rx_errors; - - /* tx stats */ - unsigned int tx_packets, - tx_latecol_errors, - tx_underrun_errors, tx_limit_errors, tx_errors; - } stats; -} greth_priv; - -/* Read MII register 'addr' from core 'regs' */ -static int read_mii(int phyaddr, int regaddr, volatile greth_regs * regs) -{ - while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { - } - - GRETH_REGSAVE(®s->mdio, ((phyaddr & 0x1F) << 11) | ((regaddr & 0x1F) << 6) | 2); - - while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { - } - - if (!(GRETH_REGLOAD(®s->mdio) & GRETH_MII_NVALID)) { - return (GRETH_REGLOAD(®s->mdio) >> 16) & 0xFFFF; - } else { - return -1; - } -} - -static void write_mii(int phyaddr, int regaddr, int data, volatile greth_regs * regs) -{ - while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { - } - - GRETH_REGSAVE(®s->mdio, - ((data & 0xFFFF) << 16) | ((phyaddr & 0x1F) << 11) | - ((regaddr & 0x1F) << 6) | 1); - - while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { - } - -} - -/* init/start hardware and allocate descriptor buffers for rx side - * - */ -int greth_init(struct eth_device *dev, bd_t * bis) -{ - int i; - - greth_priv *greth = dev->priv; - greth_regs *regs = greth->regs; - - debug("greth_init\n"); - - /* Reset core */ - GRETH_REGSAVE(®s->control, (GRETH_RESET | (greth->gb << 8) | - (greth->sp << 7) | (greth->fd << 4))); - - /* Wait for Reset to complete */ - while ( GRETH_REGLOAD(®s->control) & GRETH_RESET) ; - - GRETH_REGSAVE(®s->control, - ((greth->gb << 8) | (greth->sp << 7) | (greth->fd << 4))); - - if (!greth->rxbd_base) { - - /* allocate descriptors */ - greth->rxbd_base = (greth_bd *) - memalign(0x1000, GRETH_RXBD_CNT * sizeof(greth_bd)); - greth->txbd_base = (greth_bd *) - memalign(0x1000, GRETH_TXBD_CNT * sizeof(greth_bd)); - - /* allocate buffers to all descriptors */ - greth->rxbuf_base = - malloc(GRETH_RXBUF_EFF_SIZE * GRETH_RXBD_CNT); - } - - /* initate rx decriptors */ - for (i = 0; i < GRETH_RXBD_CNT; i++) { - greth->rxbd_base[i].addr = (unsigned int) - greth->rxbuf_base + (GRETH_RXBUF_EFF_SIZE * i); - /* enable desciptor & set wrap bit if last descriptor */ - if (i >= (GRETH_RXBD_CNT - 1)) { - greth->rxbd_base[i].stat = GRETH_BD_EN | GRETH_BD_WR; - } else { - greth->rxbd_base[i].stat = GRETH_BD_EN; - } - } - - /* initiate indexes */ - greth->rxbd_curr = greth->rxbd_base; - greth->rxbd_max = greth->rxbd_base + (GRETH_RXBD_CNT - 1); - greth->txbd_max = greth->txbd_base + (GRETH_TXBD_CNT - 1); - /* - * greth->txbd_base->addr = 0; - * greth->txbd_base->stat = GRETH_BD_WR; - */ - - /* initate tx decriptors */ - for (i = 0; i < GRETH_TXBD_CNT; i++) { - greth->txbd_base[i].addr = 0; - /* enable desciptor & set wrap bit if last descriptor */ - if (i >= (GRETH_TXBD_CNT - 1)) { - greth->txbd_base[i].stat = GRETH_BD_WR; - } else { - greth->txbd_base[i].stat = 0; - } - } - - /**** SET HARDWARE REGS ****/ - - /* Set pointer to tx/rx descriptor areas */ - GRETH_REGSAVE(®s->rx_desc_p, (unsigned int)&greth->rxbd_base[0]); - GRETH_REGSAVE(®s->tx_desc_p, (unsigned int)&greth->txbd_base[0]); - - /* Enable Transmitter, GRETH will now scan descriptors for packets - * to transmitt */ - debug("greth_init: enabling receiver\n"); - GRETH_REGORIN(®s->control, GRETH_RXEN); - - return 0; -} - -/* Initiate PHY to a relevant speed - * return: - * - 0 = success - * - 1 = timeout/fail - */ -int greth_init_phy(greth_priv * dev, bd_t * bis) -{ - greth_regs *regs = dev->regs; - int tmp, tmp1, tmp2, i; - unsigned int start, timeout; - int phyaddr = GRETH_PHY_ADR_DEFAULT; - -#ifndef CONFIG_SYS_GRLIB_GRETH_PHYADDR - /* If BSP doesn't provide a hardcoded PHY address the driver will - * try to autodetect PHY address by stopping the search on the first - * PHY address which has REG0 implemented. - */ - for (i=0; i<32; i++) { - tmp = read_mii(i, 0, regs); - if ( (tmp != 0) && (tmp != 0xffff) ) { - phyaddr = i; - break; - } - } -#endif - - /* Save PHY Address */ - dev->phyaddr = phyaddr; - - debug("GRETH PHY ADDRESS: %d\n", phyaddr); - - /* X msecs to ticks */ - timeout = GRETH_PHY_TIMEOUT_MS * 1000; - - /* Get system timer0 current value - * Total timeout is 5s - */ - start = get_timer(0); - - /* get phy control register default values */ - - while ((tmp = read_mii(phyaddr, 0, regs)) & 0x8000) { - if (get_timer(start) > timeout) { - debug("greth_init_phy: PHY read 1 failed\n"); - return 1; /* Fail */ - } - } - - /* reset PHY and wait for completion */ - write_mii(phyaddr, 0, 0x8000 | tmp, regs); - - while (((tmp = read_mii(phyaddr, 0, regs))) & 0x8000) { - if (get_timer(start) > timeout) { - debug("greth_init_phy: PHY read 2 failed\n"); - return 1; /* Fail */ - } - } - - /* Check if PHY is autoneg capable and then determine operating - * mode, otherwise force it to 10 Mbit halfduplex - */ - dev->gb = 0; - dev->fd = 0; - dev->sp = 0; - dev->auto_neg = 0; - if (!((tmp >> 12) & 1)) { - write_mii(phyaddr, 0, 0, regs); - } else { - /* wait for auto negotiation to complete and then check operating mode */ - dev->auto_neg = 1; - i = 0; - while (!(((tmp = read_mii(phyaddr, 1, regs)) >> 5) & 1)) { - if (get_timer(start) > timeout) { - printf("Auto negotiation timed out. " - "Selecting default config\n"); - tmp = read_mii(phyaddr, 0, regs); - dev->gb = ((tmp >> 6) & 1) - && !((tmp >> 13) & 1); - dev->sp = !((tmp >> 6) & 1) - && ((tmp >> 13) & 1); - dev->fd = (tmp >> 8) & 1; - goto auto_neg_done; - } - } - if ((tmp >> 8) & 1) { - tmp1 = read_mii(phyaddr, 9, regs); - tmp2 = read_mii(phyaddr, 10, regs); - if ((tmp1 & GRETH_MII_EXTADV_1000FD) && - (tmp2 & GRETH_MII_EXTPRT_1000FD)) { - dev->gb = 1; - dev->fd = 1; - } - if ((tmp1 & GRETH_MII_EXTADV_1000HD) && - (tmp2 & GRETH_MII_EXTPRT_1000HD)) { - dev->gb = 1; - dev->fd = 0; - } - } - if ((dev->gb == 0) || ((dev->gb == 1) && (dev->gbit_mac == 0))) { - tmp1 = read_mii(phyaddr, 4, regs); - tmp2 = read_mii(phyaddr, 5, regs); - if ((tmp1 & GRETH_MII_100TXFD) && - (tmp2 & GRETH_MII_100TXFD)) { - dev->sp = 1; - dev->fd = 1; - } - if ((tmp1 & GRETH_MII_100TXHD) && - (tmp2 & GRETH_MII_100TXHD)) { - dev->sp = 1; - dev->fd = 0; - } - if ((tmp1 & GRETH_MII_10FD) && (tmp2 & GRETH_MII_10FD)) { - dev->fd = 1; - } - if ((dev->gb == 1) && (dev->gbit_mac == 0)) { - dev->gb = 0; - dev->fd = 0; - write_mii(phyaddr, 0, dev->sp << 13, regs); - } - } - - } - auto_neg_done: - debug("%s GRETH Ethermac at [0x%x] irq %d. Running \ - %d Mbps %s duplex\n", dev->gbit_mac ? "10/100/1000" : "10/100", (unsigned int)(regs), (unsigned int)(dev->irq), dev->gb ? 1000 : (dev->sp ? 100 : 10), dev->fd ? "full" : "half"); - /* Read out PHY info if extended registers are available */ - if (tmp & 1) { - tmp1 = read_mii(phyaddr, 2, regs); - tmp2 = read_mii(phyaddr, 3, regs); - tmp1 = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F); - tmp = tmp2 & 0xF; - - tmp2 = (tmp2 >> 4) & 0x3F; - debug("PHY: Vendor %x Device %x Revision %d\n", tmp1, - tmp2, tmp); - } else { - printf("PHY info not available\n"); - } - - /* set speed and duplex bits in control register */ - GRETH_REGORIN(®s->control, - (dev->gb << 8) | (dev->sp << 7) | (dev->fd << 4)); - - return 0; -} - -void greth_halt(struct eth_device *dev) -{ - greth_priv *greth; - greth_regs *regs; - int i; - - debug("greth_halt\n"); - - if (!dev || !dev->priv) - return; - - greth = dev->priv; - regs = greth->regs; - - if (!regs) - return; - - /* disable receiver/transmitter by clearing the enable bits */ - GRETH_REGANDIN(®s->control, ~(GRETH_RXEN | GRETH_TXEN)); - - /* reset rx/tx descriptors */ - if (greth->rxbd_base) { - for (i = 0; i < GRETH_RXBD_CNT; i++) { - greth->rxbd_base[i].stat = - (i >= (GRETH_RXBD_CNT - 1)) ? GRETH_BD_WR : 0; - } - } - - if (greth->txbd_base) { - for (i = 0; i < GRETH_TXBD_CNT; i++) { - greth->txbd_base[i].stat = - (i >= (GRETH_TXBD_CNT - 1)) ? GRETH_BD_WR : 0; - } - } -} - -int greth_send(struct eth_device *dev, void *eth_data, int data_length) -{ - greth_priv *greth = dev->priv; - greth_regs *regs = greth->regs; - greth_bd *txbd; - void *txbuf; - unsigned int status; - - debug("greth_send\n"); - - /* send data, wait for data to be sent, then return */ - if (((unsigned int)eth_data & (GRETH_BUF_ALIGN - 1)) - && !greth->gbit_mac) { - /* data not aligned as needed by GRETH 10/100, solve this by allocating 4 byte aligned buffer - * and copy data to before giving it to GRETH. - */ - if (!greth->txbuf) { - greth->txbuf = malloc(GRETH_RXBUF_SIZE); - } - - txbuf = greth->txbuf; - - /* copy data info buffer */ - memcpy((char *)txbuf, (char *)eth_data, data_length); - - /* keep buffer to next time */ - } else { - txbuf = (void *)eth_data; - } - /* get descriptor to use, only 1 supported... hehe easy */ - txbd = greth->txbd_base; - - /* setup descriptor to wrap around to it self */ - txbd->addr = (unsigned int)txbuf; - txbd->stat = GRETH_BD_EN | GRETH_BD_WR | data_length; - - /* Remind Core which descriptor to use when sending */ - GRETH_REGSAVE(®s->tx_desc_p, (unsigned int)txbd); - - /* initate send by enabling transmitter */ - GRETH_REGORIN(®s->control, GRETH_TXEN); - - /* Wait for data to be sent */ - while ((status = GRETH_REGLOAD(&txbd->stat)) & GRETH_BD_EN) { - ; - } - - /* was the packet transmitted succesfully? */ - if (status & GRETH_TXBD_ERR_AL) { - greth->stats.tx_limit_errors++; - } - - if (status & GRETH_TXBD_ERR_UE) { - greth->stats.tx_underrun_errors++; - } - - if (status & GRETH_TXBD_ERR_LC) { - greth->stats.tx_latecol_errors++; - } - - if (status & - (GRETH_TXBD_ERR_LC | GRETH_TXBD_ERR_UE | GRETH_TXBD_ERR_AL)) { - /* any error */ - greth->stats.tx_errors++; - return -1; - } - - /* bump tx packet counter */ - greth->stats.tx_packets++; - - /* return succefully */ - return 0; -} - -int greth_recv(struct eth_device *dev) -{ - greth_priv *greth = dev->priv; - greth_regs *regs = greth->regs; - greth_bd *rxbd; - unsigned int status, len = 0, bad; - char *d; - int enable = 0; - int i; - - /* Receive One packet only, but clear as many error packets as there are - * available. - */ - { - /* current receive descriptor */ - rxbd = greth->rxbd_curr; - - /* get status of next received packet */ - status = GRETH_REGLOAD(&rxbd->stat); - - bad = 0; - - /* stop if no more packets received */ - if (status & GRETH_BD_EN) { - goto done; - } - - debug("greth_recv: packet 0x%x, 0x%x, len: %d\n", - (unsigned int)rxbd, status, status & GRETH_BD_LEN); - - /* Check status for errors. - */ - if (status & GRETH_RXBD_ERR_FT) { - greth->stats.rx_length_errors++; - bad = 1; - } - if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) { - greth->stats.rx_frame_errors++; - bad = 1; - } - if (status & GRETH_RXBD_ERR_CRC) { - greth->stats.rx_crc_errors++; - bad = 1; - } - if (bad) { - greth->stats.rx_errors++; - printf - ("greth_recv: Bad packet (%d, %d, %d, 0x%08x, %d)\n", - greth->stats.rx_length_errors, - greth->stats.rx_frame_errors, - greth->stats.rx_crc_errors, status, - greth->stats.rx_packets); - /* print all rx descriptors */ - for (i = 0; i < GRETH_RXBD_CNT; i++) { - printf("[%d]: Stat=0x%lx, Addr=0x%lx\n", i, - GRETH_REGLOAD(&greth->rxbd_base[i].stat), - GRETH_REGLOAD(&greth->rxbd_base[i].addr)); - } - } else { - /* Process the incoming packet. */ - len = status & GRETH_BD_LEN; - d = (char *)rxbd->addr; - - debug - ("greth_recv: new packet, length: %d. data: %x %x %x %x %x %x %x %x\n", - len, d[0], d[1], d[2], d[3], d[4], d[5], d[6], - d[7]); - - /* flush all data cache to make sure we're not reading old packet data */ - sparc_dcache_flush_all(); - - /* pass packet on to network subsystem */ - net_process_received_packet((void *)d, len); - - /* bump stats counters */ - greth->stats.rx_packets++; - - /* bad is now 0 ==> will stop loop */ - } - - /* reenable descriptor to receive more packet with this descriptor, wrap around if needed */ - rxbd->stat = - GRETH_BD_EN | - (((unsigned int)greth->rxbd_curr >= - (unsigned int)greth->rxbd_max) ? GRETH_BD_WR : 0); - enable = 1; - - /* increase index */ - greth->rxbd_curr = - ((unsigned int)greth->rxbd_curr >= - (unsigned int)greth->rxbd_max) ? greth-> - rxbd_base : (greth->rxbd_curr + 1); - - } - - if (enable) { - GRETH_REGORIN(®s->control, GRETH_RXEN); - } - done: - /* return positive length of packet or 0 if non received */ - return len; -} - -void greth_set_hwaddr(greth_priv * greth, unsigned char *mac) -{ - /* save new MAC address */ - greth->dev->enetaddr[0] = greth->hwaddr[0] = mac[0]; - greth->dev->enetaddr[1] = greth->hwaddr[1] = mac[1]; - greth->dev->enetaddr[2] = greth->hwaddr[2] = mac[2]; - greth->dev->enetaddr[3] = greth->hwaddr[3] = mac[3]; - greth->dev->enetaddr[4] = greth->hwaddr[4] = mac[4]; - greth->dev->enetaddr[5] = greth->hwaddr[5] = mac[5]; - greth->regs->esa_msb = (mac[0] << 8) | mac[1]; - greth->regs->esa_lsb = - (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; - - debug("GRETH: New MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -} - -int greth_initialize(bd_t * bis) -{ - greth_priv *greth; - ambapp_apbdev apbdev; - struct eth_device *dev; - int i; - char *addr_str, *end; - unsigned char addr[6]; - - debug("Scanning for GRETH\n"); - - /* Find Device & IRQ via AMBA Plug&Play information, - * CONFIG_SYS_GRLIB_GRETH_INDEX select which GRETH if multiple - * GRETHs in system. - */ - if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_ETHMAC, - CONFIG_SYS_GRLIB_GRETH_INDEX, &apbdev) != 1) { - return -1; /* GRETH not found */ - } - - greth = (greth_priv *) malloc(sizeof(greth_priv)); - dev = (struct eth_device *)malloc(sizeof(struct eth_device)); - memset(dev, 0, sizeof(struct eth_device)); - memset(greth, 0, sizeof(greth_priv)); - - greth->regs = (greth_regs *) apbdev.address; - greth->irq = apbdev.irq; - debug("Found GRETH at %p, irq %d\n", greth->regs, greth->irq); - dev->priv = (void *)greth; - dev->iobase = (unsigned int)greth->regs; - dev->init = greth_init; - dev->halt = greth_halt; - dev->send = greth_send; - dev->recv = greth_recv; - greth->dev = dev; - - /* Reset Core */ - GRETH_REGSAVE(&greth->regs->control, GRETH_RESET); - - /* Wait for core to finish reset cycle */ - while (GRETH_REGLOAD(&greth->regs->control) & GRETH_RESET) ; - - /* Get the phy address which assumed to have been set - correctly with the reset value in hardware */ - greth->phyaddr = (GRETH_REGLOAD(&greth->regs->mdio) >> 11) & 0x1F; - - /* Check if mac is gigabit capable */ - greth->gbit_mac = (GRETH_REGLOAD(&greth->regs->control) >> 27) & 1; - - /* Make descriptor string */ - if (greth->gbit_mac) { - strcpy(dev->name, "GRETH_10/100/GB"); - } else { - strcpy(dev->name, "GRETH_10/100"); - } - - /* initiate PHY, select speed/duplex depending on connected PHY */ - if (greth_init_phy(greth, bis)) { - /* Failed to init PHY (timedout) */ - debug("GRETH[%p]: Failed to init PHY\n", greth->regs); - return -1; - } - - /* Register Device to EtherNet subsystem */ - eth_register(dev); - - /* Get MAC address */ - if ((addr_str = getenv("ethaddr")) != NULL) { - for (i = 0; i < 6; i++) { - addr[i] = - addr_str ? simple_strtoul(addr_str, &end, 16) : 0; - if (addr_str) { - addr_str = (*end) ? end + 1 : end; - } - } - } else { - /* No ethaddr set */ - return -EINVAL; - } - - /* set and remember MAC address */ - greth_set_hwaddr(greth, addr); - - debug("GRETH[%p]: Initialized successfully\n", greth->regs); - return 0; -} |