1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Applied Micro X-Gene SoC MDIO Driver 3 * 4 * Copyright (c) 2016, Applied Micro Circuits Corporation 5 * Author: Iyappan Subramanian <isubramanian@apm.com> 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/clk.h> 10 #include <linux/device.h> 11 #include <linux/efi.h> 12 #include <linux/if_vlan.h> 13 #include <linux/io.h> 14 #include <linux/mdio/mdio-xgene.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/of_mdio.h> 18 #include <linux/of_net.h> 19 #include <linux/phy.h> 20 #include <linux/platform_device.h> 21 #include <linux/prefetch.h> 22 #include <linux/property.h> 23 #include <net/ip.h> 24 25 u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr) 26 { 27 void __iomem *addr, *rd, *cmd, *cmd_done; 28 u32 done, rd_data = BUSY_MASK; 29 u8 wait = 10; 30 31 addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; 32 rd = pdata->mac_csr_addr + MAC_READ_REG_OFFSET; 33 cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; 34 cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; 35 36 spin_lock(&pdata->mac_lock); 37 iowrite32(rd_addr, addr); 38 iowrite32(XGENE_ENET_RD_CMD, cmd); 39 40 while (!(done = ioread32(cmd_done)) && wait--) 41 udelay(1); 42 43 if (done) 44 rd_data = ioread32(rd); 45 46 iowrite32(0, cmd); 47 spin_unlock(&pdata->mac_lock); 48 49 return rd_data; 50 } 51 EXPORT_SYMBOL(xgene_mdio_rd_mac); 52 53 void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data) 54 { 55 void __iomem *addr, *wr, *cmd, *cmd_done; 56 u8 wait = 10; 57 u32 done; 58 59 addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET; 60 wr = pdata->mac_csr_addr + MAC_WRITE_REG_OFFSET; 61 cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET; 62 cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET; 63 64 spin_lock(&pdata->mac_lock); 65 iowrite32(wr_addr, addr); 66 iowrite32(data, wr); 67 iowrite32(XGENE_ENET_WR_CMD, cmd); 68 69 while (!(done = ioread32(cmd_done)) && wait--) 70 udelay(1); 71 72 if (!done) 73 pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); 74 75 iowrite32(0, cmd); 76 spin_unlock(&pdata->mac_lock); 77 } 78 EXPORT_SYMBOL(xgene_mdio_wr_mac); 79 80 int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) 81 { 82 struct xgene_mdio_pdata *pdata = bus->priv; 83 u32 data, done; 84 u8 wait = 10; 85 86 data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); 87 xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, data); 88 xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); 89 do { 90 usleep_range(5, 10); 91 done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); 92 } while ((done & BUSY_MASK) && wait--); 93 94 if (done & BUSY_MASK) { 95 dev_err(&bus->dev, "MII_MGMT read failed\n"); 96 return -EBUSY; 97 } 98 99 data = xgene_mdio_rd_mac(pdata, MII_MGMT_STATUS_ADDR); 100 xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); 101 102 return data; 103 } 104 EXPORT_SYMBOL(xgene_mdio_rgmii_read); 105 106 int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) 107 { 108 struct xgene_mdio_pdata *pdata = bus->priv; 109 u32 val, done; 110 u8 wait = 10; 111 112 val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); 113 xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, val); 114 115 xgene_mdio_wr_mac(pdata, MII_MGMT_CONTROL_ADDR, data); 116 do { 117 usleep_range(5, 10); 118 done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR); 119 } while ((done & BUSY_MASK) && wait--); 120 121 if (done & BUSY_MASK) { 122 dev_err(&bus->dev, "MII_MGMT write failed\n"); 123 return -EBUSY; 124 } 125 126 return 0; 127 } 128 EXPORT_SYMBOL(xgene_mdio_rgmii_write); 129 130 static u32 xgene_menet_rd_diag_csr(struct xgene_mdio_pdata *pdata, u32 offset) 131 { 132 return ioread32(pdata->diag_csr_addr + offset); 133 } 134 135 static void xgene_menet_wr_diag_csr(struct xgene_mdio_pdata *pdata, 136 u32 offset, u32 val) 137 { 138 iowrite32(val, pdata->diag_csr_addr + offset); 139 } 140 141 static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) 142 { 143 u32 data; 144 u8 wait = 10; 145 146 xgene_menet_wr_diag_csr(pdata, MENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); 147 do { 148 usleep_range(100, 110); 149 data = xgene_menet_rd_diag_csr(pdata, MENET_BLOCK_MEM_RDY_ADDR); 150 } while ((data != 0xffffffff) && wait--); 151 152 if (data != 0xffffffff) { 153 dev_err(pdata->dev, "Failed to release memory from shutdown\n"); 154 return -ENODEV; 155 } 156 157 return 0; 158 } 159 160 static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) 161 { 162 xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET); 163 xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0); 164 } 165 166 static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) 167 { 168 int ret; 169 170 if (pdata->dev->of_node) { 171 clk_prepare_enable(pdata->clk); 172 udelay(5); 173 clk_disable_unprepare(pdata->clk); 174 udelay(5); 175 clk_prepare_enable(pdata->clk); 176 udelay(5); 177 } else { 178 #ifdef CONFIG_ACPI 179 acpi_evaluate_object(ACPI_HANDLE(pdata->dev), 180 "_RST", NULL, NULL); 181 #endif 182 } 183 184 ret = xgene_enet_ecc_init(pdata); 185 if (ret) { 186 if (pdata->dev->of_node) 187 clk_disable_unprepare(pdata->clk); 188 return ret; 189 } 190 xgene_gmac_reset(pdata); 191 192 return 0; 193 } 194 195 static void xgene_enet_rd_mdio_csr(void __iomem *base_addr, 196 u32 offset, u32 *val) 197 { 198 void __iomem *addr = base_addr + offset; 199 200 *val = ioread32(addr); 201 } 202 203 static void xgene_enet_wr_mdio_csr(void __iomem *base_addr, 204 u32 offset, u32 val) 205 { 206 void __iomem *addr = base_addr + offset; 207 208 iowrite32(val, addr); 209 } 210 211 static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id, 212 int reg, u16 data) 213 { 214 void __iomem *addr = (void __iomem *)bus->priv; 215 int timeout = 100; 216 u32 status, val; 217 218 val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) | 219 SET_VAL(HSTMIIMWRDAT, data); 220 xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); 221 222 val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE); 223 xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); 224 225 do { 226 usleep_range(5, 10); 227 xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); 228 } while ((status & BUSY_MASK) && timeout--); 229 230 xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); 231 232 return 0; 233 } 234 235 static int xgene_xfi_mdio_read(struct mii_bus *bus, int phy_id, int reg) 236 { 237 void __iomem *addr = (void __iomem *)bus->priv; 238 u32 data, status, val; 239 int timeout = 100; 240 241 val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg); 242 xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); 243 244 val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_READ); 245 xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); 246 247 do { 248 usleep_range(5, 10); 249 xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); 250 } while ((status & BUSY_MASK) && timeout--); 251 252 if (status & BUSY_MASK) { 253 pr_err("XGENET_MII_MGMT write failed\n"); 254 return -EBUSY; 255 } 256 257 xgene_enet_rd_mdio_csr(addr, MIIMRD_FIELD_ADDR, &data); 258 xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); 259 260 return data; 261 } 262 263 struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr) 264 { 265 struct phy_device *phy_dev; 266 267 phy_dev = get_phy_device(bus, phy_addr, false); 268 if (!phy_dev || IS_ERR(phy_dev)) 269 return NULL; 270 271 if (phy_device_register(phy_dev)) 272 phy_device_free(phy_dev); 273 274 return phy_dev; 275 } 276 EXPORT_SYMBOL(xgene_enet_phy_register); 277 278 #ifdef CONFIG_ACPI 279 static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl, 280 void *context, void **ret) 281 { 282 struct mii_bus *mdio = context; 283 struct acpi_device *adev; 284 struct phy_device *phy_dev; 285 const union acpi_object *obj; 286 u32 phy_addr; 287 288 adev = acpi_fetch_acpi_dev(handle); 289 if (!adev) 290 return AE_OK; 291 292 if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj)) 293 return AE_OK; 294 phy_addr = obj->integer.value; 295 296 phy_dev = xgene_enet_phy_register(mdio, phy_addr); 297 adev->driver_data = phy_dev; 298 299 return AE_OK; 300 } 301 #endif 302 303 static const struct of_device_id xgene_mdio_of_match[] = { 304 { 305 .compatible = "apm,xgene-mdio-rgmii", 306 .data = (void *)XGENE_MDIO_RGMII 307 }, 308 { 309 .compatible = "apm,xgene-mdio-xfi", 310 .data = (void *)XGENE_MDIO_XFI 311 }, 312 {}, 313 }; 314 MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); 315 316 #ifdef CONFIG_ACPI 317 static const struct acpi_device_id xgene_mdio_acpi_match[] = { 318 { "APMC0D65", XGENE_MDIO_RGMII }, 319 { "APMC0D66", XGENE_MDIO_XFI }, 320 { } 321 }; 322 323 MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); 324 #endif 325 326 327 static int xgene_mdio_probe(struct platform_device *pdev) 328 { 329 struct device *dev = &pdev->dev; 330 struct mii_bus *mdio_bus; 331 struct xgene_mdio_pdata *pdata; 332 void __iomem *csr_base; 333 int mdio_id = 0, ret = 0; 334 335 mdio_id = (uintptr_t)device_get_match_data(&pdev->dev); 336 if (!mdio_id) 337 return -ENODEV; 338 339 pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL); 340 if (!pdata) 341 return -ENOMEM; 342 pdata->mdio_id = mdio_id; 343 pdata->dev = dev; 344 345 csr_base = devm_platform_ioremap_resource(pdev, 0); 346 if (IS_ERR(csr_base)) 347 return PTR_ERR(csr_base); 348 pdata->mac_csr_addr = csr_base; 349 pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; 350 pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; 351 352 if (mdio_id == XGENE_MDIO_RGMII) 353 spin_lock_init(&pdata->mac_lock); 354 355 if (dev->of_node) { 356 pdata->clk = devm_clk_get(dev, NULL); 357 if (IS_ERR(pdata->clk)) { 358 dev_err(dev, "Unable to retrieve clk\n"); 359 return PTR_ERR(pdata->clk); 360 } 361 } 362 363 ret = xgene_mdio_reset(pdata); 364 if (ret) 365 return ret; 366 367 mdio_bus = mdiobus_alloc(); 368 if (!mdio_bus) { 369 ret = -ENOMEM; 370 goto out_clk; 371 } 372 373 mdio_bus->name = "APM X-Gene MDIO bus"; 374 375 if (mdio_id == XGENE_MDIO_RGMII) { 376 mdio_bus->read = xgene_mdio_rgmii_read; 377 mdio_bus->write = xgene_mdio_rgmii_write; 378 mdio_bus->priv = (void __force *)pdata; 379 snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", 380 "xgene-mii-rgmii"); 381 } else { 382 mdio_bus->read = xgene_xfi_mdio_read; 383 mdio_bus->write = xgene_xfi_mdio_write; 384 mdio_bus->priv = (void __force *)pdata->mdio_csr_addr; 385 snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", 386 "xgene-mii-xfi"); 387 } 388 389 mdio_bus->parent = dev; 390 platform_set_drvdata(pdev, pdata); 391 392 if (dev->of_node) { 393 ret = of_mdiobus_register(mdio_bus, dev->of_node); 394 } else { 395 #ifdef CONFIG_ACPI 396 /* Mask out all PHYs from auto probing. */ 397 mdio_bus->phy_mask = ~0; 398 ret = mdiobus_register(mdio_bus); 399 if (ret) 400 goto out_mdiobus; 401 402 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1, 403 acpi_register_phy, NULL, mdio_bus, NULL); 404 #endif 405 } 406 407 if (ret) 408 goto out_mdiobus; 409 410 pdata->mdio_bus = mdio_bus; 411 412 return 0; 413 414 out_mdiobus: 415 mdiobus_free(mdio_bus); 416 417 out_clk: 418 if (dev->of_node) 419 clk_disable_unprepare(pdata->clk); 420 421 return ret; 422 } 423 424 static void xgene_mdio_remove(struct platform_device *pdev) 425 { 426 struct xgene_mdio_pdata *pdata = platform_get_drvdata(pdev); 427 struct mii_bus *mdio_bus = pdata->mdio_bus; 428 struct device *dev = &pdev->dev; 429 430 mdiobus_unregister(mdio_bus); 431 mdiobus_free(mdio_bus); 432 433 if (dev->of_node) 434 clk_disable_unprepare(pdata->clk); 435 } 436 437 static struct platform_driver xgene_mdio_driver = { 438 .driver = { 439 .name = "xgene-mdio", 440 .of_match_table = xgene_mdio_of_match, 441 .acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match), 442 }, 443 .probe = xgene_mdio_probe, 444 .remove_new = xgene_mdio_remove, 445 }; 446 447 module_platform_driver(xgene_mdio_driver); 448 449 MODULE_DESCRIPTION("APM X-Gene SoC MDIO driver"); 450 MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); 451 MODULE_LICENSE("GPL"); 452