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/6.4/sys/dev/cxgb/common/cxgb_mv88e1xxx.c 170900 2007-06-17 23:52:17Z kmacy $");
   32 
   33 #ifdef CONFIG_DEFINED
   34 #include <cxgb_include.h>
   35 #else
   36 #include <dev/cxgb/cxgb_include.h>
   37 #endif
   38 
   39 /* Marvell PHY interrupt status bits. */
   40 #define MV_INTR_JABBER          0x0001
   41 #define MV_INTR_POLARITY_CHNG   0x0002
   42 #define MV_INTR_ENG_DETECT_CHNG 0x0010
   43 #define MV_INTR_DOWNSHIFT       0x0020
   44 #define MV_INTR_MDI_XOVER_CHNG  0x0040
   45 #define MV_INTR_FIFO_OVER_UNDER 0x0080
   46 #define MV_INTR_FALSE_CARRIER   0x0100
   47 #define MV_INTR_SYMBOL_ERROR    0x0200
   48 #define MV_INTR_LINK_CHNG       0x0400
   49 #define MV_INTR_AUTONEG_DONE    0x0800
   50 #define MV_INTR_PAGE_RECV       0x1000
   51 #define MV_INTR_DUPLEX_CHNG     0x2000
   52 #define MV_INTR_SPEED_CHNG      0x4000
   53 #define MV_INTR_AUTONEG_ERR     0x8000
   54 
   55 /* Marvell PHY specific registers. */
   56 #define MV88E1XXX_SPECIFIC_CNTRL          16
   57 #define MV88E1XXX_SPECIFIC_STATUS         17
   58 #define MV88E1XXX_INTR_ENABLE             18
   59 #define MV88E1XXX_INTR_STATUS             19
   60 #define MV88E1XXX_EXT_SPECIFIC_CNTRL      20
   61 #define MV88E1XXX_RECV_ERR                21
   62 #define MV88E1XXX_EXT_ADDR                22
   63 #define MV88E1XXX_GLOBAL_STATUS           23
   64 #define MV88E1XXX_LED_CNTRL               24
   65 #define MV88E1XXX_LED_OVERRIDE            25
   66 #define MV88E1XXX_EXT_SPECIFIC_CNTRL2     26
   67 #define MV88E1XXX_EXT_SPECIFIC_STATUS     27
   68 #define MV88E1XXX_VIRTUAL_CABLE_TESTER    28
   69 #define MV88E1XXX_EXTENDED_ADDR           29
   70 #define MV88E1XXX_EXTENDED_DATA           30
   71 
   72 /* PHY specific control register fields */
   73 #define S_PSCR_MDI_XOVER_MODE    5
   74 #define M_PSCR_MDI_XOVER_MODE    0x3
   75 #define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
   76 
   77 /* Extended PHY specific control register fields */
   78 #define S_DOWNSHIFT_ENABLE 8
   79 #define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
   80 
   81 #define S_DOWNSHIFT_CNT    9
   82 #define M_DOWNSHIFT_CNT    0x7
   83 #define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
   84 
   85 /* PHY specific status register fields */
   86 #define S_PSSR_JABBER 0
   87 #define V_PSSR_JABBER (1 << S_PSSR_JABBER)
   88 
   89 #define S_PSSR_POLARITY 1
   90 #define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
   91 
   92 #define S_PSSR_RX_PAUSE 2
   93 #define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
   94 
   95 #define S_PSSR_TX_PAUSE 3
   96 #define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
   97 
   98 #define S_PSSR_ENERGY_DETECT 4
   99 #define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
  100 
  101 #define S_PSSR_DOWNSHIFT_STATUS 5
  102 #define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
  103 
  104 #define S_PSSR_MDI 6
  105 #define V_PSSR_MDI (1 << S_PSSR_MDI)
  106 
  107 #define S_PSSR_CABLE_LEN    7
  108 #define M_PSSR_CABLE_LEN    0x7
  109 #define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
  110 #define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
  111 
  112 #define S_PSSR_LINK 10
  113 #define V_PSSR_LINK (1 << S_PSSR_LINK)
  114 
  115 #define S_PSSR_STATUS_RESOLVED 11
  116 #define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
  117 
  118 #define S_PSSR_PAGE_RECEIVED 12
  119 #define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
  120 
  121 #define S_PSSR_DUPLEX 13
  122 #define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
  123 
  124 #define S_PSSR_SPEED    14
  125 #define M_PSSR_SPEED    0x3
  126 #define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
  127 #define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
  128 
  129 /* MV88E1XXX MDI crossover register values */
  130 #define CROSSOVER_MDI   0
  131 #define CROSSOVER_MDIX  1
  132 #define CROSSOVER_AUTO  3
  133 
  134 #define INTR_ENABLE_MASK (MV_INTR_SPEED_CHNG | MV_INTR_DUPLEX_CHNG | \
  135         MV_INTR_AUTONEG_DONE | MV_INTR_LINK_CHNG | MV_INTR_FIFO_OVER_UNDER | \
  136         MV_INTR_ENG_DETECT_CHNG)
  137 
  138 /*
  139  * Reset the PHY.  If 'wait' is set wait until the reset completes.
  140  */
  141 static int mv88e1xxx_reset(struct cphy *cphy, int wait)
  142 {
  143         return t3_phy_reset(cphy, 0, wait);
  144 }
  145 
  146 static int mv88e1xxx_intr_enable(struct cphy *cphy)
  147 {
  148         return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, INTR_ENABLE_MASK);
  149 }
  150 
  151 static int mv88e1xxx_intr_disable(struct cphy *cphy)
  152 {
  153         return mdio_write(cphy, 0, MV88E1XXX_INTR_ENABLE, 0);
  154 }
  155 
  156 static int mv88e1xxx_intr_clear(struct cphy *cphy)
  157 {
  158         u32 val;
  159 
  160         /* Clear PHY interrupts by reading the register. */
  161         return mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &val);
  162 }
  163 
  164 static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
  165 {
  166         return t3_mdio_change_bits(cphy, 0, MV88E1XXX_SPECIFIC_CNTRL,
  167                                    V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE),
  168                                    V_PSCR_MDI_XOVER_MODE(crossover));
  169 }
  170 
  171 static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
  172 {
  173         mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
  174 
  175         /* restart autoneg for change to take effect */
  176         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  177                                    BMCR_ANENABLE | BMCR_ANRESTART);
  178 }
  179 
  180 static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
  181 {
  182         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  183                                    BMCR_ANRESTART);
  184 }
  185 
  186 static int mv88e1xxx_set_loopback(struct cphy *cphy, int mmd, int dir, int on)
  187 {
  188         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_LOOPBACK,
  189                                    on ? BMCR_LOOPBACK : 0);
  190 }
  191 
  192 static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
  193                                      int *speed, int *duplex, int *fc)
  194 {
  195         u32 status;
  196         int sp = -1, dplx = -1, pause = 0;
  197 
  198         mdio_read(cphy, 0, MV88E1XXX_SPECIFIC_STATUS, &status);
  199         if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
  200                 if (status & V_PSSR_RX_PAUSE)
  201                         pause |= PAUSE_RX;
  202                 if (status & V_PSSR_TX_PAUSE)
  203                         pause |= PAUSE_TX;
  204                 dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
  205                 sp = G_PSSR_SPEED(status);
  206                 if (sp == 0)
  207                         sp = SPEED_10;
  208                 else if (sp == 1)
  209                         sp = SPEED_100;
  210                 else
  211                         sp = SPEED_1000;
  212         }
  213         if (link_ok)
  214                 *link_ok = (status & V_PSSR_LINK) != 0;
  215         if (speed)
  216                 *speed = sp;
  217         if (duplex)
  218                 *duplex = dplx;
  219         if (fc)
  220                 *fc = pause;
  221         return 0;
  222 }
  223 
  224 static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
  225 {
  226         /*
  227          * Set the downshift counter to 2 so we try to establish Gb link
  228          * twice before downshifting.
  229          */
  230         return t3_mdio_change_bits(cphy, 0, MV88E1XXX_EXT_SPECIFIC_CNTRL,
  231                 V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT),
  232                 downshift_enable ? V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2) : 0);
  233 }
  234 
  235 static int mv88e1xxx_power_down(struct cphy *cphy, int enable)
  236 {
  237         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
  238                                    enable ? BMCR_PDOWN : 0);
  239 }
  240 
  241 static int mv88e1xxx_intr_handler(struct cphy *cphy)
  242 {
  243         const u32 link_change_intrs = MV_INTR_LINK_CHNG |
  244                 MV_INTR_AUTONEG_DONE | MV_INTR_DUPLEX_CHNG |
  245                 MV_INTR_SPEED_CHNG | MV_INTR_DOWNSHIFT;
  246 
  247         u32 cause;
  248         int cphy_cause = 0;
  249 
  250         mdio_read(cphy, 0, MV88E1XXX_INTR_STATUS, &cause);
  251         cause &= INTR_ENABLE_MASK;
  252         if (cause & link_change_intrs)
  253                 cphy_cause |= cphy_cause_link_change;
  254         if (cause & MV_INTR_FIFO_OVER_UNDER)
  255                 cphy_cause |= cphy_cause_fifo_error;
  256         return cphy_cause;
  257 }
  258 
  259 #ifdef C99_NOT_SUPPORTED
  260 static struct cphy_ops mv88e1xxx_ops = {
  261         NULL,
  262         mv88e1xxx_reset,
  263         mv88e1xxx_intr_enable,
  264         mv88e1xxx_intr_disable,
  265         mv88e1xxx_intr_clear,
  266         mv88e1xxx_intr_handler,
  267         mv88e1xxx_autoneg_enable,
  268         mv88e1xxx_autoneg_restart,
  269         t3_phy_advertise,
  270         mv88e1xxx_set_loopback,
  271         t3_set_phy_speed_duplex,
  272         mv88e1xxx_get_link_status,
  273         mv88e1xxx_power_down,
  274 };
  275 #else
  276 static struct cphy_ops mv88e1xxx_ops = {
  277         .reset             = mv88e1xxx_reset,
  278         .intr_enable       = mv88e1xxx_intr_enable,
  279         .intr_disable      = mv88e1xxx_intr_disable,
  280         .intr_clear        = mv88e1xxx_intr_clear,
  281         .intr_handler      = mv88e1xxx_intr_handler,
  282         .autoneg_enable    = mv88e1xxx_autoneg_enable,
  283         .autoneg_restart   = mv88e1xxx_autoneg_restart,
  284         .advertise         = t3_phy_advertise,
  285         .set_loopback      = mv88e1xxx_set_loopback,
  286         .set_speed_duplex  = t3_set_phy_speed_duplex,
  287         .get_link_status   = mv88e1xxx_get_link_status,
  288         .power_down        = mv88e1xxx_power_down,
  289 };
  290 #endif
  291 
  292 void t3_mv88e1xxx_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
  293                            const struct mdio_ops *mdio_ops)
  294 {
  295         cphy_init(phy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
  296 
  297         /* Configure copper PHY transmitter as class A to reduce EMI. */
  298         mdio_write(phy, 0, MV88E1XXX_EXTENDED_ADDR, 0xb);
  299         mdio_write(phy, 0, MV88E1XXX_EXTENDED_DATA, 0x8004);
  300                 
  301         mv88e1xxx_downshift_set(phy, 1);   /* Enable downshift */
  302 }

Cache object: 6a807e0ccf6308c51a35d2db56936828


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