uboot/drivers/net/pch_gbe.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
   3 *
   4 * Intel Platform Controller Hub EG20T (codename Topcliff) GMAC Driver
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <asm/io.h>
  13#include <pci.h>
  14#include <miiphy.h>
  15#include "pch_gbe.h"
  16
  17#if !defined(CONFIG_PHYLIB)
  18# error "PCH Gigabit Ethernet driver requires PHYLIB - missing CONFIG_PHYLIB"
  19#endif
  20
  21static struct pci_device_id supported[] = {
  22        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_GBE) },
  23        { }
  24};
  25
  26static void pch_gbe_mac_read(struct pch_gbe_regs *mac_regs, u8 *addr)
  27{
  28        u32 macid_hi, macid_lo;
  29
  30        macid_hi = readl(&mac_regs->mac_adr[0].high);
  31        macid_lo = readl(&mac_regs->mac_adr[0].low) & 0xffff;
  32        debug("pch_gbe: macid_hi %#x macid_lo %#x\n", macid_hi, macid_lo);
  33
  34        addr[0] = (u8)(macid_hi & 0xff);
  35        addr[1] = (u8)((macid_hi >> 8) & 0xff);
  36        addr[2] = (u8)((macid_hi >> 16) & 0xff);
  37        addr[3] = (u8)((macid_hi >> 24) & 0xff);
  38        addr[4] = (u8)(macid_lo & 0xff);
  39        addr[5] = (u8)((macid_lo >> 8) & 0xff);
  40}
  41
  42static int pch_gbe_mac_write(struct pch_gbe_regs *mac_regs, u8 *addr)
  43{
  44        u32 macid_hi, macid_lo;
  45        ulong start;
  46
  47        macid_hi = addr[0] + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
  48        macid_lo = addr[4] + (addr[5] << 8);
  49
  50        writel(macid_hi, &mac_regs->mac_adr[0].high);
  51        writel(macid_lo, &mac_regs->mac_adr[0].low);
  52        writel(0xfffe, &mac_regs->addr_mask);
  53
  54        start = get_timer(0);
  55        while (get_timer(start) < PCH_GBE_TIMEOUT) {
  56                if (!(readl(&mac_regs->addr_mask) & PCH_GBE_BUSY))
  57                        return 0;
  58
  59                udelay(10);
  60        }
  61
  62        return -ETIME;
  63}
  64
  65static int pch_gbe_reset(struct udevice *dev)
  66{
  67        struct pch_gbe_priv *priv = dev_get_priv(dev);
  68        struct eth_pdata *plat = dev_get_platdata(dev);
  69        struct pch_gbe_regs *mac_regs = priv->mac_regs;
  70        ulong start;
  71
  72        priv->rx_idx = 0;
  73        priv->tx_idx = 0;
  74
  75        writel(PCH_GBE_ALL_RST, &mac_regs->reset);
  76
  77        /*
  78         * Configure the MAC to RGMII mode after reset
  79         *
  80         * For some unknown reason, we must do the configuration here right
  81         * after resetting the whole MAC, otherwise the reset bit in the RESET
  82         * register will never be cleared by the hardware. And there is another
  83         * way of having the same magic, that is to configure the MODE register
  84         * to have the MAC work in MII/GMII mode, which is how current Linux
  85         * pch_gbe driver does. Since anyway we need program the MAC to RGMII
  86         * mode in the driver, we just do it here.
  87         *
  88         * Note: this behavior is not documented in the hardware manual.
  89         */
  90        writel(PCH_GBE_RGMII_MODE_RGMII | PCH_GBE_CHIP_TYPE_INTERNAL,
  91               &mac_regs->rgmii_ctrl);
  92
  93        start = get_timer(0);
  94        while (get_timer(start) < PCH_GBE_TIMEOUT) {
  95                if (!(readl(&mac_regs->reset) & PCH_GBE_ALL_RST)) {
  96                        /*
  97                         * Soft reset clears hardware MAC address registers,
  98                         * so we have to reload MAC address here in order to
  99                         * make linux pch_gbe driver happy.
 100                         */
 101                        return pch_gbe_mac_write(mac_regs, plat->enetaddr);
 102                }
 103
 104                udelay(10);
 105        }
 106
 107        debug("pch_gbe: reset timeout\n");
 108        return -ETIME;
 109}
 110
 111static void pch_gbe_rx_descs_init(struct udevice *dev)
 112{
 113        struct pch_gbe_priv *priv = dev_get_priv(dev);
 114        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 115        struct pch_gbe_rx_desc *rx_desc = &priv->rx_desc[0];
 116        int i;
 117
 118        memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM);
 119        for (i = 0; i < PCH_GBE_DESC_NUM; i++)
 120                rx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev,
 121                        (u32)(priv->rx_buff[i]));
 122
 123        writel(dm_pci_phys_to_mem(priv->dev, (u32)rx_desc),
 124               &mac_regs->rx_dsc_base);
 125        writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1),
 126               &mac_regs->rx_dsc_size);
 127
 128        writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_desc + 1)),
 129               &mac_regs->rx_dsc_sw_p);
 130}
 131
 132static void pch_gbe_tx_descs_init(struct udevice *dev)
 133{
 134        struct pch_gbe_priv *priv = dev_get_priv(dev);
 135        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 136        struct pch_gbe_tx_desc *tx_desc = &priv->tx_desc[0];
 137
 138        memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM);
 139
 140        writel(dm_pci_phys_to_mem(priv->dev, (u32)tx_desc),
 141               &mac_regs->tx_dsc_base);
 142        writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1),
 143               &mac_regs->tx_dsc_size);
 144        writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_desc + 1)),
 145               &mac_regs->tx_dsc_sw_p);
 146}
 147
 148static void pch_gbe_adjust_link(struct pch_gbe_regs *mac_regs,
 149                                struct phy_device *phydev)
 150{
 151        if (!phydev->link) {
 152                printf("%s: No link.\n", phydev->dev->name);
 153                return;
 154        }
 155
 156        clrbits_le32(&mac_regs->rgmii_ctrl,
 157                     PCH_GBE_RGMII_RATE_2_5M | PCH_GBE_CRS_SEL);
 158        clrbits_le32(&mac_regs->mode,
 159                     PCH_GBE_MODE_GMII_ETHER | PCH_GBE_MODE_FULL_DUPLEX);
 160
 161        switch (phydev->speed) {
 162        case 1000:
 163                setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_125M);
 164                setbits_le32(&mac_regs->mode, PCH_GBE_MODE_GMII_ETHER);
 165                break;
 166        case 100:
 167                setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_25M);
 168                setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER);
 169                break;
 170        case 10:
 171                setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_2_5M);
 172                setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER);
 173                break;
 174        }
 175
 176        if (phydev->duplex) {
 177                setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_CRS_SEL);
 178                setbits_le32(&mac_regs->mode, PCH_GBE_MODE_FULL_DUPLEX);
 179        }
 180
 181        printf("Speed: %d, %s duplex\n", phydev->speed,
 182               (phydev->duplex) ? "full" : "half");
 183
 184        return;
 185}
 186
 187static int pch_gbe_start(struct udevice *dev)
 188{
 189        struct pch_gbe_priv *priv = dev_get_priv(dev);
 190        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 191
 192        if (pch_gbe_reset(dev))
 193                return -1;
 194
 195        pch_gbe_rx_descs_init(dev);
 196        pch_gbe_tx_descs_init(dev);
 197
 198        /* Enable frame bursting */
 199        writel(PCH_GBE_MODE_FR_BST, &mac_regs->mode);
 200        /* Disable TCP/IP accelerator */
 201        writel(PCH_GBE_RX_TCPIPACC_OFF, &mac_regs->tcpip_acc);
 202        /* Disable RX flow control */
 203        writel(0, &mac_regs->rx_fctrl);
 204        /* Configure RX/TX mode */
 205        writel(PCH_GBE_RH_ALM_EMP_16 | PCH_GBE_RH_ALM_FULL_16 |
 206               PCH_GBE_RH_RD_TRG_32, &mac_regs->rx_mode);
 207        writel(PCH_GBE_TM_TH_TX_STRT_32 | PCH_GBE_TM_TH_ALM_EMP_16 |
 208               PCH_GBE_TM_TH_ALM_FULL_32 | PCH_GBE_TM_ST_AND_FD |
 209               PCH_GBE_TM_SHORT_PKT, &mac_regs->tx_mode);
 210
 211        /* Start up the PHY */
 212        if (phy_startup(priv->phydev)) {
 213                printf("Could not initialize PHY %s\n",
 214                       priv->phydev->dev->name);
 215                return -1;
 216        }
 217
 218        pch_gbe_adjust_link(mac_regs, priv->phydev);
 219
 220        if (!priv->phydev->link)
 221                return -1;
 222
 223        /* Enable TX & RX */
 224        writel(PCH_GBE_RX_DMA_EN | PCH_GBE_TX_DMA_EN, &mac_regs->dma_ctrl);
 225        writel(PCH_GBE_MRE_MAC_RX_EN, &mac_regs->mac_rx_en);
 226
 227        return 0;
 228}
 229
 230static void pch_gbe_stop(struct udevice *dev)
 231{
 232        struct pch_gbe_priv *priv = dev_get_priv(dev);
 233
 234        pch_gbe_reset(dev);
 235
 236        phy_shutdown(priv->phydev);
 237}
 238
 239static int pch_gbe_send(struct udevice *dev, void *packet, int length)
 240{
 241        struct pch_gbe_priv *priv = dev_get_priv(dev);
 242        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 243        struct pch_gbe_tx_desc *tx_head, *tx_desc;
 244        u16 frame_ctrl = 0;
 245        u32 int_st;
 246        ulong start;
 247
 248        tx_head = &priv->tx_desc[0];
 249        tx_desc = &priv->tx_desc[priv->tx_idx];
 250
 251        if (length < 64)
 252                frame_ctrl |= PCH_GBE_TXD_CTRL_APAD;
 253
 254        tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (u32)packet);
 255        tx_desc->length = length;
 256        tx_desc->tx_words_eob = length + 3;
 257        tx_desc->tx_frame_ctrl = frame_ctrl;
 258        tx_desc->dma_status = 0;
 259        tx_desc->gbec_status = 0;
 260
 261        /* Test the wrap-around condition */
 262        if (++priv->tx_idx >= PCH_GBE_DESC_NUM)
 263                priv->tx_idx = 0;
 264
 265        writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_head + priv->tx_idx)),
 266               &mac_regs->tx_dsc_sw_p);
 267
 268        start = get_timer(0);
 269        while (get_timer(start) < PCH_GBE_TIMEOUT) {
 270                int_st = readl(&mac_regs->int_st);
 271                if (int_st & PCH_GBE_INT_TX_CMPLT)
 272                        return 0;
 273
 274                udelay(10);
 275        }
 276
 277        debug("pch_gbe: sent failed\n");
 278        return -ETIME;
 279}
 280
 281static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp)
 282{
 283        struct pch_gbe_priv *priv = dev_get_priv(dev);
 284        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 285        struct pch_gbe_rx_desc *rx_desc;
 286        u32 hw_desc, buffer_addr, length;
 287
 288        rx_desc = &priv->rx_desc[priv->rx_idx];
 289
 290        readl(&mac_regs->int_st);
 291        hw_desc = readl(&mac_regs->rx_dsc_hw_p_hld);
 292
 293        /* Just return if not receiving any packet */
 294        if ((u32)rx_desc == hw_desc)
 295                return -EAGAIN;
 296
 297        buffer_addr = dm_pci_mem_to_phys(priv->dev, rx_desc->buffer_addr);
 298        *packetp = (uchar *)buffer_addr;
 299        length = rx_desc->rx_words_eob - 3 - ETH_FCS_LEN;
 300
 301        return length;
 302}
 303
 304static int pch_gbe_free_pkt(struct udevice *dev, uchar *packet, int length)
 305{
 306        struct pch_gbe_priv *priv = dev_get_priv(dev);
 307        struct pch_gbe_regs *mac_regs = priv->mac_regs;
 308        struct pch_gbe_rx_desc *rx_head = &priv->rx_desc[0];
 309        int rx_swp;
 310
 311        /* Test the wrap-around condition */
 312        if (++priv->rx_idx >= PCH_GBE_DESC_NUM)
 313                priv->rx_idx = 0;
 314        rx_swp = priv->rx_idx;
 315        if (++rx_swp >= PCH_GBE_DESC_NUM)
 316                rx_swp = 0;
 317
 318        writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_head + rx_swp)),
 319               &mac_regs->rx_dsc_sw_p);
 320
 321        return 0;
 322}
 323
 324static int pch_gbe_mdio_ready(struct pch_gbe_regs *mac_regs)
 325{
 326        ulong start = get_timer(0);
 327
 328        while (get_timer(start) < PCH_GBE_TIMEOUT) {
 329                if (readl(&mac_regs->miim) & PCH_GBE_MIIM_OPER_READY)
 330                        return 0;
 331
 332                udelay(10);
 333        }
 334
 335        return -ETIME;
 336}
 337
 338static int pch_gbe_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 339{
 340        struct pch_gbe_regs *mac_regs = bus->priv;
 341        u32 miim;
 342
 343        if (pch_gbe_mdio_ready(mac_regs))
 344                return -ETIME;
 345
 346        miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
 347               (reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
 348               PCH_GBE_MIIM_OPER_READ;
 349        writel(miim, &mac_regs->miim);
 350
 351        if (pch_gbe_mdio_ready(mac_regs))
 352                return -ETIME;
 353
 354        return readl(&mac_regs->miim) & 0xffff;
 355}
 356
 357static int pch_gbe_mdio_write(struct mii_dev *bus, int addr, int devad,
 358                              int reg, u16 val)
 359{
 360        struct pch_gbe_regs *mac_regs = bus->priv;
 361        u32 miim;
 362
 363        if (pch_gbe_mdio_ready(mac_regs))
 364                return -ETIME;
 365
 366        miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) |
 367               (reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) |
 368               PCH_GBE_MIIM_OPER_WRITE | val;
 369        writel(miim, &mac_regs->miim);
 370
 371        if (pch_gbe_mdio_ready(mac_regs))
 372                return -ETIME;
 373        else
 374                return 0;
 375}
 376
 377static int pch_gbe_mdio_init(const char *name, struct pch_gbe_regs *mac_regs)
 378{
 379        struct mii_dev *bus;
 380
 381        bus = mdio_alloc();
 382        if (!bus) {
 383                debug("pch_gbe: failed to allocate MDIO bus\n");
 384                return -ENOMEM;
 385        }
 386
 387        bus->read = pch_gbe_mdio_read;
 388        bus->write = pch_gbe_mdio_write;
 389        strcpy(bus->name, name);
 390
 391        bus->priv = (void *)mac_regs;
 392
 393        return mdio_register(bus);
 394}
 395
 396static int pch_gbe_phy_init(struct udevice *dev)
 397{
 398        struct pch_gbe_priv *priv = dev_get_priv(dev);
 399        struct eth_pdata *plat = dev_get_platdata(dev);
 400        struct phy_device *phydev;
 401        int mask = 0xffffffff;
 402
 403        phydev = phy_find_by_mask(priv->bus, mask, plat->phy_interface);
 404        if (!phydev) {
 405                printf("pch_gbe: cannot find the phy\n");
 406                return -1;
 407        }
 408
 409        phy_connect_dev(phydev, dev);
 410
 411        phydev->supported &= PHY_GBIT_FEATURES;
 412        phydev->advertising = phydev->supported;
 413
 414        priv->phydev = phydev;
 415        phy_config(phydev);
 416
 417        return 0;
 418}
 419
 420int pch_gbe_probe(struct udevice *dev)
 421{
 422        struct pch_gbe_priv *priv;
 423        struct eth_pdata *plat = dev_get_platdata(dev);
 424        u32 iobase;
 425
 426        /*
 427         * The priv structure contains the descriptors and frame buffers which
 428         * need a strict buswidth alignment (64 bytes). This is guaranteed by
 429         * DM_FLAG_ALLOC_PRIV_DMA flag in the U_BOOT_DRIVER.
 430         */
 431        priv = dev_get_priv(dev);
 432
 433        priv->dev = dev;
 434
 435        dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase);
 436        iobase &= PCI_BASE_ADDRESS_MEM_MASK;
 437        iobase = dm_pci_mem_to_phys(dev, iobase);
 438
 439        plat->iobase = iobase;
 440        priv->mac_regs = (struct pch_gbe_regs *)iobase;
 441
 442        /* Read MAC address from SROM and initialize dev->enetaddr with it */
 443        pch_gbe_mac_read(priv->mac_regs, plat->enetaddr);
 444
 445        plat->phy_interface = PHY_INTERFACE_MODE_RGMII;
 446        pch_gbe_mdio_init(dev->name, priv->mac_regs);
 447        priv->bus = miiphy_get_dev_by_name(dev->name);
 448
 449        return pch_gbe_phy_init(dev);
 450}
 451
 452int pch_gbe_remove(struct udevice *dev)
 453{
 454        struct pch_gbe_priv *priv = dev_get_priv(dev);
 455
 456        free(priv->phydev);
 457        mdio_unregister(priv->bus);
 458        mdio_free(priv->bus);
 459
 460        return 0;
 461}
 462
 463static const struct eth_ops pch_gbe_ops = {
 464        .start = pch_gbe_start,
 465        .send = pch_gbe_send,
 466        .recv = pch_gbe_recv,
 467        .free_pkt = pch_gbe_free_pkt,
 468        .stop = pch_gbe_stop,
 469};
 470
 471static const struct udevice_id pch_gbe_ids[] = {
 472        { .compatible = "intel,pch-gbe" },
 473        { }
 474};
 475
 476U_BOOT_DRIVER(eth_pch_gbe) = {
 477        .name = "pch_gbe",
 478        .id = UCLASS_ETH,
 479        .of_match = pch_gbe_ids,
 480        .probe = pch_gbe_probe,
 481        .remove = pch_gbe_remove,
 482        .ops = &pch_gbe_ops,
 483        .priv_auto_alloc_size = sizeof(struct pch_gbe_priv),
 484        .platdata_auto_alloc_size = sizeof(struct eth_pdata),
 485        .flags = DM_FLAG_ALLOC_PRIV_DMA,
 486};
 487
 488U_BOOT_PCI_DEVICE(eth_pch_gbe, supported);
 489