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

Cache object: 6b68cd0cbe7b452533d336c3b435d23c


[ 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.