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