root/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c

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

DEFINITIONS

This source file includes following definitions.
  1. mdio_set_bit
  2. mdio_clear_bit
  3. mv88e1xxx_reset
  4. mv88e1xxx_interrupt_enable
  5. mv88e1xxx_interrupt_disable
  6. mv88e1xxx_interrupt_clear
  7. mv88e1xxx_set_speed_duplex
  8. mv88e1xxx_crossover_set
  9. mv88e1xxx_autoneg_enable
  10. mv88e1xxx_autoneg_disable
  11. mv88e1xxx_autoneg_restart
  12. mv88e1xxx_advertise
  13. mv88e1xxx_set_loopback
  14. mv88e1xxx_get_link_status
  15. mv88e1xxx_downshift_set
  16. mv88e1xxx_interrupt_handler
  17. mv88e1xxx_destroy
  18. mv88e1xxx_phy_create
  19. mv88e1xxx_phy_reset

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */
   3 #include "common.h"
   4 #include "mv88e1xxx.h"
   5 #include "cphy.h"
   6 #include "elmer0.h"
   7 
   8 /* MV88E1XXX MDI crossover register values */
   9 #define CROSSOVER_MDI   0
  10 #define CROSSOVER_MDIX  1
  11 #define CROSSOVER_AUTO  3
  12 
  13 #define INTR_ENABLE_MASK 0x6CA0
  14 
  15 /*
  16  * Set the bits given by 'bitval' in PHY register 'reg'.
  17  */
  18 static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
  19 {
  20         u32 val;
  21 
  22         (void) simple_mdio_read(cphy, reg, &val);
  23         (void) simple_mdio_write(cphy, reg, val | bitval);
  24 }
  25 
  26 /*
  27  * Clear the bits given by 'bitval' in PHY register 'reg'.
  28  */
  29 static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
  30 {
  31         u32 val;
  32 
  33         (void) simple_mdio_read(cphy, reg, &val);
  34         (void) simple_mdio_write(cphy, reg, val & ~bitval);
  35 }
  36 
  37 /*
  38  * NAME:   phy_reset
  39  *
  40  * DESC:   Reset the given PHY's port. NOTE: This is not a global
  41  *         chip reset.
  42  *
  43  * PARAMS: cphy     - Pointer to PHY instance data.
  44  *
  45  * RETURN:  0 - Successful reset.
  46  *         -1 - Timeout.
  47  */
  48 static int mv88e1xxx_reset(struct cphy *cphy, int wait)
  49 {
  50         u32 ctl;
  51         int time_out = 1000;
  52 
  53         mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
  54 
  55         do {
  56                 (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
  57                 ctl &= BMCR_RESET;
  58                 if (ctl)
  59                         udelay(1);
  60         } while (ctl && --time_out);
  61 
  62         return ctl ? -1 : 0;
  63 }
  64 
  65 static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
  66 {
  67         /* Enable PHY interrupts. */
  68         (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
  69                    INTR_ENABLE_MASK);
  70 
  71         /* Enable Marvell interrupts through Elmer0. */
  72         if (t1_is_asic(cphy->adapter)) {
  73                 u32 elmer;
  74 
  75                 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
  76                 elmer |= ELMER0_GP_BIT1;
  77                 if (is_T2(cphy->adapter))
  78                     elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
  79                 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
  80         }
  81         return 0;
  82 }
  83 
  84 static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
  85 {
  86         /* Disable all phy interrupts. */
  87         (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
  88 
  89         /* Disable Marvell interrupts through Elmer0. */
  90         if (t1_is_asic(cphy->adapter)) {
  91                 u32 elmer;
  92 
  93                 t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
  94                 elmer &= ~ELMER0_GP_BIT1;
  95                 if (is_T2(cphy->adapter))
  96                     elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
  97                 t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
  98         }
  99         return 0;
 100 }
 101 
 102 static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
 103 {
 104         u32 elmer;
 105 
 106         /* Clear PHY interrupts by reading the register. */
 107         (void) simple_mdio_read(cphy,
 108                         MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
 109 
 110         /* Clear Marvell interrupts through Elmer0. */
 111         if (t1_is_asic(cphy->adapter)) {
 112                 t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
 113                 elmer |= ELMER0_GP_BIT1;
 114                 if (is_T2(cphy->adapter))
 115                     elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
 116                 t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
 117         }
 118         return 0;
 119 }
 120 
 121 /*
 122  * Set the PHY speed and duplex.  This also disables auto-negotiation, except
 123  * for 1Gb/s, where auto-negotiation is mandatory.
 124  */
 125 static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
 126 {
 127         u32 ctl;
 128 
 129         (void) simple_mdio_read(phy, MII_BMCR, &ctl);
 130         if (speed >= 0) {
 131                 ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
 132                 if (speed == SPEED_100)
 133                         ctl |= BMCR_SPEED100;
 134                 else if (speed == SPEED_1000)
 135                         ctl |= BMCR_SPEED1000;
 136         }
 137         if (duplex >= 0) {
 138                 ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
 139                 if (duplex == DUPLEX_FULL)
 140                         ctl |= BMCR_FULLDPLX;
 141         }
 142         if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for 1Gb/s */
 143                 ctl |= BMCR_ANENABLE;
 144         (void) simple_mdio_write(phy, MII_BMCR, ctl);
 145         return 0;
 146 }
 147 
 148 static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
 149 {
 150         u32 data32;
 151 
 152         (void) simple_mdio_read(cphy,
 153                         MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
 154         data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
 155         data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
 156         (void) simple_mdio_write(cphy,
 157                         MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
 158         return 0;
 159 }
 160 
 161 static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
 162 {
 163         u32 ctl;
 164 
 165         (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
 166 
 167         (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
 168         /* restart autoneg for change to take effect */
 169         ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
 170         (void) simple_mdio_write(cphy, MII_BMCR, ctl);
 171         return 0;
 172 }
 173 
 174 static int mv88e1xxx_autoneg_disable(struct cphy *cphy)
 175 {
 176         u32 ctl;
 177 
 178         /*
 179          * Crossover *must* be set to manual in order to disable auto-neg.
 180          * The Alaska FAQs document highlights this point.
 181          */
 182         (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
 183 
 184         /*
 185          * Must include autoneg reset when disabling auto-neg. This
 186          * is described in the Alaska FAQ document.
 187          */
 188         (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
 189         ctl &= ~BMCR_ANENABLE;
 190         (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
 191         return 0;
 192 }
 193 
 194 static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
 195 {
 196         mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
 197         return 0;
 198 }
 199 
 200 static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
 201 {
 202         u32 val = 0;
 203 
 204         if (advertise_map &
 205             (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
 206                 (void) simple_mdio_read(phy, MII_GBCR, &val);
 207                 val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
 208                 if (advertise_map & ADVERTISED_1000baseT_Half)
 209                         val |= GBCR_ADV_1000HALF;
 210                 if (advertise_map & ADVERTISED_1000baseT_Full)
 211                         val |= GBCR_ADV_1000FULL;
 212         }
 213         (void) simple_mdio_write(phy, MII_GBCR, val);
 214 
 215         val = 1;
 216         if (advertise_map & ADVERTISED_10baseT_Half)
 217                 val |= ADVERTISE_10HALF;
 218         if (advertise_map & ADVERTISED_10baseT_Full)
 219                 val |= ADVERTISE_10FULL;
 220         if (advertise_map & ADVERTISED_100baseT_Half)
 221                 val |= ADVERTISE_100HALF;
 222         if (advertise_map & ADVERTISED_100baseT_Full)
 223                 val |= ADVERTISE_100FULL;
 224         if (advertise_map & ADVERTISED_PAUSE)
 225                 val |= ADVERTISE_PAUSE;
 226         if (advertise_map & ADVERTISED_ASYM_PAUSE)
 227                 val |= ADVERTISE_PAUSE_ASYM;
 228         (void) simple_mdio_write(phy, MII_ADVERTISE, val);
 229         return 0;
 230 }
 231 
 232 static int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
 233 {
 234         if (on)
 235                 mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
 236         else
 237                 mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
 238         return 0;
 239 }
 240 
 241 static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
 242                                      int *speed, int *duplex, int *fc)
 243 {
 244         u32 status;
 245         int sp = -1, dplx = -1, pause = 0;
 246 
 247         (void) simple_mdio_read(cphy,
 248                         MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
 249         if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
 250                 if (status & V_PSSR_RX_PAUSE)
 251                         pause |= PAUSE_RX;
 252                 if (status & V_PSSR_TX_PAUSE)
 253                         pause |= PAUSE_TX;
 254                 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
 255                 sp = G_PSSR_SPEED(status);
 256                 if (sp == 0)
 257                         sp = SPEED_10;
 258                 else if (sp == 1)
 259                         sp = SPEED_100;
 260                 else
 261                         sp = SPEED_1000;
 262         }
 263         if (link_ok)
 264                 *link_ok = (status & V_PSSR_LINK) != 0;
 265         if (speed)
 266                 *speed = sp;
 267         if (duplex)
 268                 *duplex = dplx;
 269         if (fc)
 270                 *fc = pause;
 271         return 0;
 272 }
 273 
 274 static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
 275 {
 276         u32 val;
 277 
 278         (void) simple_mdio_read(cphy,
 279                 MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
 280 
 281         /*
 282          * Set the downshift counter to 2 so we try to establish Gb link
 283          * twice before downshifting.
 284          */
 285         val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
 286 
 287         if (downshift_enable)
 288                 val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
 289         (void) simple_mdio_write(cphy,
 290                         MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
 291         return 0;
 292 }
 293 
 294 static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
 295 {
 296         int cphy_cause = 0;
 297         u32 status;
 298 
 299         /*
 300          * Loop until cause reads zero. Need to handle bouncing interrupts.
 301          */
 302         while (1) {
 303                 u32 cause;
 304 
 305                 (void) simple_mdio_read(cphy,
 306                                 MV88E1XXX_INTERRUPT_STATUS_REGISTER,
 307                                 &cause);
 308                 cause &= INTR_ENABLE_MASK;
 309                 if (!cause)
 310                         break;
 311 
 312                 if (cause & MV88E1XXX_INTR_LINK_CHNG) {
 313                         (void) simple_mdio_read(cphy,
 314                                 MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
 315 
 316                         if (status & MV88E1XXX_INTR_LINK_CHNG)
 317                                 cphy->state |= PHY_LINK_UP;
 318                         else {
 319                                 cphy->state &= ~PHY_LINK_UP;
 320                                 if (cphy->state & PHY_AUTONEG_EN)
 321                                         cphy->state &= ~PHY_AUTONEG_RDY;
 322                                 cphy_cause |= cphy_cause_link_change;
 323                         }
 324                 }
 325 
 326                 if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
 327                         cphy->state |= PHY_AUTONEG_RDY;
 328 
 329                 if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
 330                         (PHY_LINK_UP | PHY_AUTONEG_RDY))
 331                                 cphy_cause |= cphy_cause_link_change;
 332         }
 333         return cphy_cause;
 334 }
 335 
 336 static void mv88e1xxx_destroy(struct cphy *cphy)
 337 {
 338         kfree(cphy);
 339 }
 340 
 341 static const struct cphy_ops mv88e1xxx_ops = {
 342         .destroy              = mv88e1xxx_destroy,
 343         .reset                = mv88e1xxx_reset,
 344         .interrupt_enable     = mv88e1xxx_interrupt_enable,
 345         .interrupt_disable    = mv88e1xxx_interrupt_disable,
 346         .interrupt_clear      = mv88e1xxx_interrupt_clear,
 347         .interrupt_handler    = mv88e1xxx_interrupt_handler,
 348         .autoneg_enable       = mv88e1xxx_autoneg_enable,
 349         .autoneg_disable      = mv88e1xxx_autoneg_disable,
 350         .autoneg_restart      = mv88e1xxx_autoneg_restart,
 351         .advertise            = mv88e1xxx_advertise,
 352         .set_loopback         = mv88e1xxx_set_loopback,
 353         .set_speed_duplex     = mv88e1xxx_set_speed_duplex,
 354         .get_link_status      = mv88e1xxx_get_link_status,
 355 };
 356 
 357 static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr,
 358                                          const struct mdio_ops *mdio_ops)
 359 {
 360         struct adapter *adapter = netdev_priv(dev);
 361         struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 362 
 363         if (!cphy)
 364                 return NULL;
 365 
 366         cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops);
 367 
 368         /* Configure particular PHY's to run in a different mode. */
 369         if ((board_info(adapter)->caps & SUPPORTED_TP) &&
 370             board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
 371                 /*
 372                  * Configure the PHY transmitter as class A to reduce EMI.
 373                  */
 374                 (void) simple_mdio_write(cphy,
 375                                 MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
 376                 (void) simple_mdio_write(cphy,
 377                                 MV88E1XXX_EXTENDED_REGISTER, 0x8004);
 378         }
 379         (void) mv88e1xxx_downshift_set(cphy, 1);   /* Enable downshift */
 380 
 381         /* LED */
 382         if (is_T2(adapter)) {
 383                 (void) simple_mdio_write(cphy,
 384                                 MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
 385         }
 386 
 387         return cphy;
 388 }
 389 
 390 static int mv88e1xxx_phy_reset(adapter_t* adapter)
 391 {
 392         return 0;
 393 }
 394 
 395 const struct gphy t1_mv88e1xxx_ops = {
 396         .create = mv88e1xxx_phy_create,
 397         .reset =  mv88e1xxx_phy_reset
 398 };

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