root/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tse_pcs_reset
  2. tse_pcs_init
  3. pcs_link_timer_callback
  4. auto_nego_timer_callback
  5. aneg_link_timer_callback
  6. tse_pcs_fix_mac_speed

   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 
  66 static 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 
  91 int 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 
 110 static 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 
 129 static 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 
 191 static 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 
 201 void 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 }

/* [<][>][^][v][top][bottom][index][help] */