| /* 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 <net.h> | |
| #include <netdev.h> | |
| #include <malloc.h> | |
| #include <asm/processor.h> | |
| #include <ambapp.h> | |
| #include <asm/leon.h> | |
| #include "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 | |
| /* 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 = usec2ticks(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 */ | |
| NetReceive((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 */ | |
| if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_ETHMAC, &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) { | |
| sprintf(dev->name, "GRETH_10/100/GB"); | |
| } else { | |
| sprintf(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 { | |
| /* HW Address not found in environment, Set default HW address */ | |
| addr[0] = GRETH_HWADDR_0; /* MSB */ | |
| addr[1] = GRETH_HWADDR_1; | |
| addr[2] = GRETH_HWADDR_2; | |
| addr[3] = GRETH_HWADDR_3; | |
| addr[4] = GRETH_HWADDR_4; | |
| addr[5] = GRETH_HWADDR_5; /* LSB */ | |
| } | |
| /* set and remember MAC address */ | |
| greth_set_hwaddr(greth, addr); | |
| debug("GRETH[%p]: Initialized successfully\n", greth->regs); | |
| return 0; | |
| } |