The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cxgb/common/cxgb_mv88e1xxx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**************************************************************************
    2 SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3 
    4 Copyright (c) 2007, Chelsio Inc.
    5 All rights reserved.
    6 
    7 Redistribution and use in source and binary forms, with or without
    8 modification, are permitted provided that the following conditions are met:
    9 
   10  1. Redistributions of source code must retain the above copyright notice,
   11     this list of conditions and the following disclaimer.
   12 
   13  2. Neither the name of the Chelsio Corporation nor the names of its
   14     contributors may be used to endorse or promote products derived from
   15     this software without specific prior written permission.
   16 
   17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27 POSSIBILITY OF SUCH DAMAGE.
   28 
   29 ***************************************************************************/
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <cxgb_include.h>
   35 
   36 /* Marvell PHY interrupt status bits. */
   37 #define MV_INTR_JABBER          0x0001
   38 #define MV_INTR_POLARITY_CHNG   0x0002
   39 #define MV_INTR_ENG_DETECT_CHNG 0x0010
   40 #define MV_INTR_DOWNSHIFT       0x0020
   41 #define MV_INTR_MDI_XOVER_CHNG  0x0040
   42 #define MV_INTR_FIFO_OVER_UNDER 0x0080
   43 #define MV_INTR_FALSE_CARRIER   0x0100
   44 #define MV_INTR_SYMBOL_ERROR    0x0200
   45 #define MV_INTR_LINK_CHNG       0x0400
   46 #define MV_INTR_AUTONEG_DONE    0x0800
   47 #define MV_INTR_PAGE_RECV       0x1000
   48 #define MV_INTR_DUPLEX_CHNG     0x2000
   49 #define MV_INTR_SPEED_CHNG      0x4000
   50 #define MV_INTR_AUTONEG_ERR     0x8000
   51 
   52 /* Marvell PHY specific registers. */
   53 #define MV88E1XXX_SPECIFIC_CNTRL          16
   54 #define MV88E1XXX_SPECIFIC_STATUS         17
   55 #define MV88E1XXX_INTR_ENABLE             18
   56 #define MV88E1XXX_INTR_STATUS             19
   57 #define MV88E1XXX_EXT_SPECIFIC_CNTRL      20
   58 #define MV88E1XXX_RECV_ERR                21
   59 #define MV88E1XXX_EXT_ADDR                22
   60 #define MV88E1XXX_GLOBAL_STATUS           23
   61 #define MV88E1XXX_LED_CNTRL               24
   62 #define MV88E1XXX_LED_OVERRIDE            25
   63 #define MV88E1XXX_EXT_SPECIFIC_CNTRL2     26
   64 #define MV88E1XXX_EXT_SPECIFIC_STATUS     27
   65 #define MV88E1XXX_VIRTUAL_CABLE_TESTER    28
   66 #define MV88E1XXX_EXTENDED_ADDR           29
   67 #define MV88E1XXX_EXTENDED_DATA           30
   68 
   69 /* PHY specific control register fields */
   70 #define S_PSCR_MDI_XOVER_MODE    5
   71 #define M_PSCR_MDI_XOVER_MODE    0x3
   72 #define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
   73 
   74 /* Extended PHY specific control register fields */
   75 #define S_DOWNSHIFT_ENABLE 8
   76 #define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
   77 
   78 #define S_DOWNSHIFT_CNT    9
   79 #define M_DOWNSHIFT_CNT    0x7
   80 #define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
   81 
   82 /* PHY specific status register fields */
   83 #define S_PSSR_JABBER 0
   84 #define V_PSSR_JABBER (1 << S_PSSR_JABBER)
   85 
   86 #define S_PSSR_POLARITY 1
   87 #define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
   88 
   89 #define S_PSSR_RX_PAUSE 2
   90 #define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
   91 
   92 #define S_PSSR_TX_PAUSE 3
   93 #define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
   94 
   95 #define S_PSSR_ENERGY_DETECT 4
   96 #define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
   97 
   98 #define S_PSSR_DOWNSHIFT_STATUS 5
   99 #define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
  100 
  101 #define S_PSSR_MDI 6
  102 #define V_PSSR_MDI (1 << S_PSSR_MDI)
  103 
  104 #define S_PSSR_CABLE_LEN    7
  105 #define M_PSSR_CABLE_LEN    0x7
  106 #define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
  107 #define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
  108 
  109 #define S_PSSR_LINK 10
  110 #define V_PSSR_LINK (1 << S_PSSR_LINK)
  111 
  112 #define S_PSSR_STATUS_RESOLVED 11
  113 #define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
  114 
  115 #define S_PSSR_PAGE_RECEIVED 12
  116 #define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
  117 
  118 #define S_PSSR_DUPLEX 13
  119 #define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
  120 
  121 #define S_PSSR_SPEED    14
  122 #define M_PSSR_SPEED    0x3
  123 #define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
  124 #define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
  125 
  126 /* MV88E1XXX MDI crossover register values */
  127 #define CROSSOVER_MDI   0
  128 #define CROSSOVER_MDIX  1
  129 #define CROSSOVER_AUTO  3
  130 
  131 #define INTR_ENABLE_MASK (MV_INTR_SPEED_CHNG | MV_INTR_DUPLEX_CHNG | \
  132         MV_INTR_AUTONEG_DONE | MV_INTR_LINK_CHNG | MV_INTR_FIFO_OVER_UNDER | \
  133         MV_INTR_ENG_DETECT_CHNG)
  134 
  135 /*
  136  * Reset the PHY.  If 'wait' is set wait until the reset completes.
  137  */
  138 static int mv88e1xxx_reset(struct cphy *cphy, int wait)
  139 {
  140         return t3_phy_reset(cphy, 0, wait);
  141 }
  142 
  143 static int mv88e1xxx_intr_enable(struct cphy *cphy)
  144 {
  145         return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, INTR_ENABLE_MASK);
  146 }
  147 
  148 static int mv88e1xxx_intr_disable(struct cphy *cphy)
  149 {
  150         return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, 0);
  151 }
  152 
  153 static int mv88e1xxx_intr_clear(struct cphy *cphy)
  154 {
  155         u32 val;
  156 
  157         /* Clear PHY interrupts by reading the register. */
  158         return mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &val);
  159 }
  160 
  161 static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
  162 {
  163         return t3_mdio_change_bits(cphy, 0, MV88E1XXX_SPECIFIC_CNTRL,
  164                                    V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE),
  165                                    V_PSCR_MDI_XOVER_MODE(crossover));
  166 }
  167 
  168 static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
  169 {
  170         mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
  171 
  172         /* restart autoneg for change to take effect */
  173         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  174                                    BMCR_ANENABLE | BMCR_ANRESTART);
  175 }
  176 
  177 static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
  178 {
  179         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  180                                    BMCR_ANRESTART);
  181 }
  182 
  183 static int mv88e1xxx_set_loopback(struct cphy *cphy, int mmd, int dir, int on)
  184 {
  185         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_LOOPBACK,
  186                                    on ? BMCR_LOOPBACK : 0);
  187 }
  188 
  189 static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_state,
  190                                      int *speed, int *duplex, int *fc)
  191 {
  192         u32 status;
  193         int sp = -1, dplx = -1, pause = 0;
  194 
  195         mdio_read(cphy, 0, MV88E1XXX_SPECIFIC_STATUS, &status);
  196         if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
  197                 if (status & V_PSSR_RX_PAUSE)
  198                         pause |= PAUSE_RX;
  199                 if (status & V_PSSR_TX_PAUSE)
  200                         pause |= PAUSE_TX;
  201                 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
  202                 sp = G_PSSR_SPEED(status);
  203                 if (sp == 0)
  204                         sp = SPEED_10;
  205                 else if (sp == 1)
  206                         sp = SPEED_100;
  207                 else
  208                         sp = SPEED_1000;
  209         }
  210         if (link_state)
  211                 *link_state = status & V_PSSR_LINK ? PHY_LINK_UP :
  212                     PHY_LINK_DOWN;
  213         if (speed)
  214                 *speed = sp;
  215         if (duplex)
  216                 *duplex = dplx;
  217         if (fc)
  218                 *fc = pause;
  219         return 0;
  220 }
  221 
  222 static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
  223 {
  224         int err = t3_set_phy_speed_duplex(phy, speed, duplex);
  225 
  226         /* PHY needs reset for new settings to take effect */
  227         if (!err)
  228                 err = mv88e1xxx_reset(phy, 0);
  229         return err;
  230 }
  231 
  232 static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
  233 {
  234         /*
  235          * Set the downshift counter to 2 so we try to establish Gb link
  236          * twice before downshifting.
  237          */
  238         return t3_mdio_change_bits(cphy, 0, MV88E1XXX_EXT_SPECIFIC_CNTRL,
  239                 V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT),
  240                 downshift_enable ? V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2) : 0);
  241 }
  242 
  243 static int mv88e1xxx_power_down(struct cphy *cphy, int enable)
  244 {
  245         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
  246                                    enable ? BMCR_PDOWN : 0);
  247 }
  248 
  249 static int mv88e1xxx_intr_handler(struct cphy *cphy)
  250 {
  251         const u32 link_change_intrs = MV_INTR_LINK_CHNG |
  252                 MV_INTR_AUTONEG_DONE | MV_INTR_DUPLEX_CHNG |
  253                 MV_INTR_SPEED_CHNG | MV_INTR_DOWNSHIFT;
  254 
  255         u32 cause;
  256         int cphy_cause = 0;
  257 
  258         mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &cause);
  259         cause &= INTR_ENABLE_MASK;
  260         if (cause & link_change_intrs)
  261                 cphy_cause |= cphy_cause_link_change;
  262         if (cause & MV_INTR_FIFO_OVER_UNDER)
  263                 cphy_cause |= cphy_cause_fifo_error;
  264         return cphy_cause;
  265 }
  266 
  267 #ifdef C99_NOT_SUPPORTED
  268 static struct cphy_ops mv88e1xxx_ops = {
  269         mv88e1xxx_reset,
  270         mv88e1xxx_intr_enable,
  271         mv88e1xxx_intr_disable,
  272         mv88e1xxx_intr_clear,
  273         mv88e1xxx_intr_handler,
  274         mv88e1xxx_autoneg_enable,
  275         mv88e1xxx_autoneg_restart,
  276         t3_phy_advertise,
  277         mv88e1xxx_set_loopback,
  278         mv88e1xxx_set_speed_duplex,
  279         mv88e1xxx_get_link_status,
  280         mv88e1xxx_power_down,
  281 };
  282 #else
  283 static struct cphy_ops mv88e1xxx_ops = {
  284         .reset             = mv88e1xxx_reset,
  285         .intr_enable       = mv88e1xxx_intr_enable,
  286         .intr_disable      = mv88e1xxx_intr_disable,
  287         .intr_clear        = mv88e1xxx_intr_clear,
  288         .intr_handler      = mv88e1xxx_intr_handler,
  289         .autoneg_enable    = mv88e1xxx_autoneg_enable,
  290         .autoneg_restart   = mv88e1xxx_autoneg_restart,
  291         .advertise         = t3_phy_advertise,
  292         .set_loopback      = mv88e1xxx_set_loopback,
  293         .set_speed_duplex  = mv88e1xxx_set_speed_duplex,
  294         .get_link_status   = mv88e1xxx_get_link_status,
  295         .power_down        = mv88e1xxx_power_down,
  296 };
  297 #endif
  298 
  299 int t3_mv88e1xxx_phy_prep(pinfo_t *pinfo, int phy_addr,
  300                           const struct mdio_ops *mdio_ops)
  301 {
  302         struct cphy *phy = &pinfo->phy;
  303         int err;
  304 
  305         cphy_init(phy, pinfo->adapter, pinfo, phy_addr, &mv88e1xxx_ops, mdio_ops,
  306                   SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
  307                   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
  308                   SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
  309 
  310         /* Configure copper PHY transmitter as class A to reduce EMI. */
  311         err = mdio_write(phy, 0, MV88E1XXX_EXTENDED_ADDR, 0xb);
  312         if (!err)
  313                 err = mdio_write(phy, 0, MV88E1XXX_EXTENDED_DATA, 0x8004);
  314 
  315         if (!err)
  316                 err = mv88e1xxx_downshift_set(phy, 1);   /* Enable downshift */
  317         return err;
  318 }

Cache object: f69c2c7d61227d2d803a6e97dc4f2cd0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.