1113 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2017 Marvell4 *5 * Antoine Tenart <antoine.tenart@free-electrons.com>6 */7 8#include <linux/arm-smccc.h>9#include <linux/clk.h>10#include <linux/io.h>11#include <linux/iopoll.h>12#include <linux/mfd/syscon.h>13#include <linux/module.h>14#include <linux/of.h>15#include <linux/phy.h>16#include <linux/phy/phy.h>17#include <linux/platform_device.h>18#include <linux/regmap.h>19 20/* Relative to priv->base */21#define MVEBU_COMPHY_SERDES_CFG0(n) (0x0 + (n) * 0x1000)22#define MVEBU_COMPHY_SERDES_CFG0_PU_PLL BIT(1)23#define MVEBU_COMPHY_SERDES_CFG0_GEN_RX(n) ((n) << 3)24#define MVEBU_COMPHY_SERDES_CFG0_GEN_TX(n) ((n) << 7)25#define MVEBU_COMPHY_SERDES_CFG0_PU_RX BIT(11)26#define MVEBU_COMPHY_SERDES_CFG0_PU_TX BIT(12)27#define MVEBU_COMPHY_SERDES_CFG0_HALF_BUS BIT(14)28#define MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE BIT(15)29#define MVEBU_COMPHY_SERDES_CFG1(n) (0x4 + (n) * 0x1000)30#define MVEBU_COMPHY_SERDES_CFG1_RESET BIT(3)31#define MVEBU_COMPHY_SERDES_CFG1_RX_INIT BIT(4)32#define MVEBU_COMPHY_SERDES_CFG1_CORE_RESET BIT(5)33#define MVEBU_COMPHY_SERDES_CFG1_RF_RESET BIT(6)34#define MVEBU_COMPHY_SERDES_CFG2(n) (0x8 + (n) * 0x1000)35#define MVEBU_COMPHY_SERDES_CFG2_DFE_EN BIT(4)36#define MVEBU_COMPHY_SERDES_STATUS0(n) (0x18 + (n) * 0x1000)37#define MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY BIT(2)38#define MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY BIT(3)39#define MVEBU_COMPHY_SERDES_STATUS0_RX_INIT BIT(4)40#define MVEBU_COMPHY_PWRPLL_CTRL(n) (0x804 + (n) * 0x1000)41#define MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(n) ((n) << 0)42#define MVEBU_COMPHY_PWRPLL_PHY_MODE(n) ((n) << 5)43#define MVEBU_COMPHY_IMP_CAL(n) (0x80c + (n) * 0x1000)44#define MVEBU_COMPHY_IMP_CAL_TX_EXT(n) ((n) << 10)45#define MVEBU_COMPHY_IMP_CAL_TX_EXT_EN BIT(15)46#define MVEBU_COMPHY_DFE_RES(n) (0x81c + (n) * 0x1000)47#define MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL BIT(15)48#define MVEBU_COMPHY_COEF(n) (0x828 + (n) * 0x1000)49#define MVEBU_COMPHY_COEF_DFE_EN BIT(14)50#define MVEBU_COMPHY_COEF_DFE_CTRL BIT(15)51#define MVEBU_COMPHY_GEN1_S0(n) (0x834 + (n) * 0x1000)52#define MVEBU_COMPHY_GEN1_S0_TX_AMP(n) ((n) << 1)53#define MVEBU_COMPHY_GEN1_S0_TX_EMPH(n) ((n) << 7)54#define MVEBU_COMPHY_GEN1_S1(n) (0x838 + (n) * 0x1000)55#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(n) ((n) << 0)56#define MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(n) ((n) << 3)57#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(n) ((n) << 6)58#define MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(n) ((n) << 8)59#define MVEBU_COMPHY_GEN1_S1_RX_DFE_EN BIT(10)60#define MVEBU_COMPHY_GEN1_S1_RX_DIV(n) ((n) << 11)61#define MVEBU_COMPHY_GEN1_S2(n) (0x8f4 + (n) * 0x1000)62#define MVEBU_COMPHY_GEN1_S2_TX_EMPH(n) ((n) << 0)63#define MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN BIT(4)64#define MVEBU_COMPHY_LOOPBACK(n) (0x88c + (n) * 0x1000)65#define MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(n) ((n) << 1)66#define MVEBU_COMPHY_VDD_CAL0(n) (0x908 + (n) * 0x1000)67#define MVEBU_COMPHY_VDD_CAL0_CONT_MODE BIT(15)68#define MVEBU_COMPHY_EXT_SELV(n) (0x914 + (n) * 0x1000)69#define MVEBU_COMPHY_EXT_SELV_RX_SAMPL(n) ((n) << 5)70#define MVEBU_COMPHY_MISC_CTRL0(n) (0x93c + (n) * 0x1000)71#define MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE BIT(5)72#define MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL BIT(10)73#define MVEBU_COMPHY_RX_CTRL1(n) (0x940 + (n) * 0x1000)74#define MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL BIT(11)75#define MVEBU_COMPHY_RX_CTRL1_CLK8T_EN BIT(12)76#define MVEBU_COMPHY_SPEED_DIV(n) (0x954 + (n) * 0x1000)77#define MVEBU_COMPHY_SPEED_DIV_TX_FORCE BIT(7)78#define MVEBU_SP_CALIB(n) (0x96c + (n) * 0x1000)79#define MVEBU_SP_CALIB_SAMPLER(n) ((n) << 8)80#define MVEBU_SP_CALIB_SAMPLER_EN BIT(12)81#define MVEBU_COMPHY_TX_SLEW_RATE(n) (0x974 + (n) * 0x1000)82#define MVEBU_COMPHY_TX_SLEW_RATE_EMPH(n) ((n) << 5)83#define MVEBU_COMPHY_TX_SLEW_RATE_SLC(n) ((n) << 10)84#define MVEBU_COMPHY_DTL_CTRL(n) (0x984 + (n) * 0x1000)85#define MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN BIT(2)86#define MVEBU_COMPHY_FRAME_DETECT0(n) (0xa14 + (n) * 0x1000)87#define MVEBU_COMPHY_FRAME_DETECT0_PATN(n) ((n) << 7)88#define MVEBU_COMPHY_FRAME_DETECT3(n) (0xa20 + (n) * 0x1000)89#define MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN BIT(12)90#define MVEBU_COMPHY_DME(n) (0xa28 + (n) * 0x1000)91#define MVEBU_COMPHY_DME_ETH_MODE BIT(7)92#define MVEBU_COMPHY_TRAINING0(n) (0xa68 + (n) * 0x1000)93#define MVEBU_COMPHY_TRAINING0_P2P_HOLD BIT(15)94#define MVEBU_COMPHY_TRAINING5(n) (0xaa4 + (n) * 0x1000)95#define MVEBU_COMPHY_TRAINING5_RX_TIMER(n) ((n) << 0)96#define MVEBU_COMPHY_TX_TRAIN_PRESET(n) (0xb1c + (n) * 0x1000)97#define MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN BIT(8)98#define MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11 BIT(9)99#define MVEBU_COMPHY_GEN1_S3(n) (0xc40 + (n) * 0x1000)100#define MVEBU_COMPHY_GEN1_S3_FBCK_SEL BIT(9)101#define MVEBU_COMPHY_GEN1_S4(n) (0xc44 + (n) * 0x1000)102#define MVEBU_COMPHY_GEN1_S4_DFE_RES(n) ((n) << 8)103#define MVEBU_COMPHY_TX_PRESET(n) (0xc68 + (n) * 0x1000)104#define MVEBU_COMPHY_TX_PRESET_INDEX(n) ((n) << 0)105#define MVEBU_COMPHY_GEN1_S5(n) (0xd38 + (n) * 0x1000)106#define MVEBU_COMPHY_GEN1_S5_ICP(n) ((n) << 0)107 108/* Relative to priv->regmap */109#define MVEBU_COMPHY_CONF1(n) (0x1000 + (n) * 0x28)110#define MVEBU_COMPHY_CONF1_PWRUP BIT(1)111#define MVEBU_COMPHY_CONF1_USB_PCIE BIT(2) /* 0: Ethernet/SATA */112#define MVEBU_COMPHY_CONF6(n) (0x1014 + (n) * 0x28)113#define MVEBU_COMPHY_CONF6_40B BIT(18)114#define MVEBU_COMPHY_SELECTOR 0x1140115#define MVEBU_COMPHY_SELECTOR_PHY(n) ((n) * 0x4)116#define MVEBU_COMPHY_PIPE_SELECTOR 0x1144117#define MVEBU_COMPHY_PIPE_SELECTOR_PIPE(n) ((n) * 0x4)118#define MVEBU_COMPHY_SD1_CTRL1 0x1148119#define MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN BIT(26)120#define MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN BIT(27)121 122#define MVEBU_COMPHY_LANES 6123#define MVEBU_COMPHY_PORTS 3124 125#define COMPHY_SIP_POWER_ON 0x82000001126#define COMPHY_SIP_POWER_OFF 0x82000002127 128/*129 * A lane is described by the following bitfields:130 * [ 1- 0]: COMPHY polarity invertion131 * [ 2- 7]: COMPHY speed132 * [ 5-11]: COMPHY port index133 * [12-16]: COMPHY mode134 * [17]: Clock source135 * [18-20]: PCIe width (x1, x2, x4)136 */137#define COMPHY_FW_POL_OFFSET 0138#define COMPHY_FW_POL_MASK GENMASK(1, 0)139#define COMPHY_FW_SPEED_OFFSET 2140#define COMPHY_FW_SPEED_MASK GENMASK(7, 2)141#define COMPHY_FW_SPEED_MAX COMPHY_FW_SPEED_MASK142#define COMPHY_FW_SPEED_1250 0143#define COMPHY_FW_SPEED_3125 2144#define COMPHY_FW_SPEED_5000 3145#define COMPHY_FW_SPEED_515625 4146#define COMPHY_FW_SPEED_103125 6147#define COMPHY_FW_PORT_OFFSET 8148#define COMPHY_FW_PORT_MASK GENMASK(11, 8)149#define COMPHY_FW_MODE_OFFSET 12150#define COMPHY_FW_MODE_MASK GENMASK(16, 12)151#define COMPHY_FW_WIDTH_OFFSET 18152#define COMPHY_FW_WIDTH_MASK GENMASK(20, 18)153 154#define COMPHY_FW_PARAM_FULL(mode, port, speed, pol, width) \155 ((((pol) << COMPHY_FW_POL_OFFSET) & COMPHY_FW_POL_MASK) | \156 (((mode) << COMPHY_FW_MODE_OFFSET) & COMPHY_FW_MODE_MASK) | \157 (((port) << COMPHY_FW_PORT_OFFSET) & COMPHY_FW_PORT_MASK) | \158 (((speed) << COMPHY_FW_SPEED_OFFSET) & COMPHY_FW_SPEED_MASK) | \159 (((width) << COMPHY_FW_WIDTH_OFFSET) & COMPHY_FW_WIDTH_MASK))160 161#define COMPHY_FW_PARAM(mode, port) \162 COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_MAX, 0, 0)163 164#define COMPHY_FW_PARAM_ETH(mode, port, speed) \165 COMPHY_FW_PARAM_FULL(mode, port, speed, 0, 0)166 167#define COMPHY_FW_PARAM_PCIE(mode, port, width) \168 COMPHY_FW_PARAM_FULL(mode, port, COMPHY_FW_SPEED_5000, 0, width)169 170#define COMPHY_FW_MODE_SATA 0x1171#define COMPHY_FW_MODE_SGMII 0x2 /* SGMII 1G */172#define COMPHY_FW_MODE_2500BASEX 0x3 /* 2500BASE-X */173#define COMPHY_FW_MODE_USB3H 0x4174#define COMPHY_FW_MODE_USB3D 0x5175#define COMPHY_FW_MODE_PCIE 0x6176#define COMPHY_FW_MODE_RXAUI 0x7177#define COMPHY_FW_MODE_XFI 0x8 /* SFI: 0x9 (is treated like XFI) */178 179struct mvebu_comphy_conf {180 enum phy_mode mode;181 int submode;182 unsigned lane;183 unsigned port;184 u32 mux;185 u32 fw_mode;186};187 188#define ETH_CONF(_lane, _port, _submode, _mux, _fw) \189 { \190 .lane = _lane, \191 .port = _port, \192 .mode = PHY_MODE_ETHERNET, \193 .submode = _submode, \194 .mux = _mux, \195 .fw_mode = _fw, \196 }197 198#define GEN_CONF(_lane, _port, _mode, _fw) \199 { \200 .lane = _lane, \201 .port = _port, \202 .mode = _mode, \203 .submode = PHY_INTERFACE_MODE_NA, \204 .mux = -1, \205 .fw_mode = _fw, \206 }207 208static const struct mvebu_comphy_conf mvebu_comphy_cp110_modes[] = {209 /* lane 0 */210 GEN_CONF(0, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),211 ETH_CONF(0, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),212 ETH_CONF(0, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),213 GEN_CONF(0, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),214 /* lane 1 */215 GEN_CONF(1, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),216 GEN_CONF(1, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),217 GEN_CONF(1, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),218 GEN_CONF(1, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),219 ETH_CONF(1, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),220 ETH_CONF(1, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),221 /* lane 2 */222 ETH_CONF(2, 0, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),223 ETH_CONF(2, 0, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),224 ETH_CONF(2, 0, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),225 ETH_CONF(2, 0, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI),226 ETH_CONF(2, 0, PHY_INTERFACE_MODE_10GBASER, 0x1, COMPHY_FW_MODE_XFI),227 GEN_CONF(2, 0, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),228 GEN_CONF(2, 0, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),229 GEN_CONF(2, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),230 /* lane 3 */231 GEN_CONF(3, 0, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),232 ETH_CONF(3, 1, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),233 ETH_CONF(3, 1, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),234 ETH_CONF(3, 1, PHY_INTERFACE_MODE_RXAUI, 0x1, COMPHY_FW_MODE_RXAUI),235 GEN_CONF(3, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),236 GEN_CONF(3, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),237 /* lane 4 */238 ETH_CONF(4, 0, PHY_INTERFACE_MODE_SGMII, 0x2, COMPHY_FW_MODE_SGMII),239 ETH_CONF(4, 0, PHY_INTERFACE_MODE_2500BASEX, 0x2, COMPHY_FW_MODE_2500BASEX),240 ETH_CONF(4, 0, PHY_INTERFACE_MODE_5GBASER, 0x2, COMPHY_FW_MODE_XFI),241 ETH_CONF(4, 0, PHY_INTERFACE_MODE_10GBASER, 0x2, COMPHY_FW_MODE_XFI),242 ETH_CONF(4, 0, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),243 GEN_CONF(4, 0, PHY_MODE_USB_DEVICE_SS, COMPHY_FW_MODE_USB3D),244 GEN_CONF(4, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H),245 GEN_CONF(4, 1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),246 ETH_CONF(4, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),247 ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),248 ETH_CONF(4, 1, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI),249 ETH_CONF(4, 1, PHY_INTERFACE_MODE_10GBASER, -1, COMPHY_FW_MODE_XFI),250 /* lane 5 */251 ETH_CONF(5, 1, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI),252 GEN_CONF(5, 1, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),253 ETH_CONF(5, 2, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII),254 ETH_CONF(5, 2, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX),255 GEN_CONF(5, 2, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),256};257 258struct mvebu_comphy_priv {259 void __iomem *base;260 struct regmap *regmap;261 struct device *dev;262 struct clk *mg_domain_clk;263 struct clk *mg_core_clk;264 struct clk *axi_clk;265 unsigned long cp_phys;266};267 268struct mvebu_comphy_lane {269 struct mvebu_comphy_priv *priv;270 unsigned id;271 enum phy_mode mode;272 int submode;273 int port;274};275 276static int mvebu_comphy_smc(unsigned long function, unsigned long phys,277 unsigned long lane, unsigned long mode)278{279 struct arm_smccc_res res;280 s32 ret;281 282 arm_smccc_smc(function, phys, lane, mode, 0, 0, 0, 0, &res);283 ret = res.a0;284 285 switch (ret) {286 case SMCCC_RET_SUCCESS:287 return 0;288 case SMCCC_RET_NOT_SUPPORTED:289 return -EOPNOTSUPP;290 default:291 return -EINVAL;292 }293}294 295static int mvebu_comphy_get_mode(bool fw_mode, int lane, int port,296 enum phy_mode mode, int submode)297{298 int i, n = ARRAY_SIZE(mvebu_comphy_cp110_modes);299 /* Ignore PCIe submode: it represents the width */300 bool ignore_submode = (mode == PHY_MODE_PCIE);301 const struct mvebu_comphy_conf *conf;302 303 /* Unused PHY mux value is 0x0 */304 if (mode == PHY_MODE_INVALID)305 return 0;306 307 for (i = 0; i < n; i++) {308 conf = &mvebu_comphy_cp110_modes[i];309 if (conf->lane == lane &&310 conf->port == port &&311 conf->mode == mode &&312 (conf->submode == submode || ignore_submode))313 break;314 }315 316 if (i == n)317 return -EINVAL;318 319 if (fw_mode)320 return conf->fw_mode;321 else322 return conf->mux;323}324 325static inline int mvebu_comphy_get_mux(int lane, int port,326 enum phy_mode mode, int submode)327{328 return mvebu_comphy_get_mode(false, lane, port, mode, submode);329}330 331static inline int mvebu_comphy_get_fw_mode(int lane, int port,332 enum phy_mode mode, int submode)333{334 return mvebu_comphy_get_mode(true, lane, port, mode, submode);335}336 337static int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane)338{339 struct mvebu_comphy_priv *priv = lane->priv;340 u32 val;341 342 regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);343 val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;344 val |= MVEBU_COMPHY_CONF1_PWRUP;345 regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);346 347 /* Select baud rates and PLLs */348 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));349 val &= ~(MVEBU_COMPHY_SERDES_CFG0_PU_PLL |350 MVEBU_COMPHY_SERDES_CFG0_PU_RX |351 MVEBU_COMPHY_SERDES_CFG0_PU_TX |352 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS |353 MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xf) |354 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xf) |355 MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE);356 357 switch (lane->submode) {358 case PHY_INTERFACE_MODE_10GBASER:359 val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xe) |360 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xe);361 break;362 case PHY_INTERFACE_MODE_RXAUI:363 val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0xb) |364 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0xb) |365 MVEBU_COMPHY_SERDES_CFG0_RXAUI_MODE;366 break;367 case PHY_INTERFACE_MODE_2500BASEX:368 val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x8) |369 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x8) |370 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;371 break;372 case PHY_INTERFACE_MODE_SGMII:373 val |= MVEBU_COMPHY_SERDES_CFG0_GEN_RX(0x6) |374 MVEBU_COMPHY_SERDES_CFG0_GEN_TX(0x6) |375 MVEBU_COMPHY_SERDES_CFG0_HALF_BUS;376 break;377 default:378 dev_err(priv->dev,379 "unsupported comphy submode (%d) on lane %d\n",380 lane->submode,381 lane->id);382 return -ENOTSUPP;383 }384 385 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));386 387 if (lane->submode == PHY_INTERFACE_MODE_RXAUI) {388 regmap_read(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, &val);389 390 switch (lane->id) {391 case 2:392 case 3:393 val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI0_EN;394 break;395 case 4:396 case 5:397 val |= MVEBU_COMPHY_SD1_CTRL1_RXAUI1_EN;398 break;399 default:400 dev_err(priv->dev,401 "RXAUI is not supported on comphy lane %d\n",402 lane->id);403 return -EINVAL;404 }405 406 regmap_write(priv->regmap, MVEBU_COMPHY_SD1_CTRL1, val);407 }408 409 /* reset */410 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));411 val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |412 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |413 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);414 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));415 416 /* de-assert reset */417 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));418 val |= MVEBU_COMPHY_SERDES_CFG1_RESET |419 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET;420 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));421 422 /* wait until clocks are ready */423 mdelay(1);424 425 /* exlicitly disable 40B, the bits isn't clear on reset */426 regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);427 val &= ~MVEBU_COMPHY_CONF6_40B;428 regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);429 430 /* refclk selection */431 val = readl(priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));432 val &= ~MVEBU_COMPHY_MISC_CTRL0_REFCLK_SEL;433 if (lane->submode == PHY_INTERFACE_MODE_10GBASER)434 val |= MVEBU_COMPHY_MISC_CTRL0_ICP_FORCE;435 writel(val, priv->base + MVEBU_COMPHY_MISC_CTRL0(lane->id));436 437 /* power and pll selection */438 val = readl(priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));439 val &= ~(MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1f) |440 MVEBU_COMPHY_PWRPLL_PHY_MODE(0x7));441 val |= MVEBU_COMPHY_PWRPLL_CTRL_RFREQ(0x1) |442 MVEBU_COMPHY_PWRPLL_PHY_MODE(0x4);443 writel(val, priv->base + MVEBU_COMPHY_PWRPLL_CTRL(lane->id));444 445 val = readl(priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));446 val &= ~MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x7);447 val |= MVEBU_COMPHY_LOOPBACK_DBUS_WIDTH(0x1);448 writel(val, priv->base + MVEBU_COMPHY_LOOPBACK(lane->id));449 450 return 0;451}452 453static int mvebu_comphy_init_plls(struct mvebu_comphy_lane *lane)454{455 struct mvebu_comphy_priv *priv = lane->priv;456 u32 val;457 458 /* SERDES external config */459 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));460 val |= MVEBU_COMPHY_SERDES_CFG0_PU_PLL |461 MVEBU_COMPHY_SERDES_CFG0_PU_RX |462 MVEBU_COMPHY_SERDES_CFG0_PU_TX;463 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG0(lane->id));464 465 /* check rx/tx pll */466 readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),467 val,468 val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |469 MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY),470 1000, 150000);471 if (!(val & (MVEBU_COMPHY_SERDES_STATUS0_RX_PLL_RDY |472 MVEBU_COMPHY_SERDES_STATUS0_TX_PLL_RDY)))473 return -ETIMEDOUT;474 475 /* rx init */476 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));477 val |= MVEBU_COMPHY_SERDES_CFG1_RX_INIT;478 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));479 480 /* check rx */481 readl_poll_timeout(priv->base + MVEBU_COMPHY_SERDES_STATUS0(lane->id),482 val, val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT,483 1000, 10000);484 if (!(val & MVEBU_COMPHY_SERDES_STATUS0_RX_INIT))485 return -ETIMEDOUT;486 487 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));488 val &= ~MVEBU_COMPHY_SERDES_CFG1_RX_INIT;489 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));490 491 return 0;492}493 494static int mvebu_comphy_set_mode_sgmii(struct phy *phy)495{496 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);497 struct mvebu_comphy_priv *priv = lane->priv;498 u32 val;499 int err;500 501 err = mvebu_comphy_ethernet_init_reset(lane);502 if (err)503 return err;504 505 val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));506 val &= ~MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;507 val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL;508 writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));509 510 val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));511 val &= ~MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;512 writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));513 514 regmap_read(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), &val);515 val &= ~MVEBU_COMPHY_CONF1_USB_PCIE;516 val |= MVEBU_COMPHY_CONF1_PWRUP;517 regmap_write(priv->regmap, MVEBU_COMPHY_CONF1(lane->id), val);518 519 val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));520 val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);521 val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0x1);522 writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));523 524 return mvebu_comphy_init_plls(lane);525}526 527static int mvebu_comphy_set_mode_rxaui(struct phy *phy)528{529 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);530 struct mvebu_comphy_priv *priv = lane->priv;531 u32 val;532 int err;533 534 err = mvebu_comphy_ethernet_init_reset(lane);535 if (err)536 return err;537 538 val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));539 val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |540 MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;541 writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));542 543 val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));544 val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;545 writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));546 547 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));548 val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;549 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));550 551 val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));552 val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;553 writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));554 555 val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));556 val &= ~MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf);557 val |= MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xd);558 writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));559 560 val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));561 val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |562 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7));563 val |= MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x1) |564 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x1) |565 MVEBU_COMPHY_GEN1_S1_RX_DFE_EN;566 writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));567 568 val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));569 val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);570 writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));571 572 val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));573 val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);574 val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);575 writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));576 577 return mvebu_comphy_init_plls(lane);578}579 580static int mvebu_comphy_set_mode_10gbaser(struct phy *phy)581{582 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);583 struct mvebu_comphy_priv *priv = lane->priv;584 u32 val;585 int err;586 587 err = mvebu_comphy_ethernet_init_reset(lane);588 if (err)589 return err;590 591 val = readl(priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));592 val |= MVEBU_COMPHY_RX_CTRL1_RXCLK2X_SEL |593 MVEBU_COMPHY_RX_CTRL1_CLK8T_EN;594 writel(val, priv->base + MVEBU_COMPHY_RX_CTRL1(lane->id));595 596 val = readl(priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));597 val |= MVEBU_COMPHY_DTL_CTRL_DTL_FLOOP_EN;598 writel(val, priv->base + MVEBU_COMPHY_DTL_CTRL(lane->id));599 600 /* Speed divider */601 val = readl(priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));602 val |= MVEBU_COMPHY_SPEED_DIV_TX_FORCE;603 writel(val, priv->base + MVEBU_COMPHY_SPEED_DIV(lane->id));604 605 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));606 val |= MVEBU_COMPHY_SERDES_CFG2_DFE_EN;607 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG2(lane->id));608 609 /* DFE resolution */610 val = readl(priv->base + MVEBU_COMPHY_DFE_RES(lane->id));611 val |= MVEBU_COMPHY_DFE_RES_FORCE_GEN_TBL;612 writel(val, priv->base + MVEBU_COMPHY_DFE_RES(lane->id));613 614 val = readl(priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));615 val &= ~(MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1f) |616 MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xf));617 val |= MVEBU_COMPHY_GEN1_S0_TX_AMP(0x1c) |618 MVEBU_COMPHY_GEN1_S0_TX_EMPH(0xe);619 writel(val, priv->base + MVEBU_COMPHY_GEN1_S0(lane->id));620 621 val = readl(priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));622 val &= ~MVEBU_COMPHY_GEN1_S2_TX_EMPH(0xf);623 val |= MVEBU_COMPHY_GEN1_S2_TX_EMPH_EN;624 writel(val, priv->base + MVEBU_COMPHY_GEN1_S2(lane->id));625 626 val = readl(priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));627 val |= MVEBU_COMPHY_TX_SLEW_RATE_EMPH(0x3) |628 MVEBU_COMPHY_TX_SLEW_RATE_SLC(0x3f);629 writel(val, priv->base + MVEBU_COMPHY_TX_SLEW_RATE(lane->id));630 631 /* Impedance calibration */632 val = readl(priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));633 val &= ~MVEBU_COMPHY_IMP_CAL_TX_EXT(0x1f);634 val |= MVEBU_COMPHY_IMP_CAL_TX_EXT(0xe) |635 MVEBU_COMPHY_IMP_CAL_TX_EXT_EN;636 writel(val, priv->base + MVEBU_COMPHY_IMP_CAL(lane->id));637 638 val = readl(priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));639 val &= ~MVEBU_COMPHY_GEN1_S5_ICP(0xf);640 writel(val, priv->base + MVEBU_COMPHY_GEN1_S5(lane->id));641 642 val = readl(priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));643 val &= ~(MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x7) |644 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x7) |645 MVEBU_COMPHY_GEN1_S1_RX_MUL_FI(0x3) |646 MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x3));647 val |= MVEBU_COMPHY_GEN1_S1_RX_DFE_EN |648 MVEBU_COMPHY_GEN1_S1_RX_MUL_PI(0x2) |649 MVEBU_COMPHY_GEN1_S1_RX_MUL_PF(0x2) |650 MVEBU_COMPHY_GEN1_S1_RX_MUL_FF(0x1) |651 MVEBU_COMPHY_GEN1_S1_RX_DIV(0x3);652 writel(val, priv->base + MVEBU_COMPHY_GEN1_S1(lane->id));653 654 val = readl(priv->base + MVEBU_COMPHY_COEF(lane->id));655 val &= ~(MVEBU_COMPHY_COEF_DFE_EN | MVEBU_COMPHY_COEF_DFE_CTRL);656 writel(val, priv->base + MVEBU_COMPHY_COEF(lane->id));657 658 val = readl(priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));659 val &= ~MVEBU_COMPHY_GEN1_S4_DFE_RES(0x3);660 val |= MVEBU_COMPHY_GEN1_S4_DFE_RES(0x1);661 writel(val, priv->base + MVEBU_COMPHY_GEN1_S4(lane->id));662 663 val = readl(priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));664 val |= MVEBU_COMPHY_GEN1_S3_FBCK_SEL;665 writel(val, priv->base + MVEBU_COMPHY_GEN1_S3(lane->id));666 667 /* rx training timer */668 val = readl(priv->base + MVEBU_COMPHY_TRAINING5(lane->id));669 val &= ~MVEBU_COMPHY_TRAINING5_RX_TIMER(0x3ff);670 val |= MVEBU_COMPHY_TRAINING5_RX_TIMER(0x13);671 writel(val, priv->base + MVEBU_COMPHY_TRAINING5(lane->id));672 673 /* tx train peak to peak hold */674 val = readl(priv->base + MVEBU_COMPHY_TRAINING0(lane->id));675 val |= MVEBU_COMPHY_TRAINING0_P2P_HOLD;676 writel(val, priv->base + MVEBU_COMPHY_TRAINING0(lane->id));677 678 val = readl(priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));679 val &= ~MVEBU_COMPHY_TX_PRESET_INDEX(0xf);680 val |= MVEBU_COMPHY_TX_PRESET_INDEX(0x2); /* preset coeff */681 writel(val, priv->base + MVEBU_COMPHY_TX_PRESET(lane->id));682 683 val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));684 val &= ~MVEBU_COMPHY_FRAME_DETECT3_LOST_TIMEOUT_EN;685 writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT3(lane->id));686 687 val = readl(priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));688 val |= MVEBU_COMPHY_TX_TRAIN_PRESET_16B_AUTO_EN |689 MVEBU_COMPHY_TX_TRAIN_PRESET_PRBS11;690 writel(val, priv->base + MVEBU_COMPHY_TX_TRAIN_PRESET(lane->id));691 692 val = readl(priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));693 val &= ~MVEBU_COMPHY_FRAME_DETECT0_PATN(0x1ff);694 val |= MVEBU_COMPHY_FRAME_DETECT0_PATN(0x88);695 writel(val, priv->base + MVEBU_COMPHY_FRAME_DETECT0(lane->id));696 697 val = readl(priv->base + MVEBU_COMPHY_DME(lane->id));698 val |= MVEBU_COMPHY_DME_ETH_MODE;699 writel(val, priv->base + MVEBU_COMPHY_DME(lane->id));700 701 val = readl(priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));702 val |= MVEBU_COMPHY_VDD_CAL0_CONT_MODE;703 writel(val, priv->base + MVEBU_COMPHY_VDD_CAL0(lane->id));704 705 val = readl(priv->base + MVEBU_SP_CALIB(lane->id));706 val &= ~MVEBU_SP_CALIB_SAMPLER(0x3);707 val |= MVEBU_SP_CALIB_SAMPLER(0x3) |708 MVEBU_SP_CALIB_SAMPLER_EN;709 writel(val, priv->base + MVEBU_SP_CALIB(lane->id));710 val &= ~MVEBU_SP_CALIB_SAMPLER_EN;711 writel(val, priv->base + MVEBU_SP_CALIB(lane->id));712 713 /* External rx regulator */714 val = readl(priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));715 val &= ~MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1f);716 val |= MVEBU_COMPHY_EXT_SELV_RX_SAMPL(0x1a);717 writel(val, priv->base + MVEBU_COMPHY_EXT_SELV(lane->id));718 719 return mvebu_comphy_init_plls(lane);720}721 722static int mvebu_comphy_power_on_legacy(struct phy *phy)723{724 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);725 struct mvebu_comphy_priv *priv = lane->priv;726 int ret, mux;727 u32 val;728 729 mux = mvebu_comphy_get_mux(lane->id, lane->port,730 lane->mode, lane->submode);731 if (mux < 0)732 return -ENOTSUPP;733 734 regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);735 val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));736 regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);737 738 regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);739 val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));740 val |= mux << MVEBU_COMPHY_SELECTOR_PHY(lane->id);741 regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);742 743 switch (lane->submode) {744 case PHY_INTERFACE_MODE_SGMII:745 case PHY_INTERFACE_MODE_2500BASEX:746 ret = mvebu_comphy_set_mode_sgmii(phy);747 break;748 case PHY_INTERFACE_MODE_RXAUI:749 ret = mvebu_comphy_set_mode_rxaui(phy);750 break;751 case PHY_INTERFACE_MODE_10GBASER:752 ret = mvebu_comphy_set_mode_10gbaser(phy);753 break;754 default:755 return -ENOTSUPP;756 }757 758 /* digital reset */759 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));760 val |= MVEBU_COMPHY_SERDES_CFG1_RF_RESET;761 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));762 763 return ret;764}765 766static int mvebu_comphy_power_on(struct phy *phy)767{768 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);769 struct mvebu_comphy_priv *priv = lane->priv;770 int fw_mode, fw_speed;771 u32 fw_param = 0;772 int ret;773 774 fw_mode = mvebu_comphy_get_fw_mode(lane->id, lane->port,775 lane->mode, lane->submode);776 if (fw_mode < 0)777 goto try_legacy;778 779 /* Try SMC flow first */780 switch (lane->mode) {781 case PHY_MODE_ETHERNET:782 switch (lane->submode) {783 case PHY_INTERFACE_MODE_RXAUI:784 dev_dbg(priv->dev, "set lane %d to RXAUI mode\n",785 lane->id);786 fw_speed = 0;787 break;788 case PHY_INTERFACE_MODE_SGMII:789 dev_dbg(priv->dev, "set lane %d to 1000BASE-X mode\n",790 lane->id);791 fw_speed = COMPHY_FW_SPEED_1250;792 break;793 case PHY_INTERFACE_MODE_2500BASEX:794 dev_dbg(priv->dev, "set lane %d to 2500BASE-X mode\n",795 lane->id);796 fw_speed = COMPHY_FW_SPEED_3125;797 break;798 case PHY_INTERFACE_MODE_5GBASER:799 dev_dbg(priv->dev, "set lane %d to 5GBASE-R mode\n",800 lane->id);801 fw_speed = COMPHY_FW_SPEED_515625;802 break;803 case PHY_INTERFACE_MODE_10GBASER:804 dev_dbg(priv->dev, "set lane %d to 10GBASE-R mode\n",805 lane->id);806 fw_speed = COMPHY_FW_SPEED_103125;807 break;808 default:809 dev_err(priv->dev, "unsupported Ethernet mode (%d)\n",810 lane->submode);811 return -ENOTSUPP;812 }813 fw_param = COMPHY_FW_PARAM_ETH(fw_mode, lane->port, fw_speed);814 break;815 case PHY_MODE_USB_HOST_SS:816 case PHY_MODE_USB_DEVICE_SS:817 dev_dbg(priv->dev, "set lane %d to USB3 mode\n", lane->id);818 fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);819 break;820 case PHY_MODE_SATA:821 dev_dbg(priv->dev, "set lane %d to SATA mode\n", lane->id);822 fw_param = COMPHY_FW_PARAM(fw_mode, lane->port);823 break;824 case PHY_MODE_PCIE:825 dev_dbg(priv->dev, "set lane %d to PCIe mode (x%d)\n", lane->id,826 lane->submode);827 fw_param = COMPHY_FW_PARAM_PCIE(fw_mode, lane->port,828 lane->submode);829 break;830 default:831 dev_err(priv->dev, "unsupported PHY mode (%d)\n", lane->mode);832 return -ENOTSUPP;833 }834 835 ret = mvebu_comphy_smc(COMPHY_SIP_POWER_ON, priv->cp_phys, lane->id,836 fw_param);837 if (!ret)838 return ret;839 840 if (ret == -EOPNOTSUPP)841 dev_err(priv->dev,842 "unsupported SMC call, try updating your firmware\n");843 844 dev_warn(priv->dev,845 "Firmware could not configure PHY %d with mode %d (ret: %d), trying legacy method\n",846 lane->id, lane->mode, ret);847 848try_legacy:849 /* Fallback to Linux's implementation */850 return mvebu_comphy_power_on_legacy(phy);851}852 853static int mvebu_comphy_set_mode(struct phy *phy,854 enum phy_mode mode, int submode)855{856 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);857 858 if (submode == PHY_INTERFACE_MODE_1000BASEX)859 submode = PHY_INTERFACE_MODE_SGMII;860 861 if (mvebu_comphy_get_fw_mode(lane->id, lane->port, mode, submode) < 0)862 return -EINVAL;863 864 lane->mode = mode;865 lane->submode = submode;866 867 /* PCIe submode represents the width */868 if (mode == PHY_MODE_PCIE && !lane->submode)869 lane->submode = 1;870 871 return 0;872}873 874static int mvebu_comphy_power_off_legacy(struct phy *phy)875{876 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);877 struct mvebu_comphy_priv *priv = lane->priv;878 u32 val;879 880 val = readl(priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));881 val &= ~(MVEBU_COMPHY_SERDES_CFG1_RESET |882 MVEBU_COMPHY_SERDES_CFG1_CORE_RESET |883 MVEBU_COMPHY_SERDES_CFG1_RF_RESET);884 writel(val, priv->base + MVEBU_COMPHY_SERDES_CFG1(lane->id));885 886 regmap_read(priv->regmap, MVEBU_COMPHY_SELECTOR, &val);887 val &= ~(0xf << MVEBU_COMPHY_SELECTOR_PHY(lane->id));888 regmap_write(priv->regmap, MVEBU_COMPHY_SELECTOR, val);889 890 regmap_read(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, &val);891 val &= ~(0xf << MVEBU_COMPHY_PIPE_SELECTOR_PIPE(lane->id));892 regmap_write(priv->regmap, MVEBU_COMPHY_PIPE_SELECTOR, val);893 894 return 0;895}896 897static int mvebu_comphy_power_off(struct phy *phy)898{899 struct mvebu_comphy_lane *lane = phy_get_drvdata(phy);900 struct mvebu_comphy_priv *priv = lane->priv;901 int ret;902 903 ret = mvebu_comphy_smc(COMPHY_SIP_POWER_OFF, priv->cp_phys,904 lane->id, 0);905 if (!ret)906 return ret;907 908 /* Fallback to Linux's implementation */909 return mvebu_comphy_power_off_legacy(phy);910}911 912static const struct phy_ops mvebu_comphy_ops = {913 .power_on = mvebu_comphy_power_on,914 .power_off = mvebu_comphy_power_off,915 .set_mode = mvebu_comphy_set_mode,916 .owner = THIS_MODULE,917};918 919static struct phy *mvebu_comphy_xlate(struct device *dev,920 const struct of_phandle_args *args)921{922 struct mvebu_comphy_lane *lane;923 struct phy *phy;924 925 if (WARN_ON(args->args[0] >= MVEBU_COMPHY_PORTS))926 return ERR_PTR(-EINVAL);927 928 phy = of_phy_simple_xlate(dev, args);929 if (IS_ERR(phy))930 return phy;931 932 lane = phy_get_drvdata(phy);933 lane->port = args->args[0];934 935 return phy;936}937 938static int mvebu_comphy_init_clks(struct mvebu_comphy_priv *priv)939{940 int ret;941 942 priv->mg_domain_clk = devm_clk_get(priv->dev, "mg_clk");943 if (IS_ERR(priv->mg_domain_clk))944 return PTR_ERR(priv->mg_domain_clk);945 946 ret = clk_prepare_enable(priv->mg_domain_clk);947 if (ret < 0)948 return ret;949 950 priv->mg_core_clk = devm_clk_get(priv->dev, "mg_core_clk");951 if (IS_ERR(priv->mg_core_clk)) {952 ret = PTR_ERR(priv->mg_core_clk);953 goto dis_mg_domain_clk;954 }955 956 ret = clk_prepare_enable(priv->mg_core_clk);957 if (ret < 0)958 goto dis_mg_domain_clk;959 960 priv->axi_clk = devm_clk_get(priv->dev, "axi_clk");961 if (IS_ERR(priv->axi_clk)) {962 ret = PTR_ERR(priv->axi_clk);963 goto dis_mg_core_clk;964 }965 966 ret = clk_prepare_enable(priv->axi_clk);967 if (ret < 0)968 goto dis_mg_core_clk;969 970 return 0;971 972dis_mg_core_clk:973 clk_disable_unprepare(priv->mg_core_clk);974 975dis_mg_domain_clk:976 clk_disable_unprepare(priv->mg_domain_clk);977 978 priv->mg_domain_clk = NULL;979 priv->mg_core_clk = NULL;980 priv->axi_clk = NULL;981 982 return ret;983};984 985static void mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv *priv)986{987 if (priv->axi_clk)988 clk_disable_unprepare(priv->axi_clk);989 990 if (priv->mg_core_clk)991 clk_disable_unprepare(priv->mg_core_clk);992 993 if (priv->mg_domain_clk)994 clk_disable_unprepare(priv->mg_domain_clk);995}996 997static int mvebu_comphy_probe(struct platform_device *pdev)998{999 struct mvebu_comphy_priv *priv;1000 struct phy_provider *provider;1001 struct device_node *child;1002 struct resource *res;1003 int ret;1004 1005 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);1006 if (!priv)1007 return -ENOMEM;1008 1009 priv->dev = &pdev->dev;1010 priv->regmap =1011 syscon_regmap_lookup_by_phandle(pdev->dev.of_node,1012 "marvell,system-controller");1013 if (IS_ERR(priv->regmap))1014 return PTR_ERR(priv->regmap);1015 priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);1016 if (IS_ERR(priv->base))1017 return PTR_ERR(priv->base);1018 1019 /*1020 * Ignore error if clocks have not been initialized properly for DT1021 * compatibility reasons.1022 */1023 ret = mvebu_comphy_init_clks(priv);1024 if (ret) {1025 if (ret == -EPROBE_DEFER)1026 return ret;1027 dev_warn(&pdev->dev, "cannot initialize clocks\n");1028 }1029 1030 /*1031 * Hack to retrieve a physical offset relative to this CP that will be1032 * given to the firmware1033 */1034 priv->cp_phys = res->start;1035 1036 for_each_available_child_of_node(pdev->dev.of_node, child) {1037 struct mvebu_comphy_lane *lane;1038 struct phy *phy;1039 u32 val;1040 1041 ret = of_property_read_u32(child, "reg", &val);1042 if (ret < 0) {1043 dev_err(&pdev->dev, "missing 'reg' property (%d)\n",1044 ret);1045 continue;1046 }1047 1048 if (val >= MVEBU_COMPHY_LANES) {1049 dev_err(&pdev->dev, "invalid 'reg' property\n");1050 continue;1051 }1052 1053 lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);1054 if (!lane) {1055 of_node_put(child);1056 ret = -ENOMEM;1057 goto disable_clks;1058 }1059 1060 phy = devm_phy_create(&pdev->dev, child, &mvebu_comphy_ops);1061 if (IS_ERR(phy)) {1062 of_node_put(child);1063 ret = PTR_ERR(phy);1064 goto disable_clks;1065 }1066 1067 lane->priv = priv;1068 lane->mode = PHY_MODE_INVALID;1069 lane->submode = PHY_INTERFACE_MODE_NA;1070 lane->id = val;1071 lane->port = -1;1072 phy_set_drvdata(phy, lane);1073 1074 /*1075 * All modes are supported in this driver so we could call1076 * mvebu_comphy_power_off(phy) here to avoid relying on the1077 * bootloader/firmware configuration, but for compatibility1078 * reasons we cannot de-configure the COMPHY without being sure1079 * that the firmware is up-to-date and fully-featured.1080 */1081 }1082 1083 dev_set_drvdata(&pdev->dev, priv);1084 provider = devm_of_phy_provider_register(&pdev->dev,1085 mvebu_comphy_xlate);1086 1087 return PTR_ERR_OR_ZERO(provider);1088 1089disable_clks:1090 mvebu_comphy_disable_unprepare_clks(priv);1091 1092 return ret;1093}1094 1095static const struct of_device_id mvebu_comphy_of_match_table[] = {1096 { .compatible = "marvell,comphy-cp110" },1097 { },1098};1099MODULE_DEVICE_TABLE(of, mvebu_comphy_of_match_table);1100 1101static struct platform_driver mvebu_comphy_driver = {1102 .probe = mvebu_comphy_probe,1103 .driver = {1104 .name = "mvebu-comphy",1105 .of_match_table = mvebu_comphy_of_match_table,1106 },1107};1108module_platform_driver(mvebu_comphy_driver);1109 1110MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");1111MODULE_DESCRIPTION("Common PHY driver for mvebu SoCs");1112MODULE_LICENSE("GPL v2");1113