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