1*df482650SStephan Linz /* 2*df482650SStephan Linz * Xilinx xps_ll_temac ethernet driver for u-boot 3*df482650SStephan Linz * 4*df482650SStephan Linz * supports SDMA or FIFO access and MDIO bus communication 5*df482650SStephan Linz * 6*df482650SStephan Linz * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net> 7*df482650SStephan Linz * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu> 8*df482650SStephan Linz * Copyright (C) 2008 - 2011 PetaLogix 9*df482650SStephan Linz * 10*df482650SStephan Linz * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver 11*df482650SStephan Linz * Copyright (C) 2008 Nissin Systems Co.,Ltd. 12*df482650SStephan Linz * March 2008 created 13*df482650SStephan Linz * 14*df482650SStephan Linz * This program is free software; you can redistribute it and/or modify it 15*df482650SStephan Linz * under the terms of the GNU General Public License as published by the 16*df482650SStephan Linz * Free Software Foundation; either version 2 of the License, or (at your 17*df482650SStephan Linz * option) any later version. 18*df482650SStephan Linz * 19*df482650SStephan Linz * [0]: http://www.xilinx.com/support/documentation 20*df482650SStephan Linz * 21*df482650SStephan Linz * [S]: [0]/ip_documentation/xps_ll_temac.pdf 22*df482650SStephan Linz * [A]: [0]/application_notes/xapp1041.pdf 23*df482650SStephan Linz */ 24*df482650SStephan Linz 25*df482650SStephan Linz #include <config.h> 26*df482650SStephan Linz #include <common.h> 27*df482650SStephan Linz #include <net.h> 28*df482650SStephan Linz #include <netdev.h> 29*df482650SStephan Linz #include <malloc.h> 30*df482650SStephan Linz #include <asm/io.h> 31*df482650SStephan Linz #include <miiphy.h> 32*df482650SStephan Linz 33*df482650SStephan Linz #include "xilinx_ll_temac.h" 34*df482650SStephan Linz #include "xilinx_ll_temac_fifo.h" 35*df482650SStephan Linz #include "xilinx_ll_temac_sdma.h" 36*df482650SStephan Linz #include "xilinx_ll_temac_mdio.h" 37*df482650SStephan Linz 38*df482650SStephan Linz #if !defined(CONFIG_MII) 39*df482650SStephan Linz # error "LL_TEMAC requires MII -- missing CONFIG_MII" 40*df482650SStephan Linz #endif 41*df482650SStephan Linz 42*df482650SStephan Linz #if !defined(CONFIG_PHYLIB) 43*df482650SStephan Linz # error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB" 44*df482650SStephan Linz #endif 45*df482650SStephan Linz 46*df482650SStephan Linz struct ll_temac_info { 47*df482650SStephan Linz int flags; 48*df482650SStephan Linz unsigned long base_addr; 49*df482650SStephan Linz unsigned long ctrl_addr; 50*df482650SStephan Linz char *devname; 51*df482650SStephan Linz unsigned int phyaddr; 52*df482650SStephan Linz char *mdio_busname; 53*df482650SStephan Linz }; 54*df482650SStephan Linz 55*df482650SStephan Linz /* Ethernet interface ready status */ 56*df482650SStephan Linz int ll_temac_check_status(struct temac_reg *regs, u32 mask) 57*df482650SStephan Linz { 58*df482650SStephan Linz unsigned timeout = 50; /* 1usec * 50 = 50usec */ 59*df482650SStephan Linz 60*df482650SStephan Linz /* 61*df482650SStephan Linz * Quote from LL TEMAC documentation: The bits in the RDY 62*df482650SStephan Linz * register are asserted when there is no access in progress. 63*df482650SStephan Linz * When an access is in progress, a bit corresponding to the 64*df482650SStephan Linz * type of access is automatically de-asserted. The bit is 65*df482650SStephan Linz * automatically re-asserted when the access is complete. 66*df482650SStephan Linz */ 67*df482650SStephan Linz while (timeout && (!(in_be32(®s->rdy) & mask))) { 68*df482650SStephan Linz timeout--; 69*df482650SStephan Linz udelay(1); 70*df482650SStephan Linz } 71*df482650SStephan Linz 72*df482650SStephan Linz if (!timeout) { 73*df482650SStephan Linz printf("%s: Timeout on 0x%08x @%p\n", __func__, 74*df482650SStephan Linz mask, ®s->rdy); 75*df482650SStephan Linz return 1; 76*df482650SStephan Linz } 77*df482650SStephan Linz 78*df482650SStephan Linz return 0; 79*df482650SStephan Linz } 80*df482650SStephan Linz 81*df482650SStephan Linz /* 82*df482650SStephan Linz * Indirect write to ll_temac. 83*df482650SStephan Linz * 84*df482650SStephan Linz * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf 85*df482650SStephan Linz * page 23, second paragraph, The use of CTL0 register or CTL1 register 86*df482650SStephan Linz */ 87*df482650SStephan Linz int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data) 88*df482650SStephan Linz { 89*df482650SStephan Linz out_be32(®s->lsw, (reg_data & MLSW_MASK)); 90*df482650SStephan Linz out_be32(®s->ctl, CTL_WEN | (regn & CTL_ADDR_MASK)); 91*df482650SStephan Linz 92*df482650SStephan Linz if (ll_temac_check_status(regs, RSE_CFG_WR)) 93*df482650SStephan Linz return 0; 94*df482650SStephan Linz 95*df482650SStephan Linz return 1; 96*df482650SStephan Linz } 97*df482650SStephan Linz 98*df482650SStephan Linz /* 99*df482650SStephan Linz * Indirect read from ll_temac. 100*df482650SStephan Linz * 101*df482650SStephan Linz * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf 102*df482650SStephan Linz * page 23, second paragraph, The use of CTL0 register or CTL1 register 103*df482650SStephan Linz */ 104*df482650SStephan Linz int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data) 105*df482650SStephan Linz { 106*df482650SStephan Linz out_be32(®s->ctl, (regn & CTL_ADDR_MASK)); 107*df482650SStephan Linz 108*df482650SStephan Linz if (ll_temac_check_status(regs, RSE_CFG_RR)) 109*df482650SStephan Linz return 0; 110*df482650SStephan Linz 111*df482650SStephan Linz *reg_data = in_be32(®s->lsw) & MLSW_MASK; 112*df482650SStephan Linz return 1; 113*df482650SStephan Linz } 114*df482650SStephan Linz 115*df482650SStephan Linz /* setting sub-controller and ll_temac to proper setting */ 116*df482650SStephan Linz static int ll_temac_setup_ctrl(struct eth_device *dev) 117*df482650SStephan Linz { 118*df482650SStephan Linz struct ll_temac *ll_temac = dev->priv; 119*df482650SStephan Linz struct temac_reg *regs = (struct temac_reg *)dev->iobase; 120*df482650SStephan Linz 121*df482650SStephan Linz if (ll_temac->ctrlreset && ll_temac->ctrlreset(dev)) 122*df482650SStephan Linz return 0; 123*df482650SStephan Linz 124*df482650SStephan Linz if (ll_temac->ctrlinit && ll_temac->ctrlinit(dev)) 125*df482650SStephan Linz return 0; 126*df482650SStephan Linz 127*df482650SStephan Linz /* Promiscuous mode disable */ 128*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_AFM, 0)) 129*df482650SStephan Linz return 0; 130*df482650SStephan Linz 131*df482650SStephan Linz /* Enable Receiver - RX bit */ 132*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_RCW1, RCW1_RX)) 133*df482650SStephan Linz return 0; 134*df482650SStephan Linz 135*df482650SStephan Linz /* Enable Transmitter - TX bit */ 136*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_TC, TC_TX)) 137*df482650SStephan Linz return 0; 138*df482650SStephan Linz 139*df482650SStephan Linz return 1; 140*df482650SStephan Linz } 141*df482650SStephan Linz 142*df482650SStephan Linz /* 143*df482650SStephan Linz * Configure ll_temac based on negotiated speed and duplex 144*df482650SStephan Linz * reported by PHY handling code 145*df482650SStephan Linz */ 146*df482650SStephan Linz static int ll_temac_adjust_link(struct eth_device *dev) 147*df482650SStephan Linz { 148*df482650SStephan Linz unsigned int speed, emmc_reg; 149*df482650SStephan Linz struct temac_reg *regs = (struct temac_reg *)dev->iobase; 150*df482650SStephan Linz struct ll_temac *ll_temac = dev->priv; 151*df482650SStephan Linz struct phy_device *phydev = ll_temac->phydev; 152*df482650SStephan Linz 153*df482650SStephan Linz if (!phydev->link) { 154*df482650SStephan Linz printf("%s: No link.\n", phydev->dev->name); 155*df482650SStephan Linz return 0; 156*df482650SStephan Linz } 157*df482650SStephan Linz 158*df482650SStephan Linz switch (phydev->speed) { 159*df482650SStephan Linz case 1000: 160*df482650SStephan Linz speed = EMMC_LSPD_1000; 161*df482650SStephan Linz break; 162*df482650SStephan Linz case 100: 163*df482650SStephan Linz speed = EMMC_LSPD_100; 164*df482650SStephan Linz break; 165*df482650SStephan Linz case 10: 166*df482650SStephan Linz speed = EMMC_LSPD_10; 167*df482650SStephan Linz break; 168*df482650SStephan Linz default: 169*df482650SStephan Linz return 0; 170*df482650SStephan Linz } 171*df482650SStephan Linz 172*df482650SStephan Linz if (!ll_temac_indirect_get(regs, TEMAC_EMMC, &emmc_reg)) 173*df482650SStephan Linz return 0; 174*df482650SStephan Linz 175*df482650SStephan Linz emmc_reg &= ~EMMC_LSPD_MASK; 176*df482650SStephan Linz emmc_reg |= speed; 177*df482650SStephan Linz 178*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_EMMC, emmc_reg)) 179*df482650SStephan Linz return 0; 180*df482650SStephan Linz 181*df482650SStephan Linz printf("%s: PHY is %s with %dbase%s, %s%s\n", 182*df482650SStephan Linz dev->name, phydev->drv->name, 183*df482650SStephan Linz phydev->speed, (phydev->port == PORT_TP) ? "T" : "X", 184*df482650SStephan Linz (phydev->duplex) ? "FDX" : "HDX", 185*df482650SStephan Linz (phydev->port == PORT_OTHER) ? ", unkown mode" : ""); 186*df482650SStephan Linz 187*df482650SStephan Linz return 1; 188*df482650SStephan Linz } 189*df482650SStephan Linz 190*df482650SStephan Linz /* setup mac addr */ 191*df482650SStephan Linz static int ll_temac_setup_mac_addr(struct eth_device *dev) 192*df482650SStephan Linz { 193*df482650SStephan Linz struct temac_reg *regs = (struct temac_reg *)dev->iobase; 194*df482650SStephan Linz u32 val; 195*df482650SStephan Linz 196*df482650SStephan Linz /* set up unicast MAC address filter */ 197*df482650SStephan Linz val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) | 198*df482650SStephan Linz (dev->enetaddr[1] << 8) | (dev->enetaddr[0])); 199*df482650SStephan Linz val &= UAW0_UADDR_MASK; 200*df482650SStephan Linz 201*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_UAW0, val)) 202*df482650SStephan Linz return 1; 203*df482650SStephan Linz 204*df482650SStephan Linz val = ((dev->enetaddr[5] << 8) | dev->enetaddr[4]); 205*df482650SStephan Linz val &= UAW1_UADDR_MASK; 206*df482650SStephan Linz 207*df482650SStephan Linz if (!ll_temac_indirect_set(regs, TEMAC_UAW1, val)) 208*df482650SStephan Linz return 1; 209*df482650SStephan Linz 210*df482650SStephan Linz return 0; 211*df482650SStephan Linz } 212*df482650SStephan Linz 213*df482650SStephan Linz /* halt device */ 214*df482650SStephan Linz static void ll_temac_halt(struct eth_device *dev) 215*df482650SStephan Linz { 216*df482650SStephan Linz struct ll_temac *ll_temac = dev->priv; 217*df482650SStephan Linz struct temac_reg *regs = (struct temac_reg *)dev->iobase; 218*df482650SStephan Linz 219*df482650SStephan Linz /* Disable Receiver */ 220*df482650SStephan Linz ll_temac_indirect_set(regs, TEMAC_RCW0, 0); 221*df482650SStephan Linz 222*df482650SStephan Linz /* Disable Transmitter */ 223*df482650SStephan Linz ll_temac_indirect_set(regs, TEMAC_TC, 0); 224*df482650SStephan Linz 225*df482650SStephan Linz if (ll_temac->ctrlhalt) 226*df482650SStephan Linz ll_temac->ctrlhalt(dev); 227*df482650SStephan Linz 228*df482650SStephan Linz /* Shut down the PHY, as needed */ 229*df482650SStephan Linz phy_shutdown(ll_temac->phydev); 230*df482650SStephan Linz } 231*df482650SStephan Linz 232*df482650SStephan Linz static int ll_temac_init(struct eth_device *dev, bd_t *bis) 233*df482650SStephan Linz { 234*df482650SStephan Linz struct ll_temac *ll_temac = dev->priv; 235*df482650SStephan Linz 236*df482650SStephan Linz printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08X.\n", 237*df482650SStephan Linz dev->name, dev->index, dev->iobase); 238*df482650SStephan Linz 239*df482650SStephan Linz if (!ll_temac_setup_ctrl(dev)) 240*df482650SStephan Linz return -1; 241*df482650SStephan Linz 242*df482650SStephan Linz /* Start up the PHY */ 243*df482650SStephan Linz phy_startup(ll_temac->phydev); 244*df482650SStephan Linz 245*df482650SStephan Linz if (!ll_temac_adjust_link(dev)) { 246*df482650SStephan Linz ll_temac_halt(dev); 247*df482650SStephan Linz return -1; 248*df482650SStephan Linz } 249*df482650SStephan Linz 250*df482650SStephan Linz /* If there's no link, fail */ 251*df482650SStephan Linz return ll_temac->phydev->link ? 0 : -1; 252*df482650SStephan Linz } 253*df482650SStephan Linz 254*df482650SStephan Linz /* 255*df482650SStephan Linz * Discover which PHY is attached to the device, and configure it 256*df482650SStephan Linz * properly. If the PHY is not recognized, then return 0 257*df482650SStephan Linz * (failure). Otherwise, return 1 258*df482650SStephan Linz */ 259*df482650SStephan Linz static int ll_temac_phy_init(struct eth_device *dev) 260*df482650SStephan Linz { 261*df482650SStephan Linz struct ll_temac *ll_temac = dev->priv; 262*df482650SStephan Linz struct phy_device *phydev; 263*df482650SStephan Linz unsigned int supported = PHY_GBIT_FEATURES; 264*df482650SStephan Linz 265*df482650SStephan Linz /* interface - look at driver/net/tsec.c */ 266*df482650SStephan Linz phydev = phy_connect(ll_temac->bus, ll_temac->phyaddr, 267*df482650SStephan Linz dev, PHY_INTERFACE_MODE_NONE); 268*df482650SStephan Linz 269*df482650SStephan Linz phydev->supported &= supported; 270*df482650SStephan Linz phydev->advertising = phydev->supported; 271*df482650SStephan Linz 272*df482650SStephan Linz ll_temac->phydev = phydev; 273*df482650SStephan Linz 274*df482650SStephan Linz phy_config(phydev); 275*df482650SStephan Linz 276*df482650SStephan Linz return 1; 277*df482650SStephan Linz } 278*df482650SStephan Linz 279*df482650SStephan Linz /* 280*df482650SStephan Linz * Initialize a single ll_temac devices 281*df482650SStephan Linz * 282*df482650SStephan Linz * Returns the result of ll_temac phy interface that were initialized 283*df482650SStephan Linz */ 284*df482650SStephan Linz int xilinx_ll_temac_initialize(bd_t *bis, struct ll_temac_info *devinf) 285*df482650SStephan Linz { 286*df482650SStephan Linz struct eth_device *dev; 287*df482650SStephan Linz struct ll_temac *ll_temac; 288*df482650SStephan Linz 289*df482650SStephan Linz dev = calloc(1, sizeof(*dev)); 290*df482650SStephan Linz if (dev == NULL) 291*df482650SStephan Linz return 0; 292*df482650SStephan Linz 293*df482650SStephan Linz ll_temac = calloc(1, sizeof(struct ll_temac)); 294*df482650SStephan Linz if (ll_temac == NULL) { 295*df482650SStephan Linz free(dev); 296*df482650SStephan Linz return 0; 297*df482650SStephan Linz } 298*df482650SStephan Linz 299*df482650SStephan Linz /* use given name or generate its own unique name */ 300*df482650SStephan Linz if (devinf->devname) { 301*df482650SStephan Linz strncpy(dev->name, devinf->devname, NAMESIZE); 302*df482650SStephan Linz } else { 303*df482650SStephan Linz snprintf(dev->name, NAMESIZE, "lltemac.%lx", devinf->base_addr); 304*df482650SStephan Linz devinf->devname = dev->name; 305*df482650SStephan Linz } 306*df482650SStephan Linz 307*df482650SStephan Linz dev->iobase = devinf->base_addr; 308*df482650SStephan Linz 309*df482650SStephan Linz dev->priv = ll_temac; 310*df482650SStephan Linz dev->init = ll_temac_init; 311*df482650SStephan Linz dev->halt = ll_temac_halt; 312*df482650SStephan Linz dev->write_hwaddr = ll_temac_setup_mac_addr; 313*df482650SStephan Linz 314*df482650SStephan Linz ll_temac->ctrladdr = devinf->ctrl_addr; 315*df482650SStephan Linz if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_PLB) { 316*df482650SStephan Linz #if defined(CONFIG_XILINX_440) || defined(CONFIG_XILINX_405) 317*df482650SStephan Linz if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_DCR) { 318*df482650SStephan Linz ll_temac_collect_xldcr_sdma_reg_addr(dev); 319*df482650SStephan Linz ll_temac->in32 = ll_temac_xldcr_in32; 320*df482650SStephan Linz ll_temac->out32 = ll_temac_xldcr_out32; 321*df482650SStephan Linz } else 322*df482650SStephan Linz #endif 323*df482650SStephan Linz { 324*df482650SStephan Linz ll_temac_collect_xlplb_sdma_reg_addr(dev); 325*df482650SStephan Linz ll_temac->in32 = ll_temac_xlplb_in32; 326*df482650SStephan Linz ll_temac->out32 = ll_temac_xlplb_out32; 327*df482650SStephan Linz } 328*df482650SStephan Linz ll_temac->ctrlinit = ll_temac_init_sdma; 329*df482650SStephan Linz ll_temac->ctrlhalt = ll_temac_halt_sdma; 330*df482650SStephan Linz ll_temac->ctrlreset = ll_temac_reset_sdma; 331*df482650SStephan Linz dev->recv = ll_temac_recv_sdma; 332*df482650SStephan Linz dev->send = ll_temac_send_sdma; 333*df482650SStephan Linz } else { 334*df482650SStephan Linz ll_temac->in32 = NULL; 335*df482650SStephan Linz ll_temac->out32 = NULL; 336*df482650SStephan Linz ll_temac->ctrlinit = NULL; 337*df482650SStephan Linz ll_temac->ctrlhalt = NULL; 338*df482650SStephan Linz ll_temac->ctrlreset = ll_temac_reset_fifo; 339*df482650SStephan Linz dev->recv = ll_temac_recv_fifo; 340*df482650SStephan Linz dev->send = ll_temac_send_fifo; 341*df482650SStephan Linz } 342*df482650SStephan Linz 343*df482650SStephan Linz /* Link to specified MDIO bus */ 344*df482650SStephan Linz strncpy(ll_temac->mdio_busname, devinf->mdio_busname, MDIO_NAME_LEN); 345*df482650SStephan Linz ll_temac->bus = miiphy_get_dev_by_name(ll_temac->mdio_busname); 346*df482650SStephan Linz 347*df482650SStephan Linz /* Looking for a valid PHY address if it is not yet set */ 348*df482650SStephan Linz if (devinf->phyaddr == -1) 349*df482650SStephan Linz ll_temac->phyaddr = ll_temac_phy_addr(ll_temac->bus); 350*df482650SStephan Linz else 351*df482650SStephan Linz ll_temac->phyaddr = devinf->phyaddr; 352*df482650SStephan Linz 353*df482650SStephan Linz eth_register(dev); 354*df482650SStephan Linz 355*df482650SStephan Linz /* Try to initialize PHY here, and return */ 356*df482650SStephan Linz return ll_temac_phy_init(dev); 357*df482650SStephan Linz } 358*df482650SStephan Linz 359*df482650SStephan Linz /* 360*df482650SStephan Linz * Initialize a single ll_temac device with its mdio bus behind ll_temac 361*df482650SStephan Linz * 362*df482650SStephan Linz * Returns 1 if the ll_temac device and the mdio bus were initialized 363*df482650SStephan Linz * otherwise returns 0 364*df482650SStephan Linz */ 365*df482650SStephan Linz int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags, 366*df482650SStephan Linz unsigned long ctrl_addr) 367*df482650SStephan Linz { 368*df482650SStephan Linz struct ll_temac_info devinf; 369*df482650SStephan Linz struct ll_temac_mdio_info mdioinf; 370*df482650SStephan Linz int ret; 371*df482650SStephan Linz 372*df482650SStephan Linz /* prepare the internal driver informations */ 373*df482650SStephan Linz devinf.flags = flags; 374*df482650SStephan Linz devinf.base_addr = base_addr; 375*df482650SStephan Linz devinf.ctrl_addr = ctrl_addr; 376*df482650SStephan Linz devinf.devname = NULL; 377*df482650SStephan Linz devinf.phyaddr = -1; 378*df482650SStephan Linz 379*df482650SStephan Linz mdioinf.name = devinf.mdio_busname = NULL; 380*df482650SStephan Linz mdioinf.regs = (struct temac_reg *)devinf.base_addr; 381*df482650SStephan Linz 382*df482650SStephan Linz ret = xilinx_ll_temac_mdio_initialize(bis, &mdioinf); 383*df482650SStephan Linz if (ret >= 0) { 384*df482650SStephan Linz 385*df482650SStephan Linz /* 386*df482650SStephan Linz * If there was no MDIO bus name then take over the 387*df482650SStephan Linz * new automaticaly generated by the MDIO init code. 388*df482650SStephan Linz */ 389*df482650SStephan Linz if (mdioinf.name != devinf.mdio_busname) 390*df482650SStephan Linz devinf.mdio_busname = mdioinf.name; 391*df482650SStephan Linz 392*df482650SStephan Linz ret = xilinx_ll_temac_initialize(bis, &devinf); 393*df482650SStephan Linz if (ret > 0) 394*df482650SStephan Linz return 1; 395*df482650SStephan Linz 396*df482650SStephan Linz } 397*df482650SStephan Linz 398*df482650SStephan Linz return 0; 399*df482650SStephan Linz } 400