linux/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright Altera Corporation (C) 2016. All rights reserved.
   3 *
   4 * Author: Tien Hock Loh <thloh@altera.com>
   5 */
   6
   7#include <linux/mfd/syscon.h>
   8#include <linux/of.h>
   9#include <linux/of_address.h>
  10#include <linux/of_net.h>
  11#include <linux/phy.h>
  12#include <linux/regmap.h>
  13#include <linux/reset.h>
  14#include <linux/stmmac.h>
  15
  16#include "stmmac.h"
  17#include "stmmac_platform.h"
  18#include "altr_tse_pcs.h"
  19
  20#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII        0
  21#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII           BIT(1)
  22#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII            BIT(2)
  23#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH                2
  24#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK                 GENMASK(1, 0)
  25
  26#define TSE_PCS_CONTROL_AN_EN_MASK                      BIT(12)
  27#define TSE_PCS_CONTROL_REG                             0x00
  28#define TSE_PCS_CONTROL_RESTART_AN_MASK                 BIT(9)
  29#define TSE_PCS_CTRL_AUTONEG_SGMII                      0x1140
  30#define TSE_PCS_IF_MODE_REG                             0x28
  31#define TSE_PCS_LINK_TIMER_0_REG                        0x24
  32#define TSE_PCS_LINK_TIMER_1_REG                        0x26
  33#define TSE_PCS_SIZE                                    0x40
  34#define TSE_PCS_STATUS_AN_COMPLETED_MASK                BIT(5)
  35#define TSE_PCS_STATUS_LINK_MASK                        0x0004
  36#define TSE_PCS_STATUS_REG                              0x02
  37#define TSE_PCS_SGMII_SPEED_1000                        BIT(3)
  38#define TSE_PCS_SGMII_SPEED_100                         BIT(2)
  39#define TSE_PCS_SGMII_SPEED_10                          0x0
  40#define TSE_PCS_SW_RST_MASK                             0x8000
  41#define TSE_PCS_PARTNER_ABILITY_REG                     0x0A
  42#define TSE_PCS_PARTNER_DUPLEX_FULL                     0x1000
  43#define TSE_PCS_PARTNER_DUPLEX_HALF                     0x0000
  44#define TSE_PCS_PARTNER_DUPLEX_MASK                     0x1000
  45#define TSE_PCS_PARTNER_SPEED_MASK                      GENMASK(11, 10)
  46#define TSE_PCS_PARTNER_SPEED_1000                      BIT(11)
  47#define TSE_PCS_PARTNER_SPEED_100                       BIT(10)
  48#define TSE_PCS_PARTNER_SPEED_10                        0x0000
  49#define TSE_PCS_PARTNER_SPEED_1000                      BIT(11)
  50#define TSE_PCS_PARTNER_SPEED_100                       BIT(10)
  51#define TSE_PCS_PARTNER_SPEED_10                        0x0000
  52#define TSE_PCS_SGMII_SPEED_MASK                        GENMASK(3, 2)
  53#define TSE_PCS_SGMII_LINK_TIMER_0                      0x0D40
  54#define TSE_PCS_SGMII_LINK_TIMER_1                      0x0003
  55#define TSE_PCS_SW_RESET_TIMEOUT                        100
  56#define TSE_PCS_USE_SGMII_AN_MASK                       BIT(1)
  57#define TSE_PCS_USE_SGMII_ENA                           BIT(0)
  58#define TSE_PCS_IF_USE_SGMII                            0x03
  59
  60#define SGMII_ADAPTER_CTRL_REG                          0x00
  61#define SGMII_ADAPTER_DISABLE                           0x0001
  62#define SGMII_ADAPTER_ENABLE                            0x0000
  63
  64#define AUTONEGO_LINK_TIMER                             20
  65
  66static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs)
  67{
  68        int counter = 0;
  69        u16 val;
  70
  71        val = readw(base + TSE_PCS_CONTROL_REG);
  72        val |= TSE_PCS_SW_RST_MASK;
  73        writew(val, base + TSE_PCS_CONTROL_REG);
  74
  75        while (counter < TSE_PCS_SW_RESET_TIMEOUT) {
  76                val = readw(base + TSE_PCS_CONTROL_REG);
  77                val &= TSE_PCS_SW_RST_MASK;
  78                if (val == 0)
  79                        break;
  80                counter++;
  81                udelay(1);
  82        }
  83        if (counter >= TSE_PCS_SW_RESET_TIMEOUT) {
  84                dev_err(pcs->dev, "PCS could not get out of sw reset\n");
  85                return -ETIMEDOUT;
  86        }
  87
  88        return 0;
  89}
  90
  91int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs)
  92{
  93        int ret = 0;
  94
  95        writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG);
  96
  97        writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG);
  98
  99        writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG);
 100        writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG);
 101
 102        ret = tse_pcs_reset(base, pcs);
 103        if (ret == 0)
 104                writew(SGMII_ADAPTER_ENABLE,
 105                       pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 106
 107        return ret;
 108}
 109
 110static void pcs_link_timer_callback(struct tse_pcs *pcs)
 111{
 112        u16 val = 0;
 113        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 114        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 115
 116        val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
 117        val &= TSE_PCS_STATUS_LINK_MASK;
 118
 119        if (val != 0) {
 120                dev_dbg(pcs->dev, "Adapter: Link is established\n");
 121                writew(SGMII_ADAPTER_ENABLE,
 122                       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 123        } else {
 124                mod_timer(&pcs->aneg_link_timer, jiffies +
 125                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 126        }
 127}
 128
 129static void auto_nego_timer_callback(struct tse_pcs *pcs)
 130{
 131        u16 val = 0;
 132        u16 speed = 0;
 133        u16 duplex = 0;
 134        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 135        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 136
 137        val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
 138        val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
 139
 140        if (val != 0) {
 141                dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
 142                val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
 143                speed = val & TSE_PCS_PARTNER_SPEED_MASK;
 144                duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
 145
 146                if (speed == TSE_PCS_PARTNER_SPEED_10 &&
 147                    duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 148                        dev_dbg(pcs->dev,
 149                                "Adapter: Link Partner is Up - 10/Full\n");
 150                else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
 151                         duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 152                        dev_dbg(pcs->dev,
 153                                "Adapter: Link Partner is Up - 100/Full\n");
 154                else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
 155                         duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 156                        dev_dbg(pcs->dev,
 157                                "Adapter: Link Partner is Up - 1000/Full\n");
 158                else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
 159                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 160                        dev_err(pcs->dev,
 161                                "Adapter does not support Half Duplex\n");
 162                else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
 163                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 164                        dev_err(pcs->dev,
 165                                "Adapter does not support Half Duplex\n");
 166                else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
 167                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 168                        dev_err(pcs->dev,
 169                                "Adapter does not support Half Duplex\n");
 170                else
 171                        dev_err(pcs->dev,
 172                                "Adapter: Invalid Partner Speed and Duplex\n");
 173
 174                if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
 175                    (speed == TSE_PCS_PARTNER_SPEED_10 ||
 176                     speed == TSE_PCS_PARTNER_SPEED_100 ||
 177                     speed == TSE_PCS_PARTNER_SPEED_1000))
 178                        writew(SGMII_ADAPTER_ENABLE,
 179                               sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 180        } else {
 181                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 182                val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
 183                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 184
 185                tse_pcs_reset(tse_pcs_base, pcs);
 186                mod_timer(&pcs->aneg_link_timer, jiffies +
 187                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 188        }
 189}
 190
 191static void aneg_link_timer_callback(struct timer_list *t)
 192{
 193        struct tse_pcs *pcs = from_timer(pcs, t, aneg_link_timer);
 194
 195        if (pcs->autoneg == AUTONEG_ENABLE)
 196                auto_nego_timer_callback(pcs);
 197        else if (pcs->autoneg == AUTONEG_DISABLE)
 198                pcs_link_timer_callback(pcs);
 199}
 200
 201void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
 202                           unsigned int speed)
 203{
 204        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 205        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 206        u32 val;
 207
 208        writew(SGMII_ADAPTER_ENABLE,
 209               sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 210
 211        pcs->autoneg = phy_dev->autoneg;
 212
 213        if (phy_dev->autoneg == AUTONEG_ENABLE) {
 214                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 215                val |= TSE_PCS_CONTROL_AN_EN_MASK;
 216                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 217
 218                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 219                val |= TSE_PCS_USE_SGMII_AN_MASK;
 220                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 221
 222                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 223                val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
 224
 225                tse_pcs_reset(tse_pcs_base, pcs);
 226
 227                timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
 228                            0);
 229                mod_timer(&pcs->aneg_link_timer, jiffies +
 230                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 231        } else if (phy_dev->autoneg == AUTONEG_DISABLE) {
 232                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 233                val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
 234                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 235
 236                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 237                val &= ~TSE_PCS_USE_SGMII_AN_MASK;
 238                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 239
 240                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 241                val &= ~TSE_PCS_SGMII_SPEED_MASK;
 242
 243                switch (speed) {
 244                case 1000:
 245                        val |= TSE_PCS_SGMII_SPEED_1000;
 246                        break;
 247                case 100:
 248                        val |= TSE_PCS_SGMII_SPEED_100;
 249                        break;
 250                case 10:
 251                        val |= TSE_PCS_SGMII_SPEED_10;
 252                        break;
 253                default:
 254                        return;
 255                }
 256                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 257
 258                tse_pcs_reset(tse_pcs_base, pcs);
 259
 260                timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
 261                            0);
 262                mod_timer(&pcs->aneg_link_timer, jiffies +
 263                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 264        }
 265}
 266