12439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 22439e4bfSJean-Christophe PLAGNIOL-VILLARD * Freescale Three Speed Ethernet Controller driver 32439e4bfSJean-Christophe PLAGNIOL-VILLARD * 42439e4bfSJean-Christophe PLAGNIOL-VILLARD * This software may be used and distributed according to the 52439e4bfSJean-Christophe PLAGNIOL-VILLARD * terms of the GNU Public License, Version 2, incorporated 62439e4bfSJean-Christophe PLAGNIOL-VILLARD * herein by reference. 72439e4bfSJean-Christophe PLAGNIOL-VILLARD * 8a32a6be2SMingkai Hu * Copyright 2004-2011 Freescale Semiconductor, Inc. 92439e4bfSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2003, Motorola, Inc. 102439e4bfSJean-Christophe PLAGNIOL-VILLARD * author Andy Fleming 112439e4bfSJean-Christophe PLAGNIOL-VILLARD * 122439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 132439e4bfSJean-Christophe PLAGNIOL-VILLARD 142439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <config.h> 152439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 162439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 172439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 182439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <command.h> 19dd3d1f56SAndy Fleming #include <tsec.h> 20063c1263SAndy Fleming #include <fsl_mdio.h> 210d071cddSKim Phillips #include <asm/errno.h> 22*aada81deSchenhui zhao #include <asm/processor.h> 232439e4bfSJean-Christophe PLAGNIOL-VILLARD 242439e4bfSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR; 252439e4bfSJean-Christophe PLAGNIOL-VILLARD 262439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_BUF_CNT 2 272439e4bfSJean-Christophe PLAGNIOL-VILLARD 282439e4bfSJean-Christophe PLAGNIOL-VILLARD static uint rxIdx; /* index of the current RX buffer */ 292439e4bfSJean-Christophe PLAGNIOL-VILLARD static uint txIdx; /* index of the current TX buffer */ 302439e4bfSJean-Christophe PLAGNIOL-VILLARD 312439e4bfSJean-Christophe PLAGNIOL-VILLARD typedef volatile struct rtxbd { 322439e4bfSJean-Christophe PLAGNIOL-VILLARD txbd8_t txbd[TX_BUF_CNT]; 332439e4bfSJean-Christophe PLAGNIOL-VILLARD rxbd8_t rxbd[PKTBUFSRX]; 342439e4bfSJean-Christophe PLAGNIOL-VILLARD } RTXBD; 352439e4bfSJean-Christophe PLAGNIOL-VILLARD 3675b9d4aeSAndy Fleming #define MAXCONTROLLERS (8) 372439e4bfSJean-Christophe PLAGNIOL-VILLARD 382439e4bfSJean-Christophe PLAGNIOL-VILLARD static struct tsec_private *privlist[MAXCONTROLLERS]; 3975b9d4aeSAndy Fleming static int num_tsecs = 0; 402439e4bfSJean-Christophe PLAGNIOL-VILLARD 412439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef __GNUC__ 422439e4bfSJean-Christophe PLAGNIOL-VILLARD static RTXBD rtx __attribute__ ((aligned(8))); 432439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 442439e4bfSJean-Christophe PLAGNIOL-VILLARD #error "rtx must be 64-bit aligned" 452439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 462439e4bfSJean-Christophe PLAGNIOL-VILLARD 47*aada81deSchenhui zhao static int tsec_send(struct eth_device *dev, 48*aada81deSchenhui zhao volatile void *packet, int length); 49*aada81deSchenhui zhao 5075b9d4aeSAndy Fleming /* Default initializations for TSEC controllers. */ 5175b9d4aeSAndy Fleming 5275b9d4aeSAndy Fleming static struct tsec_info_struct tsec_info[] = { 5375b9d4aeSAndy Fleming #ifdef CONFIG_TSEC1 5475b9d4aeSAndy Fleming STD_TSEC_INFO(1), /* TSEC1 */ 5575b9d4aeSAndy Fleming #endif 5675b9d4aeSAndy Fleming #ifdef CONFIG_TSEC2 5775b9d4aeSAndy Fleming STD_TSEC_INFO(2), /* TSEC2 */ 5875b9d4aeSAndy Fleming #endif 5975b9d4aeSAndy Fleming #ifdef CONFIG_MPC85XX_FEC 6075b9d4aeSAndy Fleming { 6175b9d4aeSAndy Fleming .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000), 6275b9d4aeSAndy Fleming .devname = CONFIG_MPC85XX_FEC_NAME, 6375b9d4aeSAndy Fleming .phyaddr = FEC_PHY_ADDR, 64063c1263SAndy Fleming .flags = FEC_FLAGS, 65063c1263SAndy Fleming .mii_devname = DEFAULT_MII_NAME 6675b9d4aeSAndy Fleming }, /* FEC */ 6775b9d4aeSAndy Fleming #endif 6875b9d4aeSAndy Fleming #ifdef CONFIG_TSEC3 6975b9d4aeSAndy Fleming STD_TSEC_INFO(3), /* TSEC3 */ 7075b9d4aeSAndy Fleming #endif 7175b9d4aeSAndy Fleming #ifdef CONFIG_TSEC4 7275b9d4aeSAndy Fleming STD_TSEC_INFO(4), /* TSEC4 */ 7375b9d4aeSAndy Fleming #endif 7475b9d4aeSAndy Fleming }; 7575b9d4aeSAndy Fleming 762abe361cSAndy Fleming #define TBIANA_SETTINGS ( \ 772abe361cSAndy Fleming TBIANA_ASYMMETRIC_PAUSE \ 782abe361cSAndy Fleming | TBIANA_SYMMETRIC_PAUSE \ 792abe361cSAndy Fleming | TBIANA_FULL_DUPLEX \ 802abe361cSAndy Fleming ) 812abe361cSAndy Fleming 8290b5bf21SFelix Radensky /* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ 8390b5bf21SFelix Radensky #ifndef CONFIG_TSEC_TBICR_SETTINGS 8472c96a68SKumar Gala #define CONFIG_TSEC_TBICR_SETTINGS ( \ 852abe361cSAndy Fleming TBICR_PHY_RESET \ 8672c96a68SKumar Gala | TBICR_ANEG_ENABLE \ 872abe361cSAndy Fleming | TBICR_FULL_DUPLEX \ 882abe361cSAndy Fleming | TBICR_SPEED1_SET \ 892abe361cSAndy Fleming ) 9090b5bf21SFelix Radensky #endif /* CONFIG_TSEC_TBICR_SETTINGS */ 9146e91674SPeter Tyser 922abe361cSAndy Fleming /* Configure the TBI for SGMII operation */ 932abe361cSAndy Fleming static void tsec_configure_serdes(struct tsec_private *priv) 942abe361cSAndy Fleming { 95c6dbdfdaSPeter Tyser /* Access TBI PHY registers at given TSEC register offset as opposed 96c6dbdfdaSPeter Tyser * to the register offset used for external PHY accesses */ 97063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 98063c1263SAndy Fleming 0, TBI_ANA, TBIANA_SETTINGS); 99063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 100063c1263SAndy Fleming 0, TBI_TBICON, TBICON_CLK_SELECT); 101063c1263SAndy Fleming tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), 102063c1263SAndy Fleming 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD 1052439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_MCAST_TFTP 1062439e4bfSJean-Christophe PLAGNIOL-VILLARD 1072439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD 1092439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Set the appropriate hash bit for the given addr */ 1102439e4bfSJean-Christophe PLAGNIOL-VILLARD 1112439e4bfSJean-Christophe PLAGNIOL-VILLARD /* The algorithm works like so: 1122439e4bfSJean-Christophe PLAGNIOL-VILLARD * 1) Take the Destination Address (ie the multicast address), and 1132439e4bfSJean-Christophe PLAGNIOL-VILLARD * do a CRC on it (little endian), and reverse the bits of the 1142439e4bfSJean-Christophe PLAGNIOL-VILLARD * result. 1152439e4bfSJean-Christophe PLAGNIOL-VILLARD * 2) Use the 8 most significant bits as a hash into a 256-entry 1162439e4bfSJean-Christophe PLAGNIOL-VILLARD * table. The table is controlled through 8 32-bit registers: 1172439e4bfSJean-Christophe PLAGNIOL-VILLARD * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is 1182439e4bfSJean-Christophe PLAGNIOL-VILLARD * gaddr7. This means that the 3 most significant bits in the 1192439e4bfSJean-Christophe PLAGNIOL-VILLARD * hash index which gaddr register to use, and the 5 other bits 1202439e4bfSJean-Christophe PLAGNIOL-VILLARD * indicate which bit (assuming an IBM numbering scheme, which 1212439e4bfSJean-Christophe PLAGNIOL-VILLARD * for PowerPC (tm) is usually the case) in the tregister holds 1222439e4bfSJean-Christophe PLAGNIOL-VILLARD * the entry. */ 1232439e4bfSJean-Christophe PLAGNIOL-VILLARD static int 1242439e4bfSJean-Christophe PLAGNIOL-VILLARD tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) 1252439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1262439e4bfSJean-Christophe PLAGNIOL-VILLARD struct tsec_private *priv = privlist[1]; 1272439e4bfSJean-Christophe PLAGNIOL-VILLARD volatile tsec_t *regs = priv->regs; 1282439e4bfSJean-Christophe PLAGNIOL-VILLARD volatile u32 *reg_array, value; 1292439e4bfSJean-Christophe PLAGNIOL-VILLARD u8 result, whichbit, whichreg; 1302439e4bfSJean-Christophe PLAGNIOL-VILLARD 1312439e4bfSJean-Christophe PLAGNIOL-VILLARD result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); 1322439e4bfSJean-Christophe PLAGNIOL-VILLARD whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ 1332439e4bfSJean-Christophe PLAGNIOL-VILLARD whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ 1342439e4bfSJean-Christophe PLAGNIOL-VILLARD value = (1 << (31-whichbit)); 1352439e4bfSJean-Christophe PLAGNIOL-VILLARD 1362439e4bfSJean-Christophe PLAGNIOL-VILLARD reg_array = &(regs->hash.gaddr0); 1372439e4bfSJean-Christophe PLAGNIOL-VILLARD 1382439e4bfSJean-Christophe PLAGNIOL-VILLARD if (set) { 1392439e4bfSJean-Christophe PLAGNIOL-VILLARD reg_array[whichreg] |= value; 1402439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 1412439e4bfSJean-Christophe PLAGNIOL-VILLARD reg_array[whichreg] &= ~value; 1422439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1432439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 1442439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1452439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* Multicast TFTP ? */ 14690751910SMingkai Hu 14790751910SMingkai Hu /* Initialized required registers to appropriate values, zeroing 14890751910SMingkai Hu * those we don't care about (unless zero is bad, in which case, 14990751910SMingkai Hu * choose a more appropriate value) 15090751910SMingkai Hu */ 15190751910SMingkai Hu static void init_registers(tsec_t *regs) 15290751910SMingkai Hu { 15390751910SMingkai Hu /* Clear IEVENT */ 15490751910SMingkai Hu out_be32(®s->ievent, IEVENT_INIT_CLEAR); 15590751910SMingkai Hu 15690751910SMingkai Hu out_be32(®s->imask, IMASK_INIT_CLEAR); 15790751910SMingkai Hu 15890751910SMingkai Hu out_be32(®s->hash.iaddr0, 0); 15990751910SMingkai Hu out_be32(®s->hash.iaddr1, 0); 16090751910SMingkai Hu out_be32(®s->hash.iaddr2, 0); 16190751910SMingkai Hu out_be32(®s->hash.iaddr3, 0); 16290751910SMingkai Hu out_be32(®s->hash.iaddr4, 0); 16390751910SMingkai Hu out_be32(®s->hash.iaddr5, 0); 16490751910SMingkai Hu out_be32(®s->hash.iaddr6, 0); 16590751910SMingkai Hu out_be32(®s->hash.iaddr7, 0); 16690751910SMingkai Hu 16790751910SMingkai Hu out_be32(®s->hash.gaddr0, 0); 16890751910SMingkai Hu out_be32(®s->hash.gaddr1, 0); 16990751910SMingkai Hu out_be32(®s->hash.gaddr2, 0); 17090751910SMingkai Hu out_be32(®s->hash.gaddr3, 0); 17190751910SMingkai Hu out_be32(®s->hash.gaddr4, 0); 17290751910SMingkai Hu out_be32(®s->hash.gaddr5, 0); 17390751910SMingkai Hu out_be32(®s->hash.gaddr6, 0); 17490751910SMingkai Hu out_be32(®s->hash.gaddr7, 0); 17590751910SMingkai Hu 17690751910SMingkai Hu out_be32(®s->rctrl, 0x00000000); 17790751910SMingkai Hu 17890751910SMingkai Hu /* Init RMON mib registers */ 17990751910SMingkai Hu memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); 18090751910SMingkai Hu 18190751910SMingkai Hu out_be32(®s->rmon.cam1, 0xffffffff); 18290751910SMingkai Hu out_be32(®s->rmon.cam2, 0xffffffff); 18390751910SMingkai Hu 18490751910SMingkai Hu out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); 18590751910SMingkai Hu 18690751910SMingkai Hu out_be32(®s->minflr, MINFLR_INIT_SETTINGS); 18790751910SMingkai Hu 18890751910SMingkai Hu out_be32(®s->attr, ATTR_INIT_SETTINGS); 18990751910SMingkai Hu out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); 19090751910SMingkai Hu 19190751910SMingkai Hu } 19290751910SMingkai Hu 19390751910SMingkai Hu /* Configure maccfg2 based on negotiated speed and duplex 19490751910SMingkai Hu * reported by PHY handling code 19590751910SMingkai Hu */ 196063c1263SAndy Fleming static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) 19790751910SMingkai Hu { 19890751910SMingkai Hu tsec_t *regs = priv->regs; 19990751910SMingkai Hu u32 ecntrl, maccfg2; 20090751910SMingkai Hu 201063c1263SAndy Fleming if (!phydev->link) { 202063c1263SAndy Fleming printf("%s: No link.\n", phydev->dev->name); 20390751910SMingkai Hu return; 20490751910SMingkai Hu } 20590751910SMingkai Hu 20690751910SMingkai Hu /* clear all bits relative with interface mode */ 20790751910SMingkai Hu ecntrl = in_be32(®s->ecntrl); 20890751910SMingkai Hu ecntrl &= ~ECNTRL_R100; 20990751910SMingkai Hu 21090751910SMingkai Hu maccfg2 = in_be32(®s->maccfg2); 21190751910SMingkai Hu maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); 21290751910SMingkai Hu 213063c1263SAndy Fleming if (phydev->duplex) 21490751910SMingkai Hu maccfg2 |= MACCFG2_FULL_DUPLEX; 21590751910SMingkai Hu 216063c1263SAndy Fleming switch (phydev->speed) { 21790751910SMingkai Hu case 1000: 21890751910SMingkai Hu maccfg2 |= MACCFG2_GMII; 21990751910SMingkai Hu break; 22090751910SMingkai Hu case 100: 22190751910SMingkai Hu case 10: 22290751910SMingkai Hu maccfg2 |= MACCFG2_MII; 22390751910SMingkai Hu 22490751910SMingkai Hu /* Set R100 bit in all modes although 22590751910SMingkai Hu * it is only used in RGMII mode 22690751910SMingkai Hu */ 227063c1263SAndy Fleming if (phydev->speed == 100) 22890751910SMingkai Hu ecntrl |= ECNTRL_R100; 22990751910SMingkai Hu break; 23090751910SMingkai Hu default: 231063c1263SAndy Fleming printf("%s: Speed was bad\n", phydev->dev->name); 23290751910SMingkai Hu break; 23390751910SMingkai Hu } 23490751910SMingkai Hu 23590751910SMingkai Hu out_be32(®s->ecntrl, ecntrl); 23690751910SMingkai Hu out_be32(®s->maccfg2, maccfg2); 23790751910SMingkai Hu 238063c1263SAndy Fleming printf("Speed: %d, %s duplex%s\n", phydev->speed, 239063c1263SAndy Fleming (phydev->duplex) ? "full" : "half", 240063c1263SAndy Fleming (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); 24190751910SMingkai Hu } 24290751910SMingkai Hu 243*aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 244*aada81deSchenhui zhao /* 245*aada81deSchenhui zhao * When MACCFG1[Rx_EN] is enabled during system boot as part 246*aada81deSchenhui zhao * of the eTSEC port initialization sequence, 247*aada81deSchenhui zhao * the eTSEC Rx logic may not be properly initialized. 248*aada81deSchenhui zhao */ 249*aada81deSchenhui zhao void redundant_init(struct eth_device *dev) 250*aada81deSchenhui zhao { 251*aada81deSchenhui zhao struct tsec_private *priv = dev->priv; 252*aada81deSchenhui zhao tsec_t *regs = priv->regs; 253*aada81deSchenhui zhao uint t, count = 0; 254*aada81deSchenhui zhao int fail = 1; 255*aada81deSchenhui zhao static const u8 pkt[] = { 256*aada81deSchenhui zhao 0x00, 0x1e, 0x4f, 0x12, 0xcb, 0x2c, 0x00, 0x25, 257*aada81deSchenhui zhao 0x64, 0xbb, 0xd1, 0xab, 0x08, 0x00, 0x45, 0x00, 258*aada81deSchenhui zhao 0x00, 0x5c, 0xdd, 0x22, 0x00, 0x00, 0x80, 0x01, 259*aada81deSchenhui zhao 0x1f, 0x71, 0x0a, 0xc1, 0x14, 0x22, 0x0a, 0xc1, 260*aada81deSchenhui zhao 0x14, 0x6a, 0x08, 0x00, 0xef, 0x7e, 0x02, 0x00, 261*aada81deSchenhui zhao 0x94, 0x05, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 262*aada81deSchenhui zhao 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 263*aada81deSchenhui zhao 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 264*aada81deSchenhui zhao 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 265*aada81deSchenhui zhao 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 266*aada81deSchenhui zhao 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 267*aada81deSchenhui zhao 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 268*aada81deSchenhui zhao 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 269*aada81deSchenhui zhao 0x71, 0x72}; 270*aada81deSchenhui zhao 271*aada81deSchenhui zhao /* Enable promiscuous mode */ 272*aada81deSchenhui zhao setbits_be32(®s->rctrl, 0x8); 273*aada81deSchenhui zhao /* Enable loopback mode */ 274*aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 275*aada81deSchenhui zhao /* Enable transmit and receive */ 276*aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 277*aada81deSchenhui zhao 278*aada81deSchenhui zhao /* Tell the DMA it is clear to go */ 279*aada81deSchenhui zhao setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 280*aada81deSchenhui zhao out_be32(®s->tstat, TSTAT_CLEAR_THALT); 281*aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 282*aada81deSchenhui zhao clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 283*aada81deSchenhui zhao 284*aada81deSchenhui zhao do { 285*aada81deSchenhui zhao tsec_send(dev, (void *)pkt, sizeof(pkt)); 286*aada81deSchenhui zhao 287*aada81deSchenhui zhao /* Wait for buffer to be received */ 288*aada81deSchenhui zhao for (t = 0; rtx.rxbd[rxIdx].status & RXBD_EMPTY; t++) { 289*aada81deSchenhui zhao if (t >= 10 * TOUT_LOOP) { 290*aada81deSchenhui zhao printf("%s: tsec: rx error\n", dev->name); 291*aada81deSchenhui zhao break; 292*aada81deSchenhui zhao } 293*aada81deSchenhui zhao } 294*aada81deSchenhui zhao 295*aada81deSchenhui zhao if (!memcmp(pkt, (void *)NetRxPackets[rxIdx], sizeof(pkt))) 296*aada81deSchenhui zhao fail = 0; 297*aada81deSchenhui zhao 298*aada81deSchenhui zhao rtx.rxbd[rxIdx].length = 0; 299*aada81deSchenhui zhao rtx.rxbd[rxIdx].status = 300*aada81deSchenhui zhao RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); 301*aada81deSchenhui zhao rxIdx = (rxIdx + 1) % PKTBUFSRX; 302*aada81deSchenhui zhao 303*aada81deSchenhui zhao if (in_be32(®s->ievent) & IEVENT_BSY) { 304*aada81deSchenhui zhao out_be32(®s->ievent, IEVENT_BSY); 305*aada81deSchenhui zhao out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 306*aada81deSchenhui zhao } 307*aada81deSchenhui zhao if (fail) { 308*aada81deSchenhui zhao printf("loopback recv packet error!\n"); 309*aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_RX_EN); 310*aada81deSchenhui zhao udelay(1000); 311*aada81deSchenhui zhao setbits_be32(®s->maccfg1, MACCFG1_RX_EN); 312*aada81deSchenhui zhao } 313*aada81deSchenhui zhao } while ((count++ < 4) && (fail == 1)); 314*aada81deSchenhui zhao 315*aada81deSchenhui zhao if (fail) 316*aada81deSchenhui zhao panic("eTSEC init fail!\n"); 317*aada81deSchenhui zhao /* Disable promiscuous mode */ 318*aada81deSchenhui zhao clrbits_be32(®s->rctrl, 0x8); 319*aada81deSchenhui zhao /* Disable loopback mode */ 320*aada81deSchenhui zhao clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK); 321*aada81deSchenhui zhao } 322*aada81deSchenhui zhao #endif 323*aada81deSchenhui zhao 32490751910SMingkai Hu /* Set up the buffers and their descriptors, and bring up the 32590751910SMingkai Hu * interface 32690751910SMingkai Hu */ 32790751910SMingkai Hu static void startup_tsec(struct eth_device *dev) 32890751910SMingkai Hu { 32990751910SMingkai Hu int i; 33090751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 33190751910SMingkai Hu tsec_t *regs = priv->regs; 33290751910SMingkai Hu 333063c1263SAndy Fleming /* reset the indices to zero */ 334063c1263SAndy Fleming rxIdx = 0; 335063c1263SAndy Fleming txIdx = 0; 336*aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 337*aada81deSchenhui zhao uint svr; 338*aada81deSchenhui zhao #endif 339063c1263SAndy Fleming 34090751910SMingkai Hu /* Point to the buffer descriptors */ 34190751910SMingkai Hu out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); 34290751910SMingkai Hu out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); 34390751910SMingkai Hu 34490751910SMingkai Hu /* Initialize the Rx Buffer descriptors */ 34590751910SMingkai Hu for (i = 0; i < PKTBUFSRX; i++) { 34690751910SMingkai Hu rtx.rxbd[i].status = RXBD_EMPTY; 34790751910SMingkai Hu rtx.rxbd[i].length = 0; 34890751910SMingkai Hu rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i]; 34990751910SMingkai Hu } 35090751910SMingkai Hu rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; 35190751910SMingkai Hu 35290751910SMingkai Hu /* Initialize the TX Buffer Descriptors */ 35390751910SMingkai Hu for (i = 0; i < TX_BUF_CNT; i++) { 35490751910SMingkai Hu rtx.txbd[i].status = 0; 35590751910SMingkai Hu rtx.txbd[i].length = 0; 35690751910SMingkai Hu rtx.txbd[i].bufPtr = 0; 35790751910SMingkai Hu } 35890751910SMingkai Hu rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; 35990751910SMingkai Hu 360*aada81deSchenhui zhao #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 361*aada81deSchenhui zhao svr = get_svr(); 362*aada81deSchenhui zhao if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) 363*aada81deSchenhui zhao redundant_init(dev); 364*aada81deSchenhui zhao #endif 36590751910SMingkai Hu /* Enable Transmit and Receive */ 36690751910SMingkai Hu setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); 36790751910SMingkai Hu 36890751910SMingkai Hu /* Tell the DMA it is clear to go */ 36990751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); 37090751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 37190751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 37290751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 37390751910SMingkai Hu } 37490751910SMingkai Hu 37590751910SMingkai Hu /* This returns the status bits of the device. The return value 37690751910SMingkai Hu * is never checked, and this is what the 8260 driver did, so we 37790751910SMingkai Hu * do the same. Presumably, this would be zero if there were no 37890751910SMingkai Hu * errors 37990751910SMingkai Hu */ 38090751910SMingkai Hu static int tsec_send(struct eth_device *dev, volatile void *packet, int length) 38190751910SMingkai Hu { 38290751910SMingkai Hu int i; 38390751910SMingkai Hu int result = 0; 38490751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 38590751910SMingkai Hu tsec_t *regs = priv->regs; 38690751910SMingkai Hu 38790751910SMingkai Hu /* Find an empty buffer descriptor */ 38890751910SMingkai Hu for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { 38990751910SMingkai Hu if (i >= TOUT_LOOP) { 39090751910SMingkai Hu debug("%s: tsec: tx buffers full\n", dev->name); 39190751910SMingkai Hu return result; 39290751910SMingkai Hu } 39390751910SMingkai Hu } 39490751910SMingkai Hu 39590751910SMingkai Hu rtx.txbd[txIdx].bufPtr = (uint) packet; 39690751910SMingkai Hu rtx.txbd[txIdx].length = length; 39790751910SMingkai Hu rtx.txbd[txIdx].status |= 39890751910SMingkai Hu (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); 39990751910SMingkai Hu 40090751910SMingkai Hu /* Tell the DMA to go */ 40190751910SMingkai Hu out_be32(®s->tstat, TSTAT_CLEAR_THALT); 40290751910SMingkai Hu 40390751910SMingkai Hu /* Wait for buffer to be transmitted */ 40490751910SMingkai Hu for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { 40590751910SMingkai Hu if (i >= TOUT_LOOP) { 40690751910SMingkai Hu debug("%s: tsec: tx error\n", dev->name); 40790751910SMingkai Hu return result; 40890751910SMingkai Hu } 40990751910SMingkai Hu } 41090751910SMingkai Hu 41190751910SMingkai Hu txIdx = (txIdx + 1) % TX_BUF_CNT; 41290751910SMingkai Hu result = rtx.txbd[txIdx].status & TXBD_STATS; 41390751910SMingkai Hu 41490751910SMingkai Hu return result; 41590751910SMingkai Hu } 41690751910SMingkai Hu 41790751910SMingkai Hu static int tsec_recv(struct eth_device *dev) 41890751910SMingkai Hu { 41990751910SMingkai Hu int length; 42090751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 42190751910SMingkai Hu tsec_t *regs = priv->regs; 42290751910SMingkai Hu 42390751910SMingkai Hu while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { 42490751910SMingkai Hu 42590751910SMingkai Hu length = rtx.rxbd[rxIdx].length; 42690751910SMingkai Hu 42790751910SMingkai Hu /* Send the packet up if there were no errors */ 42890751910SMingkai Hu if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) { 42990751910SMingkai Hu NetReceive(NetRxPackets[rxIdx], length - 4); 43090751910SMingkai Hu } else { 43190751910SMingkai Hu printf("Got error %x\n", 43290751910SMingkai Hu (rtx.rxbd[rxIdx].status & RXBD_STATS)); 43390751910SMingkai Hu } 43490751910SMingkai Hu 43590751910SMingkai Hu rtx.rxbd[rxIdx].length = 0; 43690751910SMingkai Hu 43790751910SMingkai Hu /* Set the wrap bit if this is the last element in the list */ 43890751910SMingkai Hu rtx.rxbd[rxIdx].status = 43990751910SMingkai Hu RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); 44090751910SMingkai Hu 44190751910SMingkai Hu rxIdx = (rxIdx + 1) % PKTBUFSRX; 44290751910SMingkai Hu } 44390751910SMingkai Hu 44490751910SMingkai Hu if (in_be32(®s->ievent) & IEVENT_BSY) { 44590751910SMingkai Hu out_be32(®s->ievent, IEVENT_BSY); 44690751910SMingkai Hu out_be32(®s->rstat, RSTAT_CLEAR_RHALT); 44790751910SMingkai Hu } 44890751910SMingkai Hu 44990751910SMingkai Hu return -1; 45090751910SMingkai Hu 45190751910SMingkai Hu } 45290751910SMingkai Hu 45390751910SMingkai Hu /* Stop the interface */ 45490751910SMingkai Hu static void tsec_halt(struct eth_device *dev) 45590751910SMingkai Hu { 45690751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 45790751910SMingkai Hu tsec_t *regs = priv->regs; 45890751910SMingkai Hu 45990751910SMingkai Hu clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 46090751910SMingkai Hu setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); 46190751910SMingkai Hu 46290751910SMingkai Hu while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) 46390751910SMingkai Hu != (IEVENT_GRSC | IEVENT_GTSC)) 46490751910SMingkai Hu ; 46590751910SMingkai Hu 46690751910SMingkai Hu clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); 46790751910SMingkai Hu 46890751910SMingkai Hu /* Shut down the PHY, as needed */ 469063c1263SAndy Fleming phy_shutdown(priv->phydev); 47090751910SMingkai Hu } 47190751910SMingkai Hu 47290751910SMingkai Hu /* Initializes data structures and registers for the controller, 47390751910SMingkai Hu * and brings the interface up. Returns the link status, meaning 47490751910SMingkai Hu * that it returns success if the link is up, failure otherwise. 47590751910SMingkai Hu * This allows u-boot to find the first active controller. 47690751910SMingkai Hu */ 47790751910SMingkai Hu static int tsec_init(struct eth_device *dev, bd_t * bd) 47890751910SMingkai Hu { 47990751910SMingkai Hu uint tempval; 48090751910SMingkai Hu char tmpbuf[MAC_ADDR_LEN]; 48190751910SMingkai Hu int i; 48290751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 48390751910SMingkai Hu tsec_t *regs = priv->regs; 48490751910SMingkai Hu 48590751910SMingkai Hu /* Make sure the controller is stopped */ 48690751910SMingkai Hu tsec_halt(dev); 48790751910SMingkai Hu 48890751910SMingkai Hu /* Init MACCFG2. Defaults to GMII */ 48990751910SMingkai Hu out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); 49090751910SMingkai Hu 49190751910SMingkai Hu /* Init ECNTRL */ 49290751910SMingkai Hu out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); 49390751910SMingkai Hu 49490751910SMingkai Hu /* Copy the station address into the address registers. 49590751910SMingkai Hu * Backwards, because little endian MACS are dumb */ 49690751910SMingkai Hu for (i = 0; i < MAC_ADDR_LEN; i++) 49790751910SMingkai Hu tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; 49890751910SMingkai Hu 49990751910SMingkai Hu tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | 50090751910SMingkai Hu tmpbuf[3]; 50190751910SMingkai Hu 50290751910SMingkai Hu out_be32(®s->macstnaddr1, tempval); 50390751910SMingkai Hu 50490751910SMingkai Hu tempval = *((uint *) (tmpbuf + 4)); 50590751910SMingkai Hu 50690751910SMingkai Hu out_be32(®s->macstnaddr2, tempval); 50790751910SMingkai Hu 50890751910SMingkai Hu /* Clear out (for the most part) the other registers */ 50990751910SMingkai Hu init_registers(regs); 51090751910SMingkai Hu 51190751910SMingkai Hu /* Ready the device for tx/rx */ 51290751910SMingkai Hu startup_tsec(dev); 51390751910SMingkai Hu 514063c1263SAndy Fleming /* Start up the PHY */ 515063c1263SAndy Fleming phy_startup(priv->phydev); 516063c1263SAndy Fleming 517063c1263SAndy Fleming adjust_link(priv, priv->phydev); 518063c1263SAndy Fleming 51990751910SMingkai Hu /* If there's no link, fail */ 520063c1263SAndy Fleming return priv->phydev->link ? 0 : -1; 52190751910SMingkai Hu } 52290751910SMingkai Hu 523063c1263SAndy Fleming static phy_interface_t tsec_get_interface(struct tsec_private *priv) 524063c1263SAndy Fleming { 525063c1263SAndy Fleming tsec_t *regs = priv->regs; 526063c1263SAndy Fleming u32 ecntrl; 527063c1263SAndy Fleming 528063c1263SAndy Fleming ecntrl = in_be32(®s->ecntrl); 529063c1263SAndy Fleming 530063c1263SAndy Fleming if (ecntrl & ECNTRL_SGMII_MODE) 531063c1263SAndy Fleming return PHY_INTERFACE_MODE_SGMII; 532063c1263SAndy Fleming 533063c1263SAndy Fleming if (ecntrl & ECNTRL_TBI_MODE) { 534063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) 535063c1263SAndy Fleming return PHY_INTERFACE_MODE_RTBI; 536063c1263SAndy Fleming else 537063c1263SAndy Fleming return PHY_INTERFACE_MODE_TBI; 538063c1263SAndy Fleming } 539063c1263SAndy Fleming 540063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MODE) { 541063c1263SAndy Fleming if (ecntrl & ECNTRL_REDUCED_MII_MODE) 542063c1263SAndy Fleming return PHY_INTERFACE_MODE_RMII; 543063c1263SAndy Fleming else { 544063c1263SAndy Fleming phy_interface_t interface = priv->interface; 545063c1263SAndy Fleming 546063c1263SAndy Fleming /* 547063c1263SAndy Fleming * This isn't autodetected, so it must 548063c1263SAndy Fleming * be set by the platform code. 549063c1263SAndy Fleming */ 550063c1263SAndy Fleming if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || 551063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_TXID) || 552063c1263SAndy Fleming (interface == PHY_INTERFACE_MODE_RGMII_RXID)) 553063c1263SAndy Fleming return interface; 554063c1263SAndy Fleming 555063c1263SAndy Fleming return PHY_INTERFACE_MODE_RGMII; 556063c1263SAndy Fleming } 557063c1263SAndy Fleming } 558063c1263SAndy Fleming 559063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 560063c1263SAndy Fleming return PHY_INTERFACE_MODE_GMII; 561063c1263SAndy Fleming 562063c1263SAndy Fleming return PHY_INTERFACE_MODE_MII; 563063c1263SAndy Fleming } 564063c1263SAndy Fleming 565063c1263SAndy Fleming 56690751910SMingkai Hu /* Discover which PHY is attached to the device, and configure it 56790751910SMingkai Hu * properly. If the PHY is not recognized, then return 0 56890751910SMingkai Hu * (failure). Otherwise, return 1 56990751910SMingkai Hu */ 57090751910SMingkai Hu static int init_phy(struct eth_device *dev) 57190751910SMingkai Hu { 57290751910SMingkai Hu struct tsec_private *priv = (struct tsec_private *)dev->priv; 573063c1263SAndy Fleming struct phy_device *phydev; 57490751910SMingkai Hu tsec_t *regs = priv->regs; 575063c1263SAndy Fleming u32 supported = (SUPPORTED_10baseT_Half | 576063c1263SAndy Fleming SUPPORTED_10baseT_Full | 577063c1263SAndy Fleming SUPPORTED_100baseT_Half | 578063c1263SAndy Fleming SUPPORTED_100baseT_Full); 579063c1263SAndy Fleming 580063c1263SAndy Fleming if (priv->flags & TSEC_GIGABIT) 581063c1263SAndy Fleming supported |= SUPPORTED_1000baseT_Full; 58290751910SMingkai Hu 58390751910SMingkai Hu /* Assign a Physical address to the TBI */ 58490751910SMingkai Hu out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); 58590751910SMingkai Hu 586063c1263SAndy Fleming priv->interface = tsec_get_interface(priv); 58790751910SMingkai Hu 588063c1263SAndy Fleming if (priv->interface == PHY_INTERFACE_MODE_SGMII) 58990751910SMingkai Hu tsec_configure_serdes(priv); 59090751910SMingkai Hu 591063c1263SAndy Fleming phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); 59290751910SMingkai Hu 593063c1263SAndy Fleming phydev->supported &= supported; 594063c1263SAndy Fleming phydev->advertising = phydev->supported; 595063c1263SAndy Fleming 596063c1263SAndy Fleming priv->phydev = phydev; 597063c1263SAndy Fleming 598063c1263SAndy Fleming phy_config(phydev); 59990751910SMingkai Hu 60090751910SMingkai Hu return 1; 60190751910SMingkai Hu } 60290751910SMingkai Hu 60390751910SMingkai Hu /* Initialize device structure. Returns success if PHY 60490751910SMingkai Hu * initialization succeeded (i.e. if it recognizes the PHY) 60590751910SMingkai Hu */ 60690751910SMingkai Hu static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) 60790751910SMingkai Hu { 60890751910SMingkai Hu struct eth_device *dev; 60990751910SMingkai Hu int i; 61090751910SMingkai Hu struct tsec_private *priv; 61190751910SMingkai Hu 61290751910SMingkai Hu dev = (struct eth_device *)malloc(sizeof *dev); 61390751910SMingkai Hu 61490751910SMingkai Hu if (NULL == dev) 61590751910SMingkai Hu return 0; 61690751910SMingkai Hu 61790751910SMingkai Hu memset(dev, 0, sizeof *dev); 61890751910SMingkai Hu 61990751910SMingkai Hu priv = (struct tsec_private *)malloc(sizeof(*priv)); 62090751910SMingkai Hu 62190751910SMingkai Hu if (NULL == priv) 62290751910SMingkai Hu return 0; 62390751910SMingkai Hu 62490751910SMingkai Hu privlist[num_tsecs++] = priv; 62590751910SMingkai Hu priv->regs = tsec_info->regs; 62690751910SMingkai Hu priv->phyregs_sgmii = tsec_info->miiregs_sgmii; 62790751910SMingkai Hu 62890751910SMingkai Hu priv->phyaddr = tsec_info->phyaddr; 62990751910SMingkai Hu priv->flags = tsec_info->flags; 63090751910SMingkai Hu 63190751910SMingkai Hu sprintf(dev->name, tsec_info->devname); 632063c1263SAndy Fleming priv->interface = tsec_info->interface; 633063c1263SAndy Fleming priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); 63490751910SMingkai Hu dev->iobase = 0; 63590751910SMingkai Hu dev->priv = priv; 63690751910SMingkai Hu dev->init = tsec_init; 63790751910SMingkai Hu dev->halt = tsec_halt; 63890751910SMingkai Hu dev->send = tsec_send; 63990751910SMingkai Hu dev->recv = tsec_recv; 64090751910SMingkai Hu #ifdef CONFIG_MCAST_TFTP 64190751910SMingkai Hu dev->mcast = tsec_mcast_addr; 64290751910SMingkai Hu #endif 64390751910SMingkai Hu 64490751910SMingkai Hu /* Tell u-boot to get the addr from the env */ 64590751910SMingkai Hu for (i = 0; i < 6; i++) 64690751910SMingkai Hu dev->enetaddr[i] = 0; 64790751910SMingkai Hu 64890751910SMingkai Hu eth_register(dev); 64990751910SMingkai Hu 65090751910SMingkai Hu /* Reset the MAC */ 65190751910SMingkai Hu setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65290751910SMingkai Hu udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ 65390751910SMingkai Hu clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); 65490751910SMingkai Hu 65590751910SMingkai Hu /* Try to initialize PHY here, and return */ 65690751910SMingkai Hu return init_phy(dev); 65790751910SMingkai Hu } 65890751910SMingkai Hu 65990751910SMingkai Hu /* 66090751910SMingkai Hu * Initialize all the TSEC devices 66190751910SMingkai Hu * 66290751910SMingkai Hu * Returns the number of TSEC devices that were initialized 66390751910SMingkai Hu */ 66490751910SMingkai Hu int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) 66590751910SMingkai Hu { 66690751910SMingkai Hu int i; 66790751910SMingkai Hu int ret, count = 0; 66890751910SMingkai Hu 66990751910SMingkai Hu for (i = 0; i < num; i++) { 67090751910SMingkai Hu ret = tsec_initialize(bis, &tsecs[i]); 67190751910SMingkai Hu if (ret > 0) 67290751910SMingkai Hu count += ret; 67390751910SMingkai Hu } 67490751910SMingkai Hu 67590751910SMingkai Hu return count; 67690751910SMingkai Hu } 67790751910SMingkai Hu 67890751910SMingkai Hu int tsec_standard_init(bd_t *bis) 67990751910SMingkai Hu { 680063c1263SAndy Fleming struct fsl_pq_mdio_info info; 681063c1263SAndy Fleming 682063c1263SAndy Fleming info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; 683063c1263SAndy Fleming info.name = DEFAULT_MII_NAME; 684063c1263SAndy Fleming 685063c1263SAndy Fleming fsl_pq_mdio_init(bis, &info); 686063c1263SAndy Fleming 68790751910SMingkai Hu return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); 68890751910SMingkai Hu } 689