Path: blob/master/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
26481 views
/***********************license start***************1* Author: Cavium Networks2*3* Contact: [email protected]4* This file is part of the OCTEON SDK5*6* Copyright (C) 2003-2018 Cavium, Inc.7*8* This file is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License, Version 2, as10* published by the Free Software Foundation.11*12* This file is distributed in the hope that it will be useful, but13* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty14* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or15* NONINFRINGEMENT. See the GNU General Public License for more16* details.17*18* You should have received a copy of the GNU General Public License19* along with this file; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21* or visit http://www.gnu.org/licenses/.22*23* This file may also be available under a different license from Cavium.24* Contact Cavium Networks for more information25***********************license end**************************************/2627/*28* Functions for SGMII initialization, configuration,29* and monitoring.30*/3132#include <asm/octeon/octeon.h>3334#include <asm/octeon/cvmx-config.h>3536#include <asm/octeon/cvmx-helper.h>37#include <asm/octeon/cvmx-helper-board.h>3839#include <asm/octeon/cvmx-gmxx-defs.h>40#include <asm/octeon/cvmx-pcsx-defs.h>41#include <asm/octeon/cvmx-pcsxx-defs.h>4243/**44* Perform initialization required only once for an SGMII port.45*46* @interface: Interface to init47* @index: Index of prot on the interface48*49* Returns Zero on success, negative on failure50*/51static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)52{53const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;54union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;55union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;56union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;5758/* Disable GMX */59gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));60gmxx_prtx_cfg.s.en = 0;61cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);6263/*64* Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the65* appropriate value. 1000BASE-X specifies a 10ms66* interval. SGMII specifies a 1.6ms interval.67*/68pcs_misc_ctl_reg.u64 =69cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));70pcsx_linkx_timer_count_reg.u64 =71cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));72if (pcs_misc_ctl_reg.s.mode) {73/* 1000BASE-X */74pcsx_linkx_timer_count_reg.s.count =75(10000ull * clock_mhz) >> 10;76} else {77/* SGMII */78pcsx_linkx_timer_count_reg.s.count =79(1600ull * clock_mhz) >> 10;80}81cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),82pcsx_linkx_timer_count_reg.u64);8384/*85* Write the advertisement register to be used as the86* tx_Config_Reg<D15:D0> of the autonegotiation. In87* 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.88* In SGMII PHY mode, tx_Config_Reg<D15:D0> is89* PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode,90* tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this91* step can be skipped.92*/93if (pcs_misc_ctl_reg.s.mode) {94/* 1000BASE-X */95union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;96pcsx_anx_adv_reg.u64 =97cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));98pcsx_anx_adv_reg.s.rem_flt = 0;99pcsx_anx_adv_reg.s.pause = 3;100pcsx_anx_adv_reg.s.hfd = 1;101pcsx_anx_adv_reg.s.fd = 1;102cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),103pcsx_anx_adv_reg.u64);104} else {105union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;106pcsx_miscx_ctl_reg.u64 =107cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));108if (pcsx_miscx_ctl_reg.s.mac_phy) {109/* PHY Mode */110union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;111pcsx_sgmx_an_adv_reg.u64 =112cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG113(index, interface));114pcsx_sgmx_an_adv_reg.s.link = 1;115pcsx_sgmx_an_adv_reg.s.dup = 1;116pcsx_sgmx_an_adv_reg.s.speed = 2;117cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG118(index, interface),119pcsx_sgmx_an_adv_reg.u64);120} else {121/* MAC Mode - Nothing to do */122}123}124return 0;125}126127/**128* Initialize the SERTES link for the first time or after a loss129* of link.130*131* @interface: Interface to init132* @index: Index of prot on the interface133*134* Returns Zero on success, negative on failure135*/136static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)137{138union cvmx_pcsx_mrx_control_reg control_reg;139140/*141* Take PCS through a reset sequence.142* PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.143* Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the144* value of the other PCS*_MR*_CONTROL_REG bits). Read145* PCS*_MR*_CONTROL_REG[RESET] until it changes value to146* zero.147*/148control_reg.u64 =149cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));150if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {151control_reg.s.reset = 1;152cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),153control_reg.u64);154if (CVMX_WAIT_FOR_FIELD64155(CVMX_PCSX_MRX_CONTROL_REG(index, interface),156union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {157cvmx_dprintf("SGMII%d: Timeout waiting for port %d "158"to finish reset\n",159interface, index);160return -1;161}162}163164/*165* Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh166* sgmii negotiation starts.167*/168control_reg.s.rst_an = 1;169control_reg.s.an_en = 1;170control_reg.s.pwr_dn = 0;171cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),172control_reg.u64);173174/*175* Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating176* that sgmii autonegotiation is complete. In MAC mode this177* isn't an ethernet link, but a link between Octeon and the178* PHY.179*/180if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&181CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),182union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,18310000)) {184/* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */185return -1;186}187return 0;188}189190/**191* Configure an SGMII link to the specified speed after the SERTES192* link is up.193*194* @interface: Interface to init195* @index: Index of prot on the interface196* @link_info: Link state to configure197*198* Returns Zero on success, negative on failure199*/200static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,201int index,202union cvmx_helper_link_info203link_info)204{205int is_enabled;206union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;207union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;208209/* Disable GMX before we make any changes. Remember the enable state */210gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));211is_enabled = gmxx_prtx_cfg.s.en;212gmxx_prtx_cfg.s.en = 0;213cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);214215/* Wait for GMX to be idle */216if (CVMX_WAIT_FOR_FIELD64217(CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,218rx_idle, ==, 1, 10000)219|| CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),220union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,22110000)) {222cvmx_dprintf223("SGMII%d: Timeout waiting for port %d to be idle\n",224interface, index);225return -1;226}227228/* Read GMX CFG again to make sure the disable completed */229gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));230231/*232* Get the misc control for PCS. We will need to set the233* duplication amount.234*/235pcsx_miscx_ctl_reg.u64 =236cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));237238/*239* Use GMXENO to force the link down if the status we get says240* it should be down.241*/242pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;243244/* Only change the duplex setting if the link is up */245if (link_info.s.link_up)246gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;247248/* Do speed based setting for GMX */249switch (link_info.s.speed) {250case 10:251gmxx_prtx_cfg.s.speed = 0;252gmxx_prtx_cfg.s.speed_msb = 1;253gmxx_prtx_cfg.s.slottime = 0;254/* Setting from GMX-603 */255pcsx_miscx_ctl_reg.s.samp_pt = 25;256cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);257cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);258break;259case 100:260gmxx_prtx_cfg.s.speed = 0;261gmxx_prtx_cfg.s.speed_msb = 0;262gmxx_prtx_cfg.s.slottime = 0;263pcsx_miscx_ctl_reg.s.samp_pt = 0x5;264cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);265cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);266break;267case 1000:268gmxx_prtx_cfg.s.speed = 1;269gmxx_prtx_cfg.s.speed_msb = 0;270gmxx_prtx_cfg.s.slottime = 1;271pcsx_miscx_ctl_reg.s.samp_pt = 1;272cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);273cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);274break;275default:276break;277}278279/* Write the new misc control for PCS */280cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),281pcsx_miscx_ctl_reg.u64);282283/* Write the new GMX settings with the port still disabled */284cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);285286/* Read GMX CFG again to make sure the config completed */287gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));288289/* Restore the enabled / disabled state */290gmxx_prtx_cfg.s.en = is_enabled;291cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);292293return 0;294}295296/**297* Bring up the SGMII interface to be ready for packet I/O but298* leave I/O disabled using the GMX override. This function299* follows the bringup documented in 10.6.3 of the manual.300*301* @interface: Interface to bringup302* @num_ports: Number of ports on the interface303*304* Returns Zero on success, negative on failure305*/306static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)307{308int index;309310__cvmx_helper_setup_gmx(interface, num_ports);311312for (index = 0; index < num_ports; index++) {313int ipd_port = cvmx_helper_get_ipd_port(interface, index);314__cvmx_helper_sgmii_hardware_init_one_time(interface, index);315/* Linux kernel driver will call ....link_set with the316* proper link state. In the simulator there is no317* link state polling and hence it is set from318* here.319*/320if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)321__cvmx_helper_sgmii_link_set(ipd_port,322__cvmx_helper_sgmii_link_get(ipd_port));323}324325return 0;326}327328int __cvmx_helper_sgmii_enumerate(int interface)329{330return 4;331}332/**333* Probe a SGMII interface and determine the number of ports334* connected to it. The SGMII interface should still be down after335* this call.336*337* @interface: Interface to probe338*339* Returns Number of ports on the interface. Zero to disable.340*/341int __cvmx_helper_sgmii_probe(int interface)342{343union cvmx_gmxx_inf_mode mode;344345/*346* Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the347* interface needs to be enabled before IPD otherwise per port348* backpressure may not work properly349*/350mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));351mode.s.en = 1;352cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);353return __cvmx_helper_sgmii_enumerate(interface);354}355356/**357* Bringup and enable a SGMII interface. After this call packet358* I/O should be fully functional. This is called with IPD359* enabled but PKO disabled.360*361* @interface: Interface to bring up362*363* Returns Zero on success, negative on failure364*/365int __cvmx_helper_sgmii_enable(int interface)366{367int num_ports = cvmx_helper_ports_on_interface(interface);368int index;369370__cvmx_helper_sgmii_hardware_init(interface, num_ports);371372for (index = 0; index < num_ports; index++) {373union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;374gmxx_prtx_cfg.u64 =375cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));376gmxx_prtx_cfg.s.en = 1;377cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),378gmxx_prtx_cfg.u64);379__cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);380}381__cvmx_interrupt_pcsxx_int_en_reg_enable(interface);382__cvmx_interrupt_gmxx_enable(interface);383return 0;384}385386/**387* Return the link state of an IPD/PKO port as returned by388* auto negotiation. The result of this function may not match389* Octeon's link config if auto negotiation has changed since390* the last call to cvmx_helper_link_set().391*392* @ipd_port: IPD/PKO port to query393*394* Returns Link state395*/396union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port)397{398union cvmx_helper_link_info result;399union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;400int interface = cvmx_helper_get_interface_num(ipd_port);401int index = cvmx_helper_get_interface_index_num(ipd_port);402union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;403404result.u64 = 0;405406if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {407/* The simulator gives you a simulated 1Gbps full duplex link */408result.s.link_up = 1;409result.s.full_duplex = 1;410result.s.speed = 1000;411return result;412}413414pcsx_mrx_control_reg.u64 =415cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));416if (pcsx_mrx_control_reg.s.loopbck1) {417/* Force 1Gbps full duplex link for internal loopback */418result.s.link_up = 1;419result.s.full_duplex = 1;420result.s.speed = 1000;421return result;422}423424pcs_misc_ctl_reg.u64 =425cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));426if (pcs_misc_ctl_reg.s.mode) {427/* 1000BASE-X */428/* FIXME */429} else {430union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;431pcsx_miscx_ctl_reg.u64 =432cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));433if (pcsx_miscx_ctl_reg.s.mac_phy) {434/* PHY Mode */435union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;436union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;437438/*439* Don't bother continuing if the SERTES low440* level link is down441*/442pcsx_mrx_status_reg.u64 =443cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG444(index, interface));445if (pcsx_mrx_status_reg.s.lnk_st == 0) {446if (__cvmx_helper_sgmii_hardware_init_link447(interface, index) != 0)448return result;449}450451/* Read the autoneg results */452pcsx_anx_results_reg.u64 =453cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG454(index, interface));455if (pcsx_anx_results_reg.s.an_cpt) {456/*457* Auto negotiation is complete. Set458* status accordingly.459*/460result.s.full_duplex =461pcsx_anx_results_reg.s.dup;462result.s.link_up =463pcsx_anx_results_reg.s.link_ok;464switch (pcsx_anx_results_reg.s.spd) {465case 0:466result.s.speed = 10;467break;468case 1:469result.s.speed = 100;470break;471case 2:472result.s.speed = 1000;473break;474default:475result.s.speed = 0;476result.s.link_up = 0;477break;478}479} else {480/*481* Auto negotiation isn't482* complete. Return link down.483*/484result.s.speed = 0;485result.s.link_up = 0;486}487} else { /* MAC Mode */488489result = __cvmx_helper_board_link_get(ipd_port);490}491}492return result;493}494495/**496* Configure an IPD/PKO port for the specified link state. This497* function does not influence auto negotiation at the PHY level.498* The passed link state must always match the link state returned499* by cvmx_helper_link_get().500*501* @ipd_port: IPD/PKO port to configure502* @link_info: The new link state503*504* Returns Zero on success, negative on failure505*/506int __cvmx_helper_sgmii_link_set(int ipd_port,507union cvmx_helper_link_info link_info)508{509int interface = cvmx_helper_get_interface_num(ipd_port);510int index = cvmx_helper_get_interface_index_num(ipd_port);511__cvmx_helper_sgmii_hardware_init_link(interface, index);512return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,513link_info);514}515516517