123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /*
- * tsec.c
- * Motorola Three Speed Ethernet Controller driver
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * (C) Copyright 2003, Motorola, Inc.
- * maintained by Xianghua Xiao (x.xiao@motorola.com)
- * author Andy Fleming
- *
- */
- #include <config.h>
- #include <mpc85xx.h>
- #include <common.h>
- #include <malloc.h>
- #include <net.h>
- #include <command.h>
- #if defined(CONFIG_TSEC_ENET)
- #include "tsec.h"
- #define TX_BUF_CNT 2
- #undef TSEC_DEBUG
- #ifdef TSEC_DEBUG
- #define DBGPRINT(x) printf(x)
- #else
- #define DBGPRINT(x)
- #endif
- static uint rxIdx; /* index of the current RX buffer */
- static uint txIdx; /* index of the current TX buffer */
- typedef volatile struct rtxbd {
- txbd8_t txbd[TX_BUF_CNT];
- rxbd8_t rxbd[PKTBUFSRX];
- } RTXBD;
- #ifdef __GNUC__
- static RTXBD rtx __attribute__ ((aligned(8)));
- #else
- #error "rtx must be 64-bit aligned"
- #endif
- static int tsec_send(struct eth_device* dev, volatile void *packet, int length);
- static int tsec_recv(struct eth_device* dev);
- static int tsec_init(struct eth_device* dev, bd_t * bd);
- static void tsec_halt(struct eth_device* dev);
- static void init_registers(tsec_t *regs);
- static void startup_tsec(tsec_t *regs);
- static void init_phy(tsec_t *regs);
- /* Initialize device structure. returns 0 on failure, 1 on
- * success */
- int tsec_initialize(bd_t *bis)
- {
- struct eth_device* dev;
- int i;
- dev = (struct eth_device*) malloc(sizeof *dev);
- if(dev == NULL)
- return 0;
- memset(dev, 0, sizeof *dev);
- sprintf(dev->name, "MOTOROLA ETHERNET");
- dev->iobase = 0;
- dev->priv = 0;
- dev->init = tsec_init;
- dev->halt = tsec_halt;
- dev->send = tsec_send;
- dev->recv = tsec_recv;
- /* Tell u-boot to get the addr from the env */
- for(i=0;i<6;i++)
- dev->enetaddr[i] = 0;
- eth_register(dev);
- return 1;
- }
- /* Initializes data structures and registers for the controller,
- * and brings the interface up */
- int tsec_init(struct eth_device* dev, bd_t * bd)
- {
- tsec_t *regs;
- uint tempval;
- char tmpbuf[MAC_ADDR_LEN];
- int i;
- regs = (tsec_t *)(TSEC_BASE_ADDR);
- /* Make sure the controller is stopped */
- tsec_halt(dev);
- /* Reset the MAC */
- regs->maccfg1 |= MACCFG1_SOFT_RESET;
- /* Clear MACCFG1[Soft_Reset] */
- regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
- /* Init MACCFG2. Defaults to GMII/MII */
- regs->maccfg2 = MACCFG2_INIT_SETTINGS;
- /* Init ECNTRL */
- regs->ecntrl = ECNTRL_INIT_SETTINGS;
- /* Copy the station address into the address registers.
- * Backwards, because little endian MACS are dumb */
- for(i=0;i<MAC_ADDR_LEN;i++) {
- tmpbuf[MAC_ADDR_LEN - 1 - i] = bd->bi_enetaddr[i];
- }
- (uint)(regs->macstnaddr1) = *((uint *)(tmpbuf));
- tempval = *((uint *)(tmpbuf +4));
- (uint)(regs->macstnaddr2) = tempval;
- /* Initialize the PHY */
- init_phy(regs);
- /* reset the indices to zero */
- rxIdx = 0;
- txIdx = 0;
- /* Clear out (for the most part) the other registers */
- init_registers(regs);
- /* Ready the device for tx/rx */
- startup_tsec(regs);
- return 1;
- }
- /* Reads from the register at offset in the PHY at phyid, */
- /* using the register set defined in regbase. It waits until the */
- /* bits in the miimstat are valid (miimind notvalid bit cleared), */
- /* and then passes those bits on to the variable specified in */
- /* value */
- /* Before it does the read, it needs to clear the command field */
- uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset)
- {
- uint value;
- /* Put the address of the phy, and the register number into
- * MIIMADD
- */
- regbase->miimadd = (phyid << 8) | offset;
- /* Clear the command register, and wait */
- regbase->miimcom = 0;
- asm("msync");
- /* Initiate a read command, and wait */
- regbase->miimcom = MIIM_READ_COMMAND;
- asm("msync");
- /* Wait for the the indication that the read is done */
- while((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY)));
- /* Grab the value read from the PHY */
- value = regbase->miimstat;
- return value;
- }
- /* Setup the PHY */
- static void init_phy(tsec_t *regs)
- {
- uint testval;
- unsigned int timeout = TSEC_TIMEOUT;
- /* Assign a Physical address to the TBI */
- regs->tbipa=TBIPA_VALUE;
- /* reset the management interface */
- regs->miimcfg=MIIMCFG_RESET;
- regs->miimcfg=MIIMCFG_INIT_VALUE;
- /* Wait until the bus is free */
- while(regs->miimind & MIIMIND_BUSY);
- #ifdef CONFIG_PHY_CIS8201
- /* override PHY config settings */
- write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT);
- /* Set up interface mode */
- write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT);
- #endif
- /* Set the PHY to gigabit, full duplex, Auto-negotiate */
- write_phy_reg(regs, 0, MIIM_CONTROL, MIIM_CONTROL_INIT);
- /* Wait until TBI_STATUS indicates AN is done */
- DBGPRINT("Waiting for Auto-negotiation to complete\n");
- testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS);
- while((!(testval & MIIM_TBI_STATUS_AN_DONE))&& timeout--) {
- testval=read_phy_reg(regs, 0, MIIM_TBI_STATUS);
- }
- if(testval & MIIM_TBI_STATUS_AN_DONE)
- DBGPRINT("Auto-negotiation done\n");
- else
- DBGPRINT("Auto-negotiation timed-out.\n");
- #ifdef CONFIG_PHY_CIS8201
- /* Find out what duplexity (duplicity?) we have */
- /* Read it twice to make sure */
- testval=read_phy_reg(regs, 0, MIIM_AUX_CONSTAT);
- if(testval & MIIM_AUXCONSTAT_DUPLEX) {
- DBGPRINT("Enet starting in full duplex\n");
- regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
- } else {
- DBGPRINT("Enet starting in half duplex\n");
- regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
- }
- /* Also, we look to see what speed we are at
- * if Gigabit, MACCFG2 goes in GMII, otherwise,
- * MII mode.
- */
- if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) {
- if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100)
- DBGPRINT("Enet starting in 100BT\n");
- else
- DBGPRINT("Enet starting in 10BT\n");
- /* mark the mode in MACCFG2 */
- regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
- } else {
- DBGPRINT("Enet starting in 1000BT\n");
- }
- #endif
- #ifdef CONFIG_PHY_M88E1011
- /* Read the PHY to see what speed and duplex we are */
- testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS);
- timeout = TSEC_TIMEOUT;
- while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) {
- testval = read_phy_reg(regs,0,MIIM_PHY_STATUS);
- }
- if(!(testval & MIIM_PHYSTAT_SPDDONE))
- DBGPRINT("Enet: Speed not resolved\n");
- testval=read_phy_reg(regs, 0, MIIM_PHY_STATUS);
- if(testval & MIIM_PHYSTAT_DUPLEX) {
- DBGPRINT("Enet starting in Full Duplex\n");
- regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
- } else {
- DBGPRINT("Enet starting in Half Duplex\n");
- regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX;
- }
- if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) {
- if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100)
- DBGPRINT("Enet starting in 100BT\n");
- else
- DBGPRINT("Enet starting in 10BT\n");
- regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII);
- } else {
- DBGPRINT("Enet starting in 1000BT\n");
- }
- #endif
- }
- static void init_registers(tsec_t *regs)
- {
- /* Clear IEVENT */
- regs->ievent = IEVENT_INIT_CLEAR;
- regs->imask = IMASK_INIT_CLEAR;
- regs->hash.iaddr0 = 0;
- regs->hash.iaddr1 = 0;
- regs->hash.iaddr2 = 0;
- regs->hash.iaddr3 = 0;
- regs->hash.iaddr4 = 0;
- regs->hash.iaddr5 = 0;
- regs->hash.iaddr6 = 0;
- regs->hash.iaddr7 = 0;
- regs->hash.gaddr0 = 0;
- regs->hash.gaddr1 = 0;
- regs->hash.gaddr2 = 0;
- regs->hash.gaddr3 = 0;
- regs->hash.gaddr4 = 0;
- regs->hash.gaddr5 = 0;
- regs->hash.gaddr6 = 0;
- regs->hash.gaddr7 = 0;
- regs->rctrl = 0x00000000;
- /* Init RMON mib registers */
- memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
- regs->rmon.cam1 = 0xffffffff;
- regs->rmon.cam2 = 0xffffffff;
- regs->mrblr = MRBLR_INIT_SETTINGS;
- regs->minflr = MINFLR_INIT_SETTINGS;
- regs->attr = ATTR_INIT_SETTINGS;
- regs->attreli = ATTRELI_INIT_SETTINGS;
- }
- static void startup_tsec(tsec_t *regs)
- {
- int i;
- /* Point to the buffer descriptors */
- regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
- regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
- /* Initialize the Rx Buffer descriptors */
- for (i = 0; i < PKTBUFSRX; i++) {
- rtx.rxbd[i].status = RXBD_EMPTY;
- rtx.rxbd[i].length = 0;
- rtx.rxbd[i].bufPtr = (uint)NetRxPackets[i];
- }
- rtx.rxbd[PKTBUFSRX -1].status |= RXBD_WRAP;
- /* Initialize the TX Buffer Descriptors */
- for(i=0; i<TX_BUF_CNT; i++) {
- rtx.txbd[i].status = 0;
- rtx.txbd[i].length = 0;
- rtx.txbd[i].bufPtr = 0;
- }
- rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP;
- /* Enable Transmit and Receive */
- regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- /* Tell the DMA it is clear to go */
- regs->dmactrl |= DMACTRL_INIT_SETTINGS;
- regs->tstat = TSTAT_CLEAR_THALT;
- regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
- }
- /* This returns the status bits of the device. The return value
- * is never checked, and this is what the 8260 driver did, so we
- * do the same. Presumably, this would be zero if there were no
- * errors */
- static int tsec_send(struct eth_device* dev, volatile void *packet, int length)
- {
- int i;
- int result = 0;
- tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR);
- /* Find an empty buffer descriptor */
- for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- DBGPRINT("tsec: tx buffers full\n");
- return result;
- }
- }
- rtx.txbd[txIdx].bufPtr = (uint)packet;
- rtx.txbd[txIdx].length = length;
- rtx.txbd[txIdx].status |= (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
- /* Tell the DMA to go */
- regs->tstat = TSTAT_CLEAR_THALT;
- /* Wait for buffer to be transmitted */
- for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- DBGPRINT("tsec: tx error\n");
- return result;
- }
- }
- txIdx = (txIdx + 1) % TX_BUF_CNT;
- result = rtx.txbd[txIdx].status & TXBD_STATS;
- return result;
- }
- static int tsec_recv(struct eth_device* dev)
- {
- int length;
- tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
- while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
- length = rtx.rxbd[rxIdx].length;
- /* Send the packet up if there were no errors */
- if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
- NetReceive(NetRxPackets[rxIdx], length - 4);
- }
- rtx.rxbd[rxIdx].length = 0;
- /* Set the wrap bit if this is the last element in the list */
- rtx.rxbd[rxIdx].status = RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
- rxIdx = (rxIdx + 1) % PKTBUFSRX;
- }
- if(regs->ievent&IEVENT_BSY) {
- regs->ievent = IEVENT_BSY;
- regs->rstat = RSTAT_CLEAR_RHALT;
- }
- return -1;
- }
- static void tsec_halt(struct eth_device* dev)
- {
- tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR);
- regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
- regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
- while(!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)));
- regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
- }
- #endif /* CONFIG_TSEC_ENET */
|