18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Marvell 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Antoine Tenart <antoine.tenart@free-electrons.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/phy.h> 158c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Relative to priv->base */ 208c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0(n) (0x0 + (n) * 0x1000) 218c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_PU_PLL BIT(1) 228c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_GEN_RX(n) ((n) << 3) 238c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_GEN_TX(n) ((n) << 7) 248c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_PU_RX BIT(11) 258c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_PU_TX BIT(12) 268c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_HALF_BUS BIT(14) 278c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE BIT(15) 288c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG1(n) (0x4 + (n) * 0x1000) 298c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG1_RESET BIT(3) 308c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG1_RX_INIT BIT(4) 318c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG1_CORE_RESET BIT(5) 328c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG1_RF_RESET BIT(6) 338c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG2(n) (0x8 + (n) * 0x1000) 348c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_CFG2_DFE_EN BIT(4) 358c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_STATUS0(n) (0x18 + (n) * 0x1000) 368c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY BIT(2) 378c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY BIT(3) 388c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SERDES_STATUS0_RX_INIT BIT(4) 398c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PWRPLL_CTRL(n) (0x804 + (n) * 0x1000) 408c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(n) ((n) << 0) 418c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PWRPLL_PHY_MODE(n) ((n) << 5) 428c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_IMP_CAL(n) (0x80c + (n) * 0x1000) 438c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_IMP_CAL_TX_EXT(n) ((n) << 10) 448c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_IMP_CAL_TX_EXT_EN BIT(15) 458c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DFE_RES(n) (0x81c + (n) * 0x1000) 468c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL BIT(15) 478c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_COEF(n) (0x828 + (n) * 0x1000) 488c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_COEF_DFE_EN BIT(14) 498c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_COEF_DFE_CTRL BIT(15) 508c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S0(n) (0x834 + (n) * 0x1000) 518c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S0_TX_AMP(n) ((n) << 1) 528c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S0_TX_EMPH(n) ((n) << 7) 538c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1(n) (0x838 + (n) * 0x1000) 548c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(n) ((n) << 0) 558c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(n) ((n) << 3) 568c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(n) ((n) << 6) 578c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(n) ((n) << 8) 588c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_DFE_EN BIT(10) 598c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S1_RX_DIV(n) ((n) << 11) 608c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S2(n) (0x8f4 + (n) * 0x1000) 618c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S2_TX_EMPH(n) ((n) << 0) 628c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN BIT(4) 638c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_LOOPBACK(n) (0x88c + (n) * 0x1000) 648c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(n) ((n) << 1) 658c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_VDD_CAL0(n) (0x908 + (n) * 0x1000) 668c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_VDD_CAL0_CONT_MODE BIT(15) 678c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_EXT_SELV(n) (0x914 + (n) * 0x1000) 688c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_EXT_SELV_RX_SAMPL(n) ((n) << 5) 698c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_MISC_CTRL0(n) (0x93c + (n) * 0x1000) 708c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE BIT(5) 718c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL BIT(10) 728c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_RX_CTRL1(n) (0x940 + (n) * 0x1000) 738c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL BIT(11) 748c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_RX_CTRL1_CLK8T_EN BIT(12) 758c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SPEED_DIV(n) (0x954 + (n) * 0x1000) 768c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SPEED_DIV_TX_FORCE BIT(7) 778c2ecf20Sopenharmony_ci#define MVEBU_SP_CALIB(n) (0x96c + (n) * 0x1000) 788c2ecf20Sopenharmony_ci#define MVEBU_SP_CALIB_SAMPLER(n) ((n) << 8) 798c2ecf20Sopenharmony_ci#define MVEBU_SP_CALIB_SAMPLER_EN BIT(12) 808c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_SLEW_RATE(n) (0x974 + (n) * 0x1000) 818c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n) ((n) << 5) 828c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_SLEW_RATE_SLC(n) ((n) << 10) 838c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DTL_CTRL(n) (0x984 + (n) * 0x1000) 848c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN BIT(2) 858c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_FRAME_DETECT0(n) (0xa14 + (n) * 0x1000) 868c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_FRAME_DETECT0_PATN(n) ((n) << 7) 878c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_FRAME_DETECT3(n) (0xa20 + (n) * 0x1000) 888c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN BIT(12) 898c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DME(n) (0xa28 + (n) * 0x1000) 908c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_DME_ETH_MODE BIT(7) 918c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TRAINING0(n) (0xa68 + (n) * 0x1000) 928c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TRAINING0_P2P_HOLD BIT(15) 938c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TRAINING5(n) (0xaa4 + (n) * 0x1000) 948c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TRAINING5_RX_TIMER(n) ((n) << 0) 958c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_TRAIN_PRESET(n) (0xb1c + (n) * 0x1000) 968c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN BIT(8) 978c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11 BIT(9) 988c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S3(n) (0xc40 + (n) * 0x1000) 998c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S3_FBCK_SEL BIT(9) 1008c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S4(n) (0xc44 + (n) * 0x1000) 1018c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S4_DFE_RES(n) ((n) << 8) 1028c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_PRESET(n) (0xc68 + (n) * 0x1000) 1038c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_TX_PRESET_INDEX(n) ((n) << 0) 1048c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S5(n) (0xd38 + (n) * 0x1000) 1058c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_GEN1_S5_ICP(n) ((n) << 0) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Relative to priv->regmap */ 1088c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_CONF1(n) (0x1000 + (n) * 0x28) 1098c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_CONF1_PWRUP BIT(1) 1108c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_CONF1_USB_PCIE BIT(2) /* 0: Ethernet/SATA */ 1118c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_CONF6(n) (0x1014 + (n) * 0x28) 1128c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_CONF6_40B BIT(18) 1138c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SELECTOR 0x1140 1148c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SELECTOR_PHY(n) ((n) * 0x4) 1158c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PIPE_SELECTOR 0x1144 1168c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PIPE_SELECTOR_PIPE(n) ((n) * 0x4) 1178c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SD1_CTRL1 0x1148 1188c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN BIT(26) 1198c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN BIT(27) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_LANES 6 1228c2ecf20Sopenharmony_ci#define MVEBU_COMPHY_PORTS 3 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define COMPHY_SIP_POWER_ON 0x82000001 1258c2ecf20Sopenharmony_ci#define COMPHY_SIP_POWER_OFF 0x82000002 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * A lane is described by the following bitfields: 1298c2ecf20Sopenharmony_ci * [ 1- 0]: COMPHY polarity invertion 1308c2ecf20Sopenharmony_ci * [ 2- 7]: COMPHY speed 1318c2ecf20Sopenharmony_ci * [ 5-11]: COMPHY port index 1328c2ecf20Sopenharmony_ci * [12-16]: COMPHY mode 1338c2ecf20Sopenharmony_ci * [17]: Clock source 1348c2ecf20Sopenharmony_ci * [18-20]: PCIe width (x1, x2, x4) 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci#define COMPHY_FW_POL_OFFSET 0 1378c2ecf20Sopenharmony_ci#define COMPHY_FW_POL_MASK GENMASK(1, 0) 1388c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_OFFSET 2 1398c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_MASK GENMASK(7, 2) 1408c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_MAX COMPHY_FW_SPEED_MASK 1418c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_1250 0 1428c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_3125 2 1438c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_5000 3 1448c2ecf20Sopenharmony_ci#define COMPHY_FW_SPEED_103125 6 1458c2ecf20Sopenharmony_ci#define COMPHY_FW_PORT_OFFSET 8 1468c2ecf20Sopenharmony_ci#define COMPHY_FW_PORT_MASK GENMASK(11, 8) 1478c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_OFFSET 12 1488c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_MASK GENMASK(16, 12) 1498c2ecf20Sopenharmony_ci#define COMPHY_FW_WIDTH_OFFSET 18 1508c2ecf20Sopenharmony_ci#define COMPHY_FW_WIDTH_MASK GENMASK(20, 18) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci#define COMPHY_FW_PARAM_FULL(mode, port, speed, pol, width) \ 1538c2ecf20Sopenharmony_ci ((((pol) << COMPHY_FW_POL_OFFSET) & COMPHY_FW_POL_MASK) | \ 1548c2ecf20Sopenharmony_ci (((mode) << COMPHY_FW_MODE_OFFSET) & COMPHY_FW_MODE_MASK) | \ 1558c2ecf20Sopenharmony_ci (((port) << COMPHY_FW_PORT_OFFSET) & COMPHY_FW_PORT_MASK) | \ 1568c2ecf20Sopenharmony_ci (((speed) << COMPHY_FW_SPEED_OFFSET) & COMPHY_FW_SPEED_MASK) | \ 1578c2ecf20Sopenharmony_ci (((width) << COMPHY_FW_WIDTH_OFFSET) & COMPHY_FW_WIDTH_MASK)) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define COMPHY_FW_PARAM(mode, port) \ 1608c2ecf20Sopenharmony_ci COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_MAX, 0, 0) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define COMPHY_FW_PARAM_ETH(mode, port, speed) \ 1638c2ecf20Sopenharmony_ci COMPHY_FW_PARAM_FULL(mode, port, speed, 0, 0) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define COMPHY_FW_PARAM_PCIE(mode, port, width) \ 1668c2ecf20Sopenharmony_ci COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_5000, 0, width) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_SATA 0x1 1698c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_SGMII 0x2 /* SGMII 1G */ 1708c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_HS_SGMII 0x3 /* SGMII 2.5G */ 1718c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_USB3H 0x4 1728c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_USB3D 0x5 1738c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_PCIE 0x6 1748c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_RXAUI 0x7 1758c2ecf20Sopenharmony_ci#define COMPHY_FW_MODE_XFI 0x8 /* SFI: 0x9 (is treated like XFI) */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct mvebu_comphy_conf { 1788c2ecf20Sopenharmony_ci enum phy_mode mode; 1798c2ecf20Sopenharmony_ci int submode; 1808c2ecf20Sopenharmony_ci unsigned lane; 1818c2ecf20Sopenharmony_ci unsigned port; 1828c2ecf20Sopenharmony_ci u32 mux; 1838c2ecf20Sopenharmony_ci u32 fw_mode; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define ETH_CONF(_lane, _port, _submode, _mux, _fw) \ 1878c2ecf20Sopenharmony_ci { \ 1888c2ecf20Sopenharmony_ci .lane = _lane, \ 1898c2ecf20Sopenharmony_ci .port = _port, \ 1908c2ecf20Sopenharmony_ci .mode = PHY_MODE_ETHERNET, \ 1918c2ecf20Sopenharmony_ci .submode = _submode, \ 1928c2ecf20Sopenharmony_ci .mux = _mux, \ 1938c2ecf20Sopenharmony_ci .fw_mode = _fw, \ 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#define GEN_CONF(_lane, _port, _mode, _fw) \ 1978c2ecf20Sopenharmony_ci { \ 1988c2ecf20Sopenharmony_ci .lane = _lane, \ 1998c2ecf20Sopenharmony_ci .port = _port, \ 2008c2ecf20Sopenharmony_ci .mode = _mode, \ 2018c2ecf20Sopenharmony_ci .submode = PHY_INTERFACE_MODE_NA, \ 2028c2ecf20Sopenharmony_ci .mux = -1, \ 2038c2ecf20Sopenharmony_ci .fw_mode = _fw, \ 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic const struct mvebu_comphy_conf mvebu_comphy_cp110_modes[] = { 2078c2ecf20Sopenharmony_ci /* lane 0 */ 2088c2ecf20Sopenharmony_ci GEN_CONF(0, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2098c2ecf20Sopenharmony_ci ETH_CONF(0, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), 2108c2ecf20Sopenharmony_ci ETH_CONF(0, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_HS_SGMII), 2118c2ecf20Sopenharmony_ci GEN_CONF(0, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), 2128c2ecf20Sopenharmony_ci /* lane 1 */ 2138c2ecf20Sopenharmony_ci GEN_CONF(1, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H), 2148c2ecf20Sopenharmony_ci GEN_CONF(1, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D), 2158c2ecf20Sopenharmony_ci GEN_CONF(1, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), 2168c2ecf20Sopenharmony_ci GEN_CONF(1, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2178c2ecf20Sopenharmony_ci ETH_CONF(1, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), 2188c2ecf20Sopenharmony_ci ETH_CONF(1, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_HS_SGMII), 2198c2ecf20Sopenharmony_ci /* lane 2 */ 2208c2ecf20Sopenharmony_ci ETH_CONF(2, 0, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), 2218c2ecf20Sopenharmony_ci ETH_CONF(2, 0, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_HS_SGMII), 2228c2ecf20Sopenharmony_ci ETH_CONF(2, 0, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI), 2238c2ecf20Sopenharmony_ci ETH_CONF(2, 0, PHY_INTERFACE_MODE_10GBASER, 0x1, COMPHY_FW_MODE_XFI), 2248c2ecf20Sopenharmony_ci GEN_CONF(2, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H), 2258c2ecf20Sopenharmony_ci GEN_CONF(2, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), 2268c2ecf20Sopenharmony_ci GEN_CONF(2, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2278c2ecf20Sopenharmony_ci /* lane 3 */ 2288c2ecf20Sopenharmony_ci GEN_CONF(3, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2298c2ecf20Sopenharmony_ci ETH_CONF(3, 1, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII), 2308c2ecf20Sopenharmony_ci ETH_CONF(3, 1, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_HS_SGMII), 2318c2ecf20Sopenharmony_ci ETH_CONF(3, 1, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI), 2328c2ecf20Sopenharmony_ci GEN_CONF(3, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H), 2338c2ecf20Sopenharmony_ci GEN_CONF(3, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), 2348c2ecf20Sopenharmony_ci /* lane 4 */ 2358c2ecf20Sopenharmony_ci ETH_CONF(4, 0, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII), 2368c2ecf20Sopenharmony_ci ETH_CONF(4, 0, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_HS_SGMII), 2378c2ecf20Sopenharmony_ci ETH_CONF(4, 0, PHY_INTERFACE_MODE_10GBASER, 0x2, COMPHY_FW_MODE_XFI), 2388c2ecf20Sopenharmony_ci ETH_CONF(4, 0, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI), 2398c2ecf20Sopenharmony_ci GEN_CONF(4, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D), 2408c2ecf20Sopenharmony_ci GEN_CONF(4, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H), 2418c2ecf20Sopenharmony_ci GEN_CONF(4, 1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2428c2ecf20Sopenharmony_ci ETH_CONF(4, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), 2438c2ecf20Sopenharmony_ci ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, -1, COMPHY_FW_MODE_HS_SGMII), 2448c2ecf20Sopenharmony_ci ETH_CONF(4, 1, PHY_INTERFACE_MODE_10GBASER, -1, COMPHY_FW_MODE_XFI), 2458c2ecf20Sopenharmony_ci /* lane 5 */ 2468c2ecf20Sopenharmony_ci ETH_CONF(5, 1, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI), 2478c2ecf20Sopenharmony_ci GEN_CONF(5, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), 2488c2ecf20Sopenharmony_ci ETH_CONF(5, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), 2498c2ecf20Sopenharmony_ci ETH_CONF(5, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_HS_SGMII), 2508c2ecf20Sopenharmony_ci GEN_CONF(5, 2, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistruct mvebu_comphy_priv { 2548c2ecf20Sopenharmony_ci void __iomem *base; 2558c2ecf20Sopenharmony_ci struct regmap *regmap; 2568c2ecf20Sopenharmony_ci struct device *dev; 2578c2ecf20Sopenharmony_ci struct clk *mg_domain_clk; 2588c2ecf20Sopenharmony_ci struct clk *mg_core_clk; 2598c2ecf20Sopenharmony_ci struct clk *axi_clk; 2608c2ecf20Sopenharmony_ci unsigned long cp_phys; 2618c2ecf20Sopenharmony_ci}; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistruct mvebu_comphy_lane { 2648c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv; 2658c2ecf20Sopenharmony_ci unsigned id; 2668c2ecf20Sopenharmony_ci enum phy_mode mode; 2678c2ecf20Sopenharmony_ci int submode; 2688c2ecf20Sopenharmony_ci int port; 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int mvebu_comphy_smc(unsigned long function, unsigned long phys, 2728c2ecf20Sopenharmony_ci unsigned long lane, unsigned long mode) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct arm_smccc_res res; 2758c2ecf20Sopenharmony_ci s32 ret; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res); 2788c2ecf20Sopenharmony_ci ret = res.a0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci switch (ret) { 2818c2ecf20Sopenharmony_ci case SMCCC_RET_SUCCESS: 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci case SMCCC_RET_NOT_SUPPORTED: 2848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2858c2ecf20Sopenharmony_ci default: 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int mvebu_comphy_get_mode(bool fw_mode, int lane, int port, 2918c2ecf20Sopenharmony_ci enum phy_mode mode, int submode) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int i, n = ARRAY_SIZE(mvebu_comphy_cp110_modes); 2948c2ecf20Sopenharmony_ci /* Ignore PCIe submode: it represents the width */ 2958c2ecf20Sopenharmony_ci bool ignore_submode = (mode == PHY_MODE_PCIE); 2968c2ecf20Sopenharmony_ci const struct mvebu_comphy_conf *conf; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Unused PHY mux value is 0x0 */ 2998c2ecf20Sopenharmony_ci if (mode == PHY_MODE_INVALID) 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 3038c2ecf20Sopenharmony_ci conf = &mvebu_comphy_cp110_modes[i]; 3048c2ecf20Sopenharmony_ci if (conf->lane == lane && 3058c2ecf20Sopenharmony_ci conf->port == port && 3068c2ecf20Sopenharmony_ci conf->mode == mode && 3078c2ecf20Sopenharmony_ci (conf->submode == submode || ignore_submode)) 3088c2ecf20Sopenharmony_ci break; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (i == n) 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (fw_mode) 3158c2ecf20Sopenharmony_ci return conf->fw_mode; 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci return conf->mux; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic inline int mvebu_comphy_get_mux(int lane, int port, 3218c2ecf20Sopenharmony_ci enum phy_mode mode, int submode) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci return mvebu_comphy_get_mode(false, lane, port, mode, submode); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic inline int mvebu_comphy_get_fw_mode(int lane, int port, 3278c2ecf20Sopenharmony_ci enum phy_mode mode, int submode) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci return mvebu_comphy_get_mode(true, lane, port, mode, submode); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 3358c2ecf20Sopenharmony_ci u32 val; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val); 3388c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_CONF1_USB_PCIE; 3398c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_CONF1_PWRUP; 3408c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Select baud rates and PLLs */ 3438c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id)); 3448c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL | 3458c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_PU_RX | 3468c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_PU_TX | 3478c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_HALF_BUS | 3488c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) | 3498c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf) | 3508c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci switch (lane->submode) { 3538c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 3548c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) | 3558c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe); 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 3588c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xb) | 3598c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xb) | 3608c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 3638c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x8) | 3648c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x8) | 3658c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_HALF_BUS; 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 3688c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) | 3698c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) | 3708c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_HALF_BUS; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci default: 3738c2ecf20Sopenharmony_ci dev_err(priv->dev, 3748c2ecf20Sopenharmony_ci "unsupported comphy submode (%d) on lane %d\n", 3758c2ecf20Sopenharmony_ci lane->submode, 3768c2ecf20Sopenharmony_ci lane->id); 3778c2ecf20Sopenharmony_ci return -ENOTSUPP; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id)); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (lane->submode == PHY_INTERFACE_MODE_RXAUI) { 3838c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, &val); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch (lane->id) { 3868c2ecf20Sopenharmony_ci case 2: 3878c2ecf20Sopenharmony_ci case 3: 3888c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN; 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case 4: 3918c2ecf20Sopenharmony_ci case 5: 3928c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci default: 3958c2ecf20Sopenharmony_ci dev_err(priv->dev, 3968c2ecf20Sopenharmony_ci "RXAUI is not supported on comphy lane %d\n", 3978c2ecf20Sopenharmony_ci lane->id); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, val); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* reset */ 4058c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4068c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET | 4078c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG1_CORE_RESET | 4088c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG1_RF_RESET); 4098c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* de-assert reset */ 4128c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4138c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG1_RESET | 4148c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG1_CORE_RESET; 4158c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* wait until clocks are ready */ 4188c2ecf20Sopenharmony_ci mdelay(1); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* exlicitly disable 40B, the bits isn't clear on reset */ 4218c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val); 4228c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_CONF6_40B; 4238c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* refclk selection */ 4268c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id)); 4278c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL; 4288c2ecf20Sopenharmony_ci if (lane->submode == PHY_INTERFACE_MODE_10GBASER) 4298c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE; 4308c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id)); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* power and pll selection */ 4338c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id)); 4348c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) | 4358c2ecf20Sopenharmony_ci MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7)); 4368c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) | 4378c2ecf20Sopenharmony_ci MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4); 4388c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id)); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id)); 4418c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7); 4428c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1); 4438c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id)); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int mvebu_comphy_init_plls(struct mvebu_comphy_lane *lane) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 4518c2ecf20Sopenharmony_ci u32 val; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* SERDES external config */ 4548c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id)); 4558c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG0_PU_PLL | 4568c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_PU_RX | 4578c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG0_PU_TX; 4588c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id)); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* check rx/tx pll */ 4618c2ecf20Sopenharmony_ci readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id), 4628c2ecf20Sopenharmony_ci val, 4638c2ecf20Sopenharmony_ci val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY | 4648c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY), 4658c2ecf20Sopenharmony_ci 1000, 150000); 4668c2ecf20Sopenharmony_ci if (!(val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY | 4678c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY))) 4688c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* rx init */ 4718c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4728c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG1_RX_INIT; 4738c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* check rx */ 4768c2ecf20Sopenharmony_ci readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id), 4778c2ecf20Sopenharmony_ci val, val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT, 4788c2ecf20Sopenharmony_ci 1000, 10000); 4798c2ecf20Sopenharmony_ci if (!(val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT)) 4808c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4838c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_SERDES_CFG1_RX_INIT; 4848c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int mvebu_comphy_set_mode_sgmii(struct phy *phy) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 4928c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 4938c2ecf20Sopenharmony_ci u32 val; 4948c2ecf20Sopenharmony_ci int err; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci err = mvebu_comphy_ethernet_init_reset(lane); 4978c2ecf20Sopenharmony_ci if (err) 4988c2ecf20Sopenharmony_ci return err; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5018c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_RX_CTRL1_CLK8T_EN; 5028c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL; 5038c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5068c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN; 5078c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val); 5108c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_CONF1_USB_PCIE; 5118c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_CONF1_PWRUP; 5128c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 5158c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf); 5168c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0x1); 5178c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return mvebu_comphy_init_plls(lane); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic int mvebu_comphy_set_mode_rxaui(struct phy *phy) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 5258c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 5268c2ecf20Sopenharmony_ci u32 val; 5278c2ecf20Sopenharmony_ci int err; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci err = mvebu_comphy_ethernet_init_reset(lane); 5308c2ecf20Sopenharmony_ci if (err) 5318c2ecf20Sopenharmony_ci return err; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5348c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL | 5358c2ecf20Sopenharmony_ci MVEBU_COMPHY_RX_CTRL1_CLK8T_EN; 5368c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5398c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN; 5408c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id)); 5438c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN; 5448c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id)); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id)); 5478c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL; 5488c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id)); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 5518c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf); 5528c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xd); 5538c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id)); 5568c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) | 5578c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7)); 5588c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x1) | 5598c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x1) | 5608c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_DFE_EN; 5618c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id)); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id)); 5648c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL); 5658c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id)); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id)); 5688c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3); 5698c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1); 5708c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id)); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return mvebu_comphy_init_plls(lane); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int mvebu_comphy_set_mode_10gbaser(struct phy *phy) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 5788c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 5798c2ecf20Sopenharmony_ci u32 val; 5808c2ecf20Sopenharmony_ci int err; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci err = mvebu_comphy_ethernet_init_reset(lane); 5838c2ecf20Sopenharmony_ci if (err) 5848c2ecf20Sopenharmony_ci return err; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5878c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL | 5888c2ecf20Sopenharmony_ci MVEBU_COMPHY_RX_CTRL1_CLK8T_EN; 5898c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id)); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5928c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN; 5938c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id)); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Speed divider */ 5968c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id)); 5978c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SPEED_DIV_TX_FORCE; 5988c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id)); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id)); 6018c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN; 6028c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id)); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* DFE resolution */ 6058c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id)); 6068c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL; 6078c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id)); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 6108c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1f) | 6118c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf)); 6128c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1c) | 6138c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xe); 6148c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S2(lane->id)); 6178c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S2_TX_EMPH(0xf); 6188c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN; 6198c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S2(lane->id)); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id)); 6228c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_TX_SLEW_RATE_EMPH(0x3) | 6238c2ecf20Sopenharmony_ci MVEBU_COMPHY_TX_SLEW_RATE_SLC(0x3f); 6248c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id)); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* Impedance calibration */ 6278c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_IMP_CAL(lane->id)); 6288c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_IMP_CAL_TX_EXT(0x1f); 6298c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_IMP_CAL_TX_EXT(0xe) | 6308c2ecf20Sopenharmony_ci MVEBU_COMPHY_IMP_CAL_TX_EXT_EN; 6318c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_IMP_CAL(lane->id)); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S5(lane->id)); 6348c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S5_ICP(0xf); 6358c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S5(lane->id)); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id)); 6388c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) | 6398c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7) | 6408c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(0x3) | 6418c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x3)); 6428c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S1_RX_DFE_EN | 6438c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x2) | 6448c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x2) | 6458c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x1) | 6468c2ecf20Sopenharmony_ci MVEBU_COMPHY_GEN1_S1_RX_DIV(0x3); 6478c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id)); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id)); 6508c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL); 6518c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id)); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id)); 6548c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3); 6558c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1); 6568c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id)); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_GEN1_S3(lane->id)); 6598c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_GEN1_S3_FBCK_SEL; 6608c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_GEN1_S3(lane->id)); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* rx training timer */ 6638c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_TRAINING5(lane->id)); 6648c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_TRAINING5_RX_TIMER(0x3ff); 6658c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_TRAINING5_RX_TIMER(0x13); 6668c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_TRAINING5(lane->id)); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* tx train peak to peak hold */ 6698c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_TRAINING0(lane->id)); 6708c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_TRAINING0_P2P_HOLD; 6718c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_TRAINING0(lane->id)); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_TX_PRESET(lane->id)); 6748c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_TX_PRESET_INDEX(0xf); 6758c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_TX_PRESET_INDEX(0x2); /* preset coeff */ 6768c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_TX_PRESET(lane->id)); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id)); 6798c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN; 6808c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id)); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id)); 6838c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN | 6848c2ecf20Sopenharmony_ci MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11; 6858c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id)); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id)); 6888c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_FRAME_DETECT0_PATN(0x1ff); 6898c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_FRAME_DETECT0_PATN(0x88); 6908c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id)); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_DME(lane->id)); 6938c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_DME_ETH_MODE; 6948c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_DME(lane->id)); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id)); 6978c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_VDD_CAL0_CONT_MODE; 6988c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id)); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_SP_CALIB(lane->id)); 7018c2ecf20Sopenharmony_ci val &= ~MVEBU_SP_CALIB_SAMPLER(0x3); 7028c2ecf20Sopenharmony_ci val |= MVEBU_SP_CALIB_SAMPLER(0x3) | 7038c2ecf20Sopenharmony_ci MVEBU_SP_CALIB_SAMPLER_EN; 7048c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_SP_CALIB(lane->id)); 7058c2ecf20Sopenharmony_ci val &= ~MVEBU_SP_CALIB_SAMPLER_EN; 7068c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_SP_CALIB(lane->id)); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* External rx regulator */ 7098c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_EXT_SELV(lane->id)); 7108c2ecf20Sopenharmony_ci val &= ~MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1f); 7118c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1a); 7128c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_EXT_SELV(lane->id)); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return mvebu_comphy_init_plls(lane); 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int mvebu_comphy_power_on_legacy(struct phy *phy) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 7208c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 7218c2ecf20Sopenharmony_ci int ret, mux; 7228c2ecf20Sopenharmony_ci u32 val; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci mux = mvebu_comphy_get_mux(lane->id, lane->port, 7258c2ecf20Sopenharmony_ci lane->mode, lane->submode); 7268c2ecf20Sopenharmony_ci if (mux < 0) 7278c2ecf20Sopenharmony_ci return -ENOTSUPP; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val); 7308c2ecf20Sopenharmony_ci val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id)); 7318c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val); 7348c2ecf20Sopenharmony_ci val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id)); 7358c2ecf20Sopenharmony_ci val |= mux << MVEBU_COMPHY_SELECTOR_PHY(lane->id); 7368c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci switch (lane->submode) { 7398c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 7408c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 7418c2ecf20Sopenharmony_ci ret = mvebu_comphy_set_mode_sgmii(phy); 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 7448c2ecf20Sopenharmony_ci ret = mvebu_comphy_set_mode_rxaui(phy); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 7478c2ecf20Sopenharmony_ci ret = mvebu_comphy_set_mode_10gbaser(phy); 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci default: 7508c2ecf20Sopenharmony_ci return -ENOTSUPP; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* digital reset */ 7548c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 7558c2ecf20Sopenharmony_ci val |= MVEBU_COMPHY_SERDES_CFG1_RF_RESET; 7568c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return ret; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic int mvebu_comphy_power_on(struct phy *phy) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 7648c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 7658c2ecf20Sopenharmony_ci int fw_mode, fw_speed; 7668c2ecf20Sopenharmony_ci u32 fw_param = 0; 7678c2ecf20Sopenharmony_ci int ret; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci fw_mode = mvebu_comphy_get_fw_mode(lane->id, lane->port, 7708c2ecf20Sopenharmony_ci lane->mode, lane->submode); 7718c2ecf20Sopenharmony_ci if (fw_mode < 0) 7728c2ecf20Sopenharmony_ci goto try_legacy; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Try SMC flow first */ 7758c2ecf20Sopenharmony_ci switch (lane->mode) { 7768c2ecf20Sopenharmony_ci case PHY_MODE_ETHERNET: 7778c2ecf20Sopenharmony_ci switch (lane->submode) { 7788c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 7798c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to RXAUI mode\n", 7808c2ecf20Sopenharmony_ci lane->id); 7818c2ecf20Sopenharmony_ci fw_speed = 0; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 7848c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to 1000BASE-X mode\n", 7858c2ecf20Sopenharmony_ci lane->id); 7868c2ecf20Sopenharmony_ci fw_speed = COMPHY_FW_SPEED_1250; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 7898c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to 2500BASE-X mode\n", 7908c2ecf20Sopenharmony_ci lane->id); 7918c2ecf20Sopenharmony_ci fw_speed = COMPHY_FW_SPEED_3125; 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_10GBASER: 7948c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to 10GBASE-R mode\n", 7958c2ecf20Sopenharmony_ci lane->id); 7968c2ecf20Sopenharmony_ci fw_speed = COMPHY_FW_SPEED_103125; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci default: 7998c2ecf20Sopenharmony_ci dev_err(priv->dev, "unsupported Ethernet mode (%d)\n", 8008c2ecf20Sopenharmony_ci lane->submode); 8018c2ecf20Sopenharmony_ci return -ENOTSUPP; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci fw_param = COMPHY_FW_PARAM_ETH(fw_mode, lane->port, fw_speed); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case PHY_MODE_USB_HOST_SS: 8068c2ecf20Sopenharmony_ci case PHY_MODE_USB_DEVICE_SS: 8078c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to USB3 mode\n", lane->id); 8088c2ecf20Sopenharmony_ci fw_param = COMPHY_FW_PARAM(fw_mode, lane->port); 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci case PHY_MODE_SATA: 8118c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to SATA mode\n", lane->id); 8128c2ecf20Sopenharmony_ci fw_param = COMPHY_FW_PARAM(fw_mode, lane->port); 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case PHY_MODE_PCIE: 8158c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "set lane %d to PCIe mode (x%d)\n", lane->id, 8168c2ecf20Sopenharmony_ci lane->submode); 8178c2ecf20Sopenharmony_ci fw_param = COMPHY_FW_PARAM_PCIE(fw_mode, lane->port, 8188c2ecf20Sopenharmony_ci lane->submode); 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci default: 8218c2ecf20Sopenharmony_ci dev_err(priv->dev, "unsupported PHY mode (%d)\n", lane->mode); 8228c2ecf20Sopenharmony_ci return -ENOTSUPP; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci ret = mvebu_comphy_smc(COMPHY_SIP_POWER_ON, priv->cp_phys, lane->id, 8268c2ecf20Sopenharmony_ci fw_param); 8278c2ecf20Sopenharmony_ci if (!ret) 8288c2ecf20Sopenharmony_ci return ret; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP) 8318c2ecf20Sopenharmony_ci dev_err(priv->dev, 8328c2ecf20Sopenharmony_ci "unsupported SMC call, try updating your firmware\n"); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci dev_warn(priv->dev, 8358c2ecf20Sopenharmony_ci "Firmware could not configure PHY %d with mode %d (ret: %d), trying legacy method\n", 8368c2ecf20Sopenharmony_ci lane->id, lane->mode, ret); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_citry_legacy: 8398c2ecf20Sopenharmony_ci /* Fallback to Linux's implementation */ 8408c2ecf20Sopenharmony_ci return mvebu_comphy_power_on_legacy(phy); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int mvebu_comphy_set_mode(struct phy *phy, 8448c2ecf20Sopenharmony_ci enum phy_mode mode, int submode) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (submode == PHY_INTERFACE_MODE_1000BASEX) 8498c2ecf20Sopenharmony_ci submode = PHY_INTERFACE_MODE_SGMII; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (mvebu_comphy_get_fw_mode(lane->id, lane->port, mode, submode) < 0) 8528c2ecf20Sopenharmony_ci return -EINVAL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci lane->mode = mode; 8558c2ecf20Sopenharmony_ci lane->submode = submode; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* PCIe submode represents the width */ 8588c2ecf20Sopenharmony_ci if (mode == PHY_MODE_PCIE && !lane->submode) 8598c2ecf20Sopenharmony_ci lane->submode = 1; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return 0; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int mvebu_comphy_power_off_legacy(struct phy *phy) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 8678c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 8688c2ecf20Sopenharmony_ci u32 val; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 8718c2ecf20Sopenharmony_ci val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET | 8728c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG1_CORE_RESET | 8738c2ecf20Sopenharmony_ci MVEBU_COMPHY_SERDES_CFG1_RF_RESET); 8748c2ecf20Sopenharmony_ci writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id)); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val); 8778c2ecf20Sopenharmony_ci val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id)); 8788c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val); 8818c2ecf20Sopenharmony_ci val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id)); 8828c2ecf20Sopenharmony_ci regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return 0; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int mvebu_comphy_power_off(struct phy *phy) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane = phy_get_drvdata(phy); 8908c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv = lane->priv; 8918c2ecf20Sopenharmony_ci int ret; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ret = mvebu_comphy_smc(COMPHY_SIP_POWER_OFF, priv->cp_phys, 8948c2ecf20Sopenharmony_ci lane->id, 0); 8958c2ecf20Sopenharmony_ci if (!ret) 8968c2ecf20Sopenharmony_ci return ret; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Fallback to Linux's implementation */ 8998c2ecf20Sopenharmony_ci return mvebu_comphy_power_off_legacy(phy); 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic const struct phy_ops mvebu_comphy_ops = { 9038c2ecf20Sopenharmony_ci .power_on = mvebu_comphy_power_on, 9048c2ecf20Sopenharmony_ci .power_off = mvebu_comphy_power_off, 9058c2ecf20Sopenharmony_ci .set_mode = mvebu_comphy_set_mode, 9068c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9078c2ecf20Sopenharmony_ci}; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic struct phy *mvebu_comphy_xlate(struct device *dev, 9108c2ecf20Sopenharmony_ci struct of_phandle_args *args) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane; 9138c2ecf20Sopenharmony_ci struct phy *phy; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (WARN_ON(args->args[0] >= MVEBU_COMPHY_PORTS)) 9168c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci phy = of_phy_simple_xlate(dev, args); 9198c2ecf20Sopenharmony_ci if (IS_ERR(phy)) 9208c2ecf20Sopenharmony_ci return phy; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci lane = phy_get_drvdata(phy); 9238c2ecf20Sopenharmony_ci lane->port = args->args[0]; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return phy; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int mvebu_comphy_init_clks(struct mvebu_comphy_priv *priv) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci int ret; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci priv->mg_domain_clk = devm_clk_get(priv->dev, "mg_clk"); 9338c2ecf20Sopenharmony_ci if (IS_ERR(priv->mg_domain_clk)) 9348c2ecf20Sopenharmony_ci return PTR_ERR(priv->mg_domain_clk); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->mg_domain_clk); 9378c2ecf20Sopenharmony_ci if (ret < 0) 9388c2ecf20Sopenharmony_ci return ret; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci priv->mg_core_clk = devm_clk_get(priv->dev, "mg_core_clk"); 9418c2ecf20Sopenharmony_ci if (IS_ERR(priv->mg_core_clk)) { 9428c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->mg_core_clk); 9438c2ecf20Sopenharmony_ci goto dis_mg_domain_clk; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->mg_core_clk); 9478c2ecf20Sopenharmony_ci if (ret < 0) 9488c2ecf20Sopenharmony_ci goto dis_mg_domain_clk; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci priv->axi_clk = devm_clk_get(priv->dev, "axi_clk"); 9518c2ecf20Sopenharmony_ci if (IS_ERR(priv->axi_clk)) { 9528c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->axi_clk); 9538c2ecf20Sopenharmony_ci goto dis_mg_core_clk; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->axi_clk); 9578c2ecf20Sopenharmony_ci if (ret < 0) 9588c2ecf20Sopenharmony_ci goto dis_mg_core_clk; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cidis_mg_core_clk: 9638c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->mg_core_clk); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cidis_mg_domain_clk: 9668c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->mg_domain_clk); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci priv->mg_domain_clk = NULL; 9698c2ecf20Sopenharmony_ci priv->mg_core_clk = NULL; 9708c2ecf20Sopenharmony_ci priv->axi_clk = NULL; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return ret; 9738c2ecf20Sopenharmony_ci}; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic void mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv *priv) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci if (priv->axi_clk) 9788c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->axi_clk); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (priv->mg_core_clk) 9818c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->mg_core_clk); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (priv->mg_domain_clk) 9848c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->mg_domain_clk); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic int mvebu_comphy_probe(struct platform_device *pdev) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct mvebu_comphy_priv *priv; 9908c2ecf20Sopenharmony_ci struct phy_provider *provider; 9918c2ecf20Sopenharmony_ci struct device_node *child; 9928c2ecf20Sopenharmony_ci struct resource *res; 9938c2ecf20Sopenharmony_ci int ret; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 9968c2ecf20Sopenharmony_ci if (!priv) 9978c2ecf20Sopenharmony_ci return -ENOMEM; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 10008c2ecf20Sopenharmony_ci priv->regmap = 10018c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 10028c2ecf20Sopenharmony_ci "marvell,system-controller"); 10038c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) 10048c2ecf20Sopenharmony_ci return PTR_ERR(priv->regmap); 10058c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10068c2ecf20Sopenharmony_ci priv->base = devm_ioremap_resource(&pdev->dev, res); 10078c2ecf20Sopenharmony_ci if (IS_ERR(priv->base)) 10088c2ecf20Sopenharmony_ci return PTR_ERR(priv->base); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* 10118c2ecf20Sopenharmony_ci * Ignore error if clocks have not been initialized properly for DT 10128c2ecf20Sopenharmony_ci * compatibility reasons. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_ci ret = mvebu_comphy_init_clks(priv); 10158c2ecf20Sopenharmony_ci if (ret) { 10168c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 10178c2ecf20Sopenharmony_ci return ret; 10188c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "cannot initialize clocks\n"); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* 10228c2ecf20Sopenharmony_ci * Hack to retrieve a physical offset relative to this CP that will be 10238c2ecf20Sopenharmony_ci * given to the firmware 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_ci priv->cp_phys = res->start; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci for_each_available_child_of_node(pdev->dev.of_node, child) { 10288c2ecf20Sopenharmony_ci struct mvebu_comphy_lane *lane; 10298c2ecf20Sopenharmony_ci struct phy *phy; 10308c2ecf20Sopenharmony_ci u32 val; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "reg", &val); 10338c2ecf20Sopenharmony_ci if (ret < 0) { 10348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing 'reg' property (%d)\n", 10358c2ecf20Sopenharmony_ci ret); 10368c2ecf20Sopenharmony_ci continue; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (val >= MVEBU_COMPHY_LANES) { 10408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid 'reg' property\n"); 10418c2ecf20Sopenharmony_ci continue; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL); 10458c2ecf20Sopenharmony_ci if (!lane) { 10468c2ecf20Sopenharmony_ci of_node_put(child); 10478c2ecf20Sopenharmony_ci ret = -ENOMEM; 10488c2ecf20Sopenharmony_ci goto disable_clks; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci phy = devm_phy_create(&pdev->dev, child, &mvebu_comphy_ops); 10528c2ecf20Sopenharmony_ci if (IS_ERR(phy)) { 10538c2ecf20Sopenharmony_ci of_node_put(child); 10548c2ecf20Sopenharmony_ci ret = PTR_ERR(phy); 10558c2ecf20Sopenharmony_ci goto disable_clks; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci lane->priv = priv; 10598c2ecf20Sopenharmony_ci lane->mode = PHY_MODE_INVALID; 10608c2ecf20Sopenharmony_ci lane->submode = PHY_INTERFACE_MODE_NA; 10618c2ecf20Sopenharmony_ci lane->id = val; 10628c2ecf20Sopenharmony_ci lane->port = -1; 10638c2ecf20Sopenharmony_ci phy_set_drvdata(phy, lane); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* 10668c2ecf20Sopenharmony_ci * All modes are supported in this driver so we could call 10678c2ecf20Sopenharmony_ci * mvebu_comphy_power_off(phy) here to avoid relying on the 10688c2ecf20Sopenharmony_ci * bootloader/firmware configuration, but for compatibility 10698c2ecf20Sopenharmony_ci * reasons we cannot de-configure the COMPHY without being sure 10708c2ecf20Sopenharmony_ci * that the firmware is up-to-date and fully-featured. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, priv); 10758c2ecf20Sopenharmony_ci provider = devm_of_phy_provider_register(&pdev->dev, 10768c2ecf20Sopenharmony_ci mvebu_comphy_xlate); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(provider); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cidisable_clks: 10818c2ecf20Sopenharmony_ci mvebu_comphy_disable_unprepare_clks(priv); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci return ret; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic const struct of_device_id mvebu_comphy_of_match_table[] = { 10878c2ecf20Sopenharmony_ci { .compatible = "marvell,comphy-cp110" }, 10888c2ecf20Sopenharmony_ci { }, 10898c2ecf20Sopenharmony_ci}; 10908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mvebu_comphy_of_match_table); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic struct platform_driver mvebu_comphy_driver = { 10938c2ecf20Sopenharmony_ci .probe = mvebu_comphy_probe, 10948c2ecf20Sopenharmony_ci .driver = { 10958c2ecf20Sopenharmony_ci .name = "mvebu-comphy", 10968c2ecf20Sopenharmony_ci .of_match_table = mvebu_comphy_of_match_table, 10978c2ecf20Sopenharmony_ci }, 10988c2ecf20Sopenharmony_ci}; 10998c2ecf20Sopenharmony_cimodule_platform_driver(mvebu_comphy_driver); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 11028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Common PHY driver for mvebu SoCs"); 11038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1104