linux/drivers/net/ethernet/ti/netcp_sgmii.c
<<
>>
Prefs
   1/*
   2 * SGMI module initialisation
   3 *
   4 * Copyright (C) 2014 Texas Instruments Incorporated
   5 * Authors:     Sandeep Nair <sandeep_n@ti.com>
   6 *              Sandeep Paulraj <s-paulraj@ti.com>
   7 *              Wingman Kwok <w-kwok2@ti.com>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation version 2.
  12 *
  13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14 * kind, whether express or implied; without even the implied warranty
  15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include "netcp.h"
  20
  21#define SGMII_SRESET_RESET              BIT(0)
  22#define SGMII_SRESET_RTRESET            BIT(1)
  23
  24#define SGMII_REG_STATUS_LOCK           BIT(4)
  25#define SGMII_REG_STATUS_LINK           BIT(0)
  26#define SGMII_REG_STATUS_AUTONEG        BIT(2)
  27#define SGMII_REG_CONTROL_AUTONEG       BIT(0)
  28
  29#define SGMII23_OFFSET(x)       ((x - 2) * 0x100)
  30#define SGMII_OFFSET(x)         ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x)))
  31
  32/* SGMII registers */
  33#define SGMII_SRESET_REG(x)   (SGMII_OFFSET(x) + 0x004)
  34#define SGMII_CTL_REG(x)      (SGMII_OFFSET(x) + 0x010)
  35#define SGMII_STATUS_REG(x)   (SGMII_OFFSET(x) + 0x014)
  36#define SGMII_MRADV_REG(x)    (SGMII_OFFSET(x) + 0x018)
  37
  38static void sgmii_write_reg(void __iomem *base, int reg, u32 val)
  39{
  40        writel(val, base + reg);
  41}
  42
  43static u32 sgmii_read_reg(void __iomem *base, int reg)
  44{
  45        return readl(base + reg);
  46}
  47
  48static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
  49{
  50        writel((readl(base + reg) | val), base + reg);
  51}
  52
  53/* port is 0 based */
  54int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
  55{
  56        /* Soft reset */
  57        sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
  58                            SGMII_SRESET_RESET);
  59
  60        while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
  61                SGMII_SRESET_RESET) != 0x0)
  62                ;
  63
  64        return 0;
  65}
  66
  67/* port is 0 based */
  68bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
  69{
  70        u32 reg;
  71        bool oldval;
  72
  73        /* Initiate a soft reset */
  74        reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
  75        oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
  76        if (set)
  77                reg |= SGMII_SRESET_RTRESET;
  78        else
  79                reg &= ~SGMII_SRESET_RTRESET;
  80        sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
  81        wmb();
  82
  83        return oldval;
  84}
  85
  86int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
  87{
  88        u32 status = 0, link = 0;
  89
  90        status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
  91        if ((status & SGMII_REG_STATUS_LINK) != 0)
  92                link = 1;
  93        return link;
  94}
  95
  96int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface)
  97{
  98        unsigned int i, status, mask;
  99        u32 mr_adv_ability;
 100        u32 control;
 101
 102        switch (interface) {
 103        case SGMII_LINK_MAC_MAC_AUTONEG:
 104                mr_adv_ability  = 0x9801;
 105                control         = 0x21;
 106                break;
 107
 108        case SGMII_LINK_MAC_PHY:
 109        case SGMII_LINK_MAC_PHY_NO_MDIO:
 110                mr_adv_ability  = 1;
 111                control         = 1;
 112                break;
 113
 114        case SGMII_LINK_MAC_MAC_FORCED:
 115                mr_adv_ability  = 0x9801;
 116                control         = 0x20;
 117                break;
 118
 119        case SGMII_LINK_MAC_FIBER:
 120                mr_adv_ability  = 0x20;
 121                control         = 0x1;
 122                break;
 123
 124        default:
 125                WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface);
 126                return -EINVAL;
 127        }
 128
 129        sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0);
 130
 131        /* Wait for the SerDes pll to lock */
 132        for (i = 0; i < 1000; i++)  {
 133                usleep_range(1000, 2000);
 134                status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
 135                if ((status & SGMII_REG_STATUS_LOCK) != 0)
 136                        break;
 137        }
 138
 139        if ((status & SGMII_REG_STATUS_LOCK) == 0)
 140                pr_err("serdes PLL not locked\n");
 141
 142        sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability);
 143        sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control);
 144
 145        mask = SGMII_REG_STATUS_LINK;
 146        if (control & SGMII_REG_CONTROL_AUTONEG)
 147                mask |= SGMII_REG_STATUS_AUTONEG;
 148
 149        for (i = 0; i < 1000; i++)  {
 150                usleep_range(200, 500);
 151                status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
 152                if ((status & mask) == mask)
 153                        break;
 154        }
 155
 156        return 0;
 157}
 158