^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2009-2016 Cavium, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/of_mdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "mdio-cavium.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct thunder_mdiobus_nexus {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) void __iomem *bar0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct cavium_mdiobus *buses[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) const struct pci_device_id *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct fwnode_handle *fwn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct thunder_mdiobus_nexus *nexus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) nexus = devm_kzalloc(&pdev->dev, sizeof(*nexus), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (!nexus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) pci_set_drvdata(pdev, nexus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) err = pcim_enable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) dev_err(&pdev->dev, "Failed to enable PCI device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) pci_set_drvdata(pdev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) err = pci_request_regions(pdev, KBUILD_MODNAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) dev_err(&pdev->dev, "pci_request_regions failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) goto err_disable_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) nexus->bar0 = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!nexus->bar0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) goto err_release_regions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) device_for_each_child_node(&pdev->dev, fwn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct resource r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct mii_bus *mii_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct cavium_mdiobus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) union cvmx_smix_en smi_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* If it is not an OF node we cannot handle it yet, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * exit the loop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) node = to_of_node(fwn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) err = of_address_to_resource(node, 0, &r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "Couldn't translate address for \"%pOFn\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!mii_bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bus = mii_bus->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) bus->mii_bus = mii_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) nexus->buses[i] = bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) bus->register_base = nexus->bar0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) r.start - pci_resource_start(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) smi_en.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) smi_en.s.en = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) bus->mii_bus->name = KBUILD_MODNAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) bus->mii_bus->parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) bus->mii_bus->read = cavium_mdiobus_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) bus->mii_bus->write = cavium_mdiobus_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) err = of_mdiobus_register(bus->mii_bus, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) dev_err(&pdev->dev, "of_mdiobus_register failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) dev_info(&pdev->dev, "Added bus at %llx\n", r.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (i >= ARRAY_SIZE(nexus->buses))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) err_release_regions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) pci_release_regions(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) err_disable_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) pci_set_drvdata(pdev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void thunder_mdiobus_pci_remove(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct thunder_mdiobus_nexus *nexus = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) for (i = 0; i < ARRAY_SIZE(nexus->buses); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct cavium_mdiobus *bus = nexus->buses[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) mdiobus_unregister(bus->mii_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) oct_mdio_writeq(0, bus->register_base + SMI_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) pci_release_regions(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) pci_set_drvdata(pdev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static const struct pci_device_id thunder_mdiobus_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa02b) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) { 0, } /* End of table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) MODULE_DEVICE_TABLE(pci, thunder_mdiobus_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static struct pci_driver thunder_mdiobus_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .name = KBUILD_MODNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .id_table = thunder_mdiobus_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .probe = thunder_mdiobus_pci_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .remove = thunder_mdiobus_pci_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) module_pci_driver(thunder_mdiobus_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) MODULE_LICENSE("GPL v2");