From: Andrew LaMarche Date: Mon, 31 Mar 2025 13:00:00 +0000 Subject: [PATCH] octeon: force pcs reset QCA833x devices misbehave with SGMII until a PCS reset is triggered. U-boot has a newer vendor GPL dump that contains logic to reset the PCS. This patch backports that functionality so that Octeon devices with QCA833{4/7} switchs pass traffic between the switch and CPU. References: - https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L197-L225 - https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L701-L737 Signed-off-by: Andrew LaMarche --- a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c @@ -125,6 +125,17 @@ static int __cvmx_helper_sgmii_hardware_ return 0; } +static int __cvmx_helper_need_g15618(void) +{ + if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM || + OCTEON_IS_MODEL(OCTEON_CN63XX) || + OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 1; + else + return 0; +} + /** * Initialize the SERTES link for the first time or after a loss * of link. @@ -172,6 +183,39 @@ static int __cvmx_helper_sgmii_hardware_ cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), control_reg.u64); + /* Force a PCS reset by powering down the PCS interface + * This is needed to deal with broken Qualcomm/Atheros PHYs and switches + * which never recover if PCS is not power cycled. The alternative + * is to power cycle or hardware reset the Qualcomm devices whenever + * SGMII is initialized. + * + * This is needed for the QCA8033 PHYs as well as the QCA833X switches + * to work. The QCA8337 switch has additional SGMII problems and is + * best avoided if at all possible. Failure to power cycle PCS prevents + * any traffic from flowing between Octeon and Qualcomm devices if there + * is a warm reset. Even a software reset to the Qualcomm device will + * not work. + * + * Note that this problem has been reported between Qualcomm and other + * vendor's processors as well so this problem is not unique to + * Qualcomm and Octeon. + * + * Power cycling PCS doesn't hurt anything with non-Qualcomm devices + * other than adding a 25ms delay during initialization. + */ + control_reg.s.pwr_dn = 1; + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + + if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) + /* 25ms should be enough, 10ms is too short */ + mdelay(25); + + control_reg.s.pwr_dn = 0; + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + /* * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating * that sgmii autonegotiation is complete. In MAC mode this @@ -507,9 +551,47 @@ union cvmx_helper_link_info __cvmx_helpe int __cvmx_helper_sgmii_link_set(int ipd_port, union cvmx_helper_link_info link_info) { + union cvmx_pcsx_mrx_control_reg control_reg; int interface = cvmx_helper_get_interface_num(ipd_port); int index = cvmx_helper_get_interface_index_num(ipd_port); - __cvmx_helper_sgmii_hardware_init_link(interface, index); + + /* For some devices, i.e. the Qualcomm QCA8337 switch we need to power + * down the PCS interface when the link goes down and power it back + * up when the link returns. + */ + if (link_info.s.link_up || !__cvmx_helper_need_g15618()) { + __cvmx_helper_sgmii_hardware_init_link(interface, index); + } else { + union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; + + pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + + /* Disable autonegotiation when MAC mode is enabled or + * autonegotiation is disabled. + */ + control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + if (pcsx_miscx_ctl_reg.s.mac_phy == 0 || + !cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface))) { + + control_reg.s.an_en = 0; + control_reg.s.spdmsb = 1; + control_reg.s.spdlsb = 0; + control_reg.s.dup = 1; + + } + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); + /* + * Use GMXENO to force the link down it will get + * reenabled later... + */ + pcsx_miscx_ctl_reg.s.gmxeno = 1; + cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), + pcsx_miscx_ctl_reg.u64); + cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); + return 0; + } return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, link_info); }