1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 Marvell 4 * 5 * Authors: 6 * Evan Wang <xswang@marvell.com> 7 * Miquèl Raynal <miquel.raynal@bootlin.com> 8 * 9 * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart. 10 * SMC call initial support done by Grzegorz Jaszczyk. 11 */ 12 13 #include <linux/arm-smccc.h> 14 #include <linux/io.h> 15 #include <linux/iopoll.h> 16 #include <linux/mfd/syscon.h> 17 #include <linux/module.h> 18 #include <linux/phy.h> 19 #include <linux/phy/phy.h> 20 #include <linux/platform_device.h> 21 22 #define MVEBU_A3700_COMPHY_LANES 3 23 #define MVEBU_A3700_COMPHY_PORTS 2 24 25 /* COMPHY Fast SMC function identifiers */ 26 #define COMPHY_SIP_POWER_ON 0x82000001 27 #define COMPHY_SIP_POWER_OFF 0x82000002 28 #define COMPHY_SIP_PLL_LOCK 0x82000003 29 #define COMPHY_FW_NOT_SUPPORTED (-1) 30 31 #define COMPHY_FW_MODE_SATA 0x1 32 #define COMPHY_FW_MODE_SGMII 0x2 33 #define COMPHY_FW_MODE_HS_SGMII 0x3 34 #define COMPHY_FW_MODE_USB3H 0x4 35 #define COMPHY_FW_MODE_USB3D 0x5 36 #define COMPHY_FW_MODE_PCIE 0x6 37 #define COMPHY_FW_MODE_RXAUI 0x7 38 #define COMPHY_FW_MODE_XFI 0x8 39 #define COMPHY_FW_MODE_SFI 0x9 40 #define COMPHY_FW_MODE_USB3 0xa 41 42 #define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */ 43 #define COMPHY_FW_SPEED_2_5G 1 44 #define COMPHY_FW_SPEED_3_125G 2 /* SGMII 2.5G */ 45 #define COMPHY_FW_SPEED_5G 3 46 #define COMPHY_FW_SPEED_5_15625G 4 /* XFI 5G */ 47 #define COMPHY_FW_SPEED_6G 5 48 #define COMPHY_FW_SPEED_10_3125G 6 /* XFI 10G */ 49 #define COMPHY_FW_SPEED_MAX 0x3F 50 51 #define COMPHY_FW_MODE(mode) ((mode) << 12) 52 #define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ 53 ((idx) << 8) | \ 54 ((speed) << 2)) 55 #define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \ 56 ((width) << 18)) 57 58 struct mvebu_a3700_comphy_conf { 59 unsigned int lane; 60 enum phy_mode mode; 61 int submode; 62 unsigned int port; 63 u32 fw_mode; 64 }; 65 66 #define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \ 67 { \ 68 .lane = _lane, \ 69 .mode = _mode, \ 70 .submode = _smode, \ 71 .port = _port, \ 72 .fw_mode = _fw, \ 73 } 74 75 #define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \ 76 MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw) 77 78 #define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \ 79 MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw) 80 81 static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { 82 /* lane 0 */ 83 MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0, 84 COMPHY_FW_MODE_USB3H), 85 MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1, 86 COMPHY_FW_MODE_SGMII), 87 MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1, 88 COMPHY_FW_MODE_HS_SGMII), 89 /* lane 1 */ 90 MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0, 91 COMPHY_FW_MODE_PCIE), 92 MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0, 93 COMPHY_FW_MODE_SGMII), 94 MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0, 95 COMPHY_FW_MODE_HS_SGMII), 96 /* lane 2 */ 97 MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0, 98 COMPHY_FW_MODE_SATA), 99 MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0, 100 COMPHY_FW_MODE_USB3H), 101 }; 102 103 struct mvebu_a3700_comphy_lane { 104 struct device *dev; 105 unsigned int id; 106 enum phy_mode mode; 107 int submode; 108 int port; 109 }; 110 111 static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, 112 unsigned long mode) 113 { 114 struct arm_smccc_res res; 115 116 arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res); 117 118 return res.a0; 119 } 120 121 static int mvebu_a3700_comphy_get_fw_mode(int lane, int port, 122 enum phy_mode mode, 123 int submode) 124 { 125 int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes); 126 127 /* Unused PHY mux value is 0x0 */ 128 if (mode == PHY_MODE_INVALID) 129 return -EINVAL; 130 131 for (i = 0; i < n; i++) { 132 if (mvebu_a3700_comphy_modes[i].lane == lane && 133 mvebu_a3700_comphy_modes[i].port == port && 134 mvebu_a3700_comphy_modes[i].mode == mode && 135 mvebu_a3700_comphy_modes[i].submode == submode) 136 break; 137 } 138 139 if (i == n) 140 return -EINVAL; 141 142 return mvebu_a3700_comphy_modes[i].fw_mode; 143 } 144 145 static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode, 146 int submode) 147 { 148 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); 149 int fw_mode; 150 151 if (submode == PHY_INTERFACE_MODE_1000BASEX) 152 submode = PHY_INTERFACE_MODE_SGMII; 153 154 fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode, 155 submode); 156 if (fw_mode < 0) { 157 dev_err(lane->dev, "invalid COMPHY mode\n"); 158 return fw_mode; 159 } 160 161 /* Just remember the mode, ->power_on() will do the real setup */ 162 lane->mode = mode; 163 lane->submode = submode; 164 165 return 0; 166 } 167 168 static int mvebu_a3700_comphy_power_on(struct phy *phy) 169 { 170 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); 171 u32 fw_param; 172 int fw_mode; 173 int ret; 174 175 fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, 176 lane->mode, lane->submode); 177 if (fw_mode < 0) { 178 dev_err(lane->dev, "invalid COMPHY mode\n"); 179 return fw_mode; 180 } 181 182 switch (lane->mode) { 183 case PHY_MODE_USB_HOST_SS: 184 dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); 185 fw_param = COMPHY_FW_MODE(fw_mode); 186 break; 187 case PHY_MODE_SATA: 188 dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id); 189 fw_param = COMPHY_FW_MODE(fw_mode); 190 break; 191 case PHY_MODE_ETHERNET: 192 switch (lane->submode) { 193 case PHY_INTERFACE_MODE_SGMII: 194 dev_dbg(lane->dev, "set lane %d to SGMII mode\n", 195 lane->id); 196 fw_param = COMPHY_FW_NET(fw_mode, lane->port, 197 COMPHY_FW_SPEED_1_25G); 198 break; 199 case PHY_INTERFACE_MODE_2500BASEX: 200 dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n", 201 lane->id); 202 fw_param = COMPHY_FW_NET(fw_mode, lane->port, 203 COMPHY_FW_SPEED_3_125G); 204 break; 205 default: 206 dev_err(lane->dev, "unsupported PHY submode (%d)\n", 207 lane->submode); 208 return -ENOTSUPP; 209 } 210 break; 211 case PHY_MODE_PCIE: 212 dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); 213 fw_param = COMPHY_FW_PCIE(fw_mode, lane->port, 214 COMPHY_FW_SPEED_5G, 215 phy->attrs.bus_width); 216 break; 217 default: 218 dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode); 219 return -ENOTSUPP; 220 } 221 222 ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param); 223 if (ret == COMPHY_FW_NOT_SUPPORTED) 224 dev_err(lane->dev, 225 "unsupported SMC call, try updating your firmware\n"); 226 227 return ret; 228 } 229 230 static int mvebu_a3700_comphy_power_off(struct phy *phy) 231 { 232 struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); 233 234 return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0); 235 } 236 237 static const struct phy_ops mvebu_a3700_comphy_ops = { 238 .power_on = mvebu_a3700_comphy_power_on, 239 .power_off = mvebu_a3700_comphy_power_off, 240 .set_mode = mvebu_a3700_comphy_set_mode, 241 .owner = THIS_MODULE, 242 }; 243 244 static struct phy *mvebu_a3700_comphy_xlate(struct device *dev, 245 struct of_phandle_args *args) 246 { 247 struct mvebu_a3700_comphy_lane *lane; 248 struct phy *phy; 249 250 if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS)) 251 return ERR_PTR(-EINVAL); 252 253 phy = of_phy_simple_xlate(dev, args); 254 if (IS_ERR(phy)) 255 return phy; 256 257 lane = phy_get_drvdata(phy); 258 lane->port = args->args[0]; 259 260 return phy; 261 } 262 263 static int mvebu_a3700_comphy_probe(struct platform_device *pdev) 264 { 265 struct phy_provider *provider; 266 struct device_node *child; 267 268 for_each_available_child_of_node(pdev->dev.of_node, child) { 269 struct mvebu_a3700_comphy_lane *lane; 270 struct phy *phy; 271 int ret; 272 u32 lane_id; 273 274 ret = of_property_read_u32(child, "reg", &lane_id); 275 if (ret < 0) { 276 dev_err(&pdev->dev, "missing 'reg' property (%d)\n", 277 ret); 278 continue; 279 } 280 281 if (lane_id >= MVEBU_A3700_COMPHY_LANES) { 282 dev_err(&pdev->dev, "invalid 'reg' property\n"); 283 continue; 284 } 285 286 lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL); 287 if (!lane) { 288 of_node_put(child); 289 return -ENOMEM; 290 } 291 292 phy = devm_phy_create(&pdev->dev, child, 293 &mvebu_a3700_comphy_ops); 294 if (IS_ERR(phy)) { 295 of_node_put(child); 296 return PTR_ERR(phy); 297 } 298 299 lane->dev = &pdev->dev; 300 lane->mode = PHY_MODE_INVALID; 301 lane->submode = PHY_INTERFACE_MODE_NA; 302 lane->id = lane_id; 303 lane->port = -1; 304 phy_set_drvdata(phy, lane); 305 } 306 307 provider = devm_of_phy_provider_register(&pdev->dev, 308 mvebu_a3700_comphy_xlate); 309 return PTR_ERR_OR_ZERO(provider); 310 } 311 312 static const struct of_device_id mvebu_a3700_comphy_of_match_table[] = { 313 { .compatible = "marvell,comphy-a3700" }, 314 { }, 315 }; 316 MODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table); 317 318 static struct platform_driver mvebu_a3700_comphy_driver = { 319 .probe = mvebu_a3700_comphy_probe, 320 .driver = { 321 .name = "mvebu-a3700-comphy", 322 .of_match_table = mvebu_a3700_comphy_of_match_table, 323 }, 324 }; 325 module_platform_driver(mvebu_a3700_comphy_driver); 326 327 MODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>"); 328 MODULE_DESCRIPTION("Common PHY driver for A3700"); 329 MODULE_LICENSE("GPL v2"); 330