root/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c

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

DEFINITIONS

This source file includes following definitions.
  1. __cvmx_helper_sgmii_hardware_init_one_time
  2. __cvmx_helper_sgmii_hardware_init_link
  3. __cvmx_helper_sgmii_hardware_init_link_speed
  4. __cvmx_helper_sgmii_hardware_init
  5. __cvmx_helper_sgmii_enumerate
  6. __cvmx_helper_sgmii_probe
  7. __cvmx_helper_sgmii_enable
  8. __cvmx_helper_sgmii_link_get
  9. __cvmx_helper_sgmii_link_set

   1 /***********************license start***************
   2  * Author: Cavium Networks
   3  *
   4  * Contact: support@caviumnetworks.com
   5  * This file is part of the OCTEON SDK
   6  *
   7  * Copyright (C) 2003-2018 Cavium, Inc.
   8  *
   9  * This file is free software; you can redistribute it and/or modify
  10  * it under the terms of the GNU General Public License, Version 2, as
  11  * published by the Free Software Foundation.
  12  *
  13  * This file is distributed in the hope that it will be useful, but
  14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
  15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  16  * NONINFRINGEMENT.  See the GNU General Public License for more
  17  * details.
  18  *
  19  * You should have received a copy of the GNU General Public License
  20  * along with this file; if not, write to the Free Software
  21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22  * or visit http://www.gnu.org/licenses/.
  23  *
  24  * This file may also be available under a different license from Cavium.
  25  * Contact Cavium Networks for more information
  26  ***********************license end**************************************/
  27 
  28 /*
  29  * Functions for SGMII initialization, configuration,
  30  * and monitoring.
  31  */
  32 
  33 #include <asm/octeon/octeon.h>
  34 
  35 #include <asm/octeon/cvmx-config.h>
  36 
  37 #include <asm/octeon/cvmx-helper.h>
  38 #include <asm/octeon/cvmx-helper-board.h>
  39 
  40 #include <asm/octeon/cvmx-gmxx-defs.h>
  41 #include <asm/octeon/cvmx-pcsx-defs.h>
  42 #include <asm/octeon/cvmx-pcsxx-defs.h>
  43 
  44 /**
  45  * Perform initialization required only once for an SGMII port.
  46  *
  47  * @interface: Interface to init
  48  * @index:     Index of prot on the interface
  49  *
  50  * Returns Zero on success, negative on failure
  51  */
  52 static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
  53 {
  54         const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
  55         union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
  56         union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
  57         union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
  58 
  59         /* Disable GMX */
  60         gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
  61         gmxx_prtx_cfg.s.en = 0;
  62         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
  63 
  64         /*
  65          * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
  66          * appropriate value. 1000BASE-X specifies a 10ms
  67          * interval. SGMII specifies a 1.6ms interval.
  68          */
  69         pcs_misc_ctl_reg.u64 =
  70             cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
  71         pcsx_linkx_timer_count_reg.u64 =
  72             cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
  73         if (pcs_misc_ctl_reg.s.mode) {
  74                 /* 1000BASE-X */
  75                 pcsx_linkx_timer_count_reg.s.count =
  76                     (10000ull * clock_mhz) >> 10;
  77         } else {
  78                 /* SGMII */
  79                 pcsx_linkx_timer_count_reg.s.count =
  80                     (1600ull * clock_mhz) >> 10;
  81         }
  82         cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
  83                        pcsx_linkx_timer_count_reg.u64);
  84 
  85         /*
  86          * Write the advertisement register to be used as the
  87          * tx_Config_Reg<D15:D0> of the autonegotiation.  In
  88          * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
  89          * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
  90          * PCS*_SGM*_AN_ADV_REG.  In SGMII MAC mode,
  91          * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
  92          * step can be skipped.
  93          */
  94         if (pcs_misc_ctl_reg.s.mode) {
  95                 /* 1000BASE-X */
  96                 union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
  97                 pcsx_anx_adv_reg.u64 =
  98                     cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
  99                 pcsx_anx_adv_reg.s.rem_flt = 0;
 100                 pcsx_anx_adv_reg.s.pause = 3;
 101                 pcsx_anx_adv_reg.s.hfd = 1;
 102                 pcsx_anx_adv_reg.s.fd = 1;
 103                 cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
 104                                pcsx_anx_adv_reg.u64);
 105         } else {
 106                 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
 107                 pcsx_miscx_ctl_reg.u64 =
 108                     cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
 109                 if (pcsx_miscx_ctl_reg.s.mac_phy) {
 110                         /* PHY Mode */
 111                         union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
 112                         pcsx_sgmx_an_adv_reg.u64 =
 113                             cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
 114                                           (index, interface));
 115                         pcsx_sgmx_an_adv_reg.s.link = 1;
 116                         pcsx_sgmx_an_adv_reg.s.dup = 1;
 117                         pcsx_sgmx_an_adv_reg.s.speed = 2;
 118                         cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
 119                                        (index, interface),
 120                                        pcsx_sgmx_an_adv_reg.u64);
 121                 } else {
 122                         /* MAC Mode - Nothing to do */
 123                 }
 124         }
 125         return 0;
 126 }
 127 
 128 /**
 129  * Initialize the SERTES link for the first time or after a loss
 130  * of link.
 131  *
 132  * @interface: Interface to init
 133  * @index:     Index of prot on the interface
 134  *
 135  * Returns Zero on success, negative on failure
 136  */
 137 static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
 138 {
 139         union cvmx_pcsx_mrx_control_reg control_reg;
 140 
 141         /*
 142          * Take PCS through a reset sequence.
 143          * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
 144          * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
 145          * value of the other PCS*_MR*_CONTROL_REG bits).  Read
 146          * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
 147          * zero.
 148          */
 149         control_reg.u64 =
 150             cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
 151         if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
 152                 control_reg.s.reset = 1;
 153                 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
 154                                control_reg.u64);
 155                 if (CVMX_WAIT_FOR_FIELD64
 156                     (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
 157                      union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
 158                         cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
 159                                      "to finish reset\n",
 160                              interface, index);
 161                         return -1;
 162                 }
 163         }
 164 
 165         /*
 166          * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
 167          * sgmii negotiation starts.
 168          */
 169         control_reg.s.rst_an = 1;
 170         control_reg.s.an_en = 1;
 171         control_reg.s.pwr_dn = 0;
 172         cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
 173                        control_reg.u64);
 174 
 175         /*
 176          * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
 177          * that sgmii autonegotiation is complete. In MAC mode this
 178          * isn't an ethernet link, but a link between Octeon and the
 179          * PHY.
 180          */
 181         if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
 182             CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
 183                                   union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
 184                                   10000)) {
 185                 /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
 186                 return -1;
 187         }
 188         return 0;
 189 }
 190 
 191 /**
 192  * Configure an SGMII link to the specified speed after the SERTES
 193  * link is up.
 194  *
 195  * @interface: Interface to init
 196  * @index:     Index of prot on the interface
 197  * @link_info: Link state to configure
 198  *
 199  * Returns Zero on success, negative on failure
 200  */
 201 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
 202                                                         int index,
 203                                                         cvmx_helper_link_info_t
 204                                                         link_info)
 205 {
 206         int is_enabled;
 207         union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
 208         union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
 209 
 210         /* Disable GMX before we make any changes. Remember the enable state */
 211         gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
 212         is_enabled = gmxx_prtx_cfg.s.en;
 213         gmxx_prtx_cfg.s.en = 0;
 214         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
 215 
 216         /* Wait for GMX to be idle */
 217         if (CVMX_WAIT_FOR_FIELD64
 218             (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
 219              rx_idle, ==, 1, 10000)
 220             || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
 221                                      union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
 222                                      10000)) {
 223                 cvmx_dprintf
 224                     ("SGMII%d: Timeout waiting for port %d to be idle\n",
 225                      interface, index);
 226                 return -1;
 227         }
 228 
 229         /* Read GMX CFG again to make sure the disable completed */
 230         gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
 231 
 232         /*
 233          * Get the misc control for PCS. We will need to set the
 234          * duplication amount.
 235          */
 236         pcsx_miscx_ctl_reg.u64 =
 237             cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
 238 
 239         /*
 240          * Use GMXENO to force the link down if the status we get says
 241          * it should be down.
 242          */
 243         pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
 244 
 245         /* Only change the duplex setting if the link is up */
 246         if (link_info.s.link_up)
 247                 gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
 248 
 249         /* Do speed based setting for GMX */
 250         switch (link_info.s.speed) {
 251         case 10:
 252                 gmxx_prtx_cfg.s.speed = 0;
 253                 gmxx_prtx_cfg.s.speed_msb = 1;
 254                 gmxx_prtx_cfg.s.slottime = 0;
 255                 /* Setting from GMX-603 */
 256                 pcsx_miscx_ctl_reg.s.samp_pt = 25;
 257                 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
 258                 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
 259                 break;
 260         case 100:
 261                 gmxx_prtx_cfg.s.speed = 0;
 262                 gmxx_prtx_cfg.s.speed_msb = 0;
 263                 gmxx_prtx_cfg.s.slottime = 0;
 264                 pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
 265                 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
 266                 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
 267                 break;
 268         case 1000:
 269                 gmxx_prtx_cfg.s.speed = 1;
 270                 gmxx_prtx_cfg.s.speed_msb = 0;
 271                 gmxx_prtx_cfg.s.slottime = 1;
 272                 pcsx_miscx_ctl_reg.s.samp_pt = 1;
 273                 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
 274                 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
 275                 break;
 276         default:
 277                 break;
 278         }
 279 
 280         /* Write the new misc control for PCS */
 281         cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
 282                        pcsx_miscx_ctl_reg.u64);
 283 
 284         /* Write the new GMX settings with the port still disabled */
 285         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
 286 
 287         /* Read GMX CFG again to make sure the config completed */
 288         gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
 289 
 290         /* Restore the enabled / disabled state */
 291         gmxx_prtx_cfg.s.en = is_enabled;
 292         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
 293 
 294         return 0;
 295 }
 296 
 297 /**
 298  * Bring up the SGMII interface to be ready for packet I/O but
 299  * leave I/O disabled using the GMX override. This function
 300  * follows the bringup documented in 10.6.3 of the manual.
 301  *
 302  * @interface: Interface to bringup
 303  * @num_ports: Number of ports on the interface
 304  *
 305  * Returns Zero on success, negative on failure
 306  */
 307 static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
 308 {
 309         int index;
 310 
 311         __cvmx_helper_setup_gmx(interface, num_ports);
 312 
 313         for (index = 0; index < num_ports; index++) {
 314                 int ipd_port = cvmx_helper_get_ipd_port(interface, index);
 315                 __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
 316                 /* Linux kernel driver will call ....link_set with the
 317                  * proper link state. In the simulator there is no
 318                  * link state polling and hence it is set from
 319                  * here.
 320                  */
 321                 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
 322                         __cvmx_helper_sgmii_link_set(ipd_port,
 323                                        __cvmx_helper_sgmii_link_get(ipd_port));
 324         }
 325 
 326         return 0;
 327 }
 328 
 329 int __cvmx_helper_sgmii_enumerate(int interface)
 330 {
 331         return 4;
 332 }
 333 /**
 334  * Probe a SGMII interface and determine the number of ports
 335  * connected to it. The SGMII interface should still be down after
 336  * this call.
 337  *
 338  * @interface: Interface to probe
 339  *
 340  * Returns Number of ports on the interface. Zero to disable.
 341  */
 342 int __cvmx_helper_sgmii_probe(int interface)
 343 {
 344         union cvmx_gmxx_inf_mode mode;
 345 
 346         /*
 347          * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
 348          * interface needs to be enabled before IPD otherwise per port
 349          * backpressure may not work properly
 350          */
 351         mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
 352         mode.s.en = 1;
 353         cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
 354         return __cvmx_helper_sgmii_enumerate(interface);
 355 }
 356 
 357 /**
 358  * Bringup and enable a SGMII interface. After this call packet
 359  * I/O should be fully functional. This is called with IPD
 360  * enabled but PKO disabled.
 361  *
 362  * @interface: Interface to bring up
 363  *
 364  * Returns Zero on success, negative on failure
 365  */
 366 int __cvmx_helper_sgmii_enable(int interface)
 367 {
 368         int num_ports = cvmx_helper_ports_on_interface(interface);
 369         int index;
 370 
 371         __cvmx_helper_sgmii_hardware_init(interface, num_ports);
 372 
 373         for (index = 0; index < num_ports; index++) {
 374                 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
 375                 gmxx_prtx_cfg.u64 =
 376                     cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
 377                 gmxx_prtx_cfg.s.en = 1;
 378                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
 379                                gmxx_prtx_cfg.u64);
 380                 __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
 381         }
 382         __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
 383         __cvmx_interrupt_gmxx_enable(interface);
 384         return 0;
 385 }
 386 
 387 /**
 388  * Return the link state of an IPD/PKO port as returned by
 389  * auto negotiation. The result of this function may not match
 390  * Octeon's link config if auto negotiation has changed since
 391  * the last call to cvmx_helper_link_set().
 392  *
 393  * @ipd_port: IPD/PKO port to query
 394  *
 395  * Returns Link state
 396  */
 397 cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
 398 {
 399         cvmx_helper_link_info_t result;
 400         union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
 401         int interface = cvmx_helper_get_interface_num(ipd_port);
 402         int index = cvmx_helper_get_interface_index_num(ipd_port);
 403         union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
 404 
 405         result.u64 = 0;
 406 
 407         if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
 408                 /* The simulator gives you a simulated 1Gbps full duplex link */
 409                 result.s.link_up = 1;
 410                 result.s.full_duplex = 1;
 411                 result.s.speed = 1000;
 412                 return result;
 413         }
 414 
 415         pcsx_mrx_control_reg.u64 =
 416             cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
 417         if (pcsx_mrx_control_reg.s.loopbck1) {
 418                 /* Force 1Gbps full duplex link for internal loopback */
 419                 result.s.link_up = 1;
 420                 result.s.full_duplex = 1;
 421                 result.s.speed = 1000;
 422                 return result;
 423         }
 424 
 425         pcs_misc_ctl_reg.u64 =
 426             cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
 427         if (pcs_misc_ctl_reg.s.mode) {
 428                 /* 1000BASE-X */
 429                 /* FIXME */
 430         } else {
 431                 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
 432                 pcsx_miscx_ctl_reg.u64 =
 433                     cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
 434                 if (pcsx_miscx_ctl_reg.s.mac_phy) {
 435                         /* PHY Mode */
 436                         union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
 437                         union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
 438 
 439                         /*
 440                          * Don't bother continuing if the SERTES low
 441                          * level link is down
 442                          */
 443                         pcsx_mrx_status_reg.u64 =
 444                             cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
 445                                           (index, interface));
 446                         if (pcsx_mrx_status_reg.s.lnk_st == 0) {
 447                                 if (__cvmx_helper_sgmii_hardware_init_link
 448                                     (interface, index) != 0)
 449                                         return result;
 450                         }
 451 
 452                         /* Read the autoneg results */
 453                         pcsx_anx_results_reg.u64 =
 454                             cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
 455                                           (index, interface));
 456                         if (pcsx_anx_results_reg.s.an_cpt) {
 457                                 /*
 458                                  * Auto negotiation is complete. Set
 459                                  * status accordingly.
 460                                  */
 461                                 result.s.full_duplex =
 462                                     pcsx_anx_results_reg.s.dup;
 463                                 result.s.link_up =
 464                                     pcsx_anx_results_reg.s.link_ok;
 465                                 switch (pcsx_anx_results_reg.s.spd) {
 466                                 case 0:
 467                                         result.s.speed = 10;
 468                                         break;
 469                                 case 1:
 470                                         result.s.speed = 100;
 471                                         break;
 472                                 case 2:
 473                                         result.s.speed = 1000;
 474                                         break;
 475                                 default:
 476                                         result.s.speed = 0;
 477                                         result.s.link_up = 0;
 478                                         break;
 479                                 }
 480                         } else {
 481                                 /*
 482                                  * Auto negotiation isn't
 483                                  * complete. Return link down.
 484                                  */
 485                                 result.s.speed = 0;
 486                                 result.s.link_up = 0;
 487                         }
 488                 } else {        /* MAC Mode */
 489 
 490                         result = __cvmx_helper_board_link_get(ipd_port);
 491                 }
 492         }
 493         return result;
 494 }
 495 
 496 /**
 497  * Configure an IPD/PKO port for the specified link state. This
 498  * function does not influence auto negotiation at the PHY level.
 499  * The passed link state must always match the link state returned
 500  * by cvmx_helper_link_get().
 501  *
 502  * @ipd_port:  IPD/PKO port to configure
 503  * @link_info: The new link state
 504  *
 505  * Returns Zero on success, negative on failure
 506  */
 507 int __cvmx_helper_sgmii_link_set(int ipd_port,
 508                                  cvmx_helper_link_info_t link_info)
 509 {
 510         int interface = cvmx_helper_get_interface_num(ipd_port);
 511         int index = cvmx_helper_get_interface_index_num(ipd_port);
 512         __cvmx_helper_sgmii_hardware_init_link(interface, index);
 513         return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
 514                                                             link_info);
 515 }

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