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