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(unsigned long data)
 122{
 123        u16 val = 0;
 124        struct tse_pcs *pcs = (struct tse_pcs *)data;
 125        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 126        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 127
 128        val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
 129        val &= TSE_PCS_STATUS_LINK_MASK;
 130
 131        if (val != 0) {
 132                dev_dbg(pcs->dev, "Adapter: Link is established\n");
 133                writew(SGMII_ADAPTER_ENABLE,
 134                       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 135        } else {
 136                mod_timer(&pcs->aneg_link_timer, jiffies +
 137                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 138        }
 139}
 140
 141static void auto_nego_timer_callback(unsigned long data)
 142{
 143        u16 val = 0;
 144        u16 speed = 0;
 145        u16 duplex = 0;
 146        struct tse_pcs *pcs = (struct tse_pcs *)data;
 147        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 148        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 149
 150        val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
 151        val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
 152
 153        if (val != 0) {
 154                dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
 155                val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
 156                speed = val & TSE_PCS_PARTNER_SPEED_MASK;
 157                duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
 158
 159                if (speed == TSE_PCS_PARTNER_SPEED_10 &&
 160                    duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 161                        dev_dbg(pcs->dev,
 162                                "Adapter: Link Partner is Up - 10/Full\n");
 163                else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
 164                         duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 165                        dev_dbg(pcs->dev,
 166                                "Adapter: Link Partner is Up - 100/Full\n");
 167                else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
 168                         duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
 169                        dev_dbg(pcs->dev,
 170                                "Adapter: Link Partner is Up - 1000/Full\n");
 171                else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
 172                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 173                        dev_err(pcs->dev,
 174                                "Adapter does not support Half Duplex\n");
 175                else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
 176                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 177                        dev_err(pcs->dev,
 178                                "Adapter does not support Half Duplex\n");
 179                else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
 180                         duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
 181                        dev_err(pcs->dev,
 182                                "Adapter does not support Half Duplex\n");
 183                else
 184                        dev_err(pcs->dev,
 185                                "Adapter: Invalid Partner Speed and Duplex\n");
 186
 187                if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
 188                    (speed == TSE_PCS_PARTNER_SPEED_10 ||
 189                     speed == TSE_PCS_PARTNER_SPEED_100 ||
 190                     speed == TSE_PCS_PARTNER_SPEED_1000))
 191                        writew(SGMII_ADAPTER_ENABLE,
 192                               sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 193        } else {
 194                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 195                val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
 196                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 197
 198                tse_pcs_reset(tse_pcs_base, pcs);
 199                mod_timer(&pcs->aneg_link_timer, jiffies +
 200                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 201        }
 202}
 203
 204static void aneg_link_timer_callback(unsigned long data)
 205{
 206        struct tse_pcs *pcs = (struct tse_pcs *)data;
 207
 208        if (pcs->autoneg == AUTONEG_ENABLE)
 209                auto_nego_timer_callback(data);
 210        else if (pcs->autoneg == AUTONEG_DISABLE)
 211                pcs_link_timer_callback(data);
 212}
 213
 214void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
 215                           unsigned int speed)
 216{
 217        void __iomem *tse_pcs_base = pcs->tse_pcs_base;
 218        void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
 219        u32 val;
 220
 221        writew(SGMII_ADAPTER_ENABLE,
 222               sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
 223
 224        pcs->autoneg = phy_dev->autoneg;
 225
 226        if (phy_dev->autoneg == AUTONEG_ENABLE) {
 227                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 228                val |= TSE_PCS_CONTROL_AN_EN_MASK;
 229                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 230
 231                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 232                val |= TSE_PCS_USE_SGMII_AN_MASK;
 233                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 234
 235                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 236                val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
 237
 238                tse_pcs_reset(tse_pcs_base, pcs);
 239
 240                setup_timer(&pcs->aneg_link_timer,
 241                            aneg_link_timer_callback, (unsigned long)pcs);
 242                mod_timer(&pcs->aneg_link_timer, jiffies +
 243                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 244        } else if (phy_dev->autoneg == AUTONEG_DISABLE) {
 245                val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
 246                val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
 247                writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
 248
 249                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 250                val &= ~TSE_PCS_USE_SGMII_AN_MASK;
 251                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 252
 253                val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
 254                val &= ~TSE_PCS_SGMII_SPEED_MASK;
 255
 256                switch (speed) {
 257                case 1000:
 258                        val |= TSE_PCS_SGMII_SPEED_1000;
 259                        break;
 260                case 100:
 261                        val |= TSE_PCS_SGMII_SPEED_100;
 262                        break;
 263                case 10:
 264                        val |= TSE_PCS_SGMII_SPEED_10;
 265                        break;
 266                default:
 267                        return;
 268                }
 269                writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
 270
 271                tse_pcs_reset(tse_pcs_base, pcs);
 272
 273                setup_timer(&pcs->aneg_link_timer,
 274                            aneg_link_timer_callback, (unsigned long)pcs);
 275                mod_timer(&pcs->aneg_link_timer, jiffies +
 276                          msecs_to_jiffies(AUTONEGO_LINK_TIMER));
 277        }
 278}
 279