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