1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2009-2016 Cavium, Inc.
6 #include <linux/of_address.h>
7 #include <linux/of_mdio.h>
8 #include <linux/module.h>
10 #include <linux/phy.h>
12 #include <linux/acpi.h>
13 #include <linux/pci.h>
15 #include "mdio-cavium.h"
17 struct thunder_mdiobus_nexus
{
19 struct cavium_mdiobus
*buses
[4];
22 static int thunder_mdiobus_pci_probe(struct pci_dev
*pdev
,
23 const struct pci_device_id
*ent
)
25 struct device_node
*node
;
26 struct fwnode_handle
*fwn
;
27 struct thunder_mdiobus_nexus
*nexus
;
31 nexus
= devm_kzalloc(&pdev
->dev
, sizeof(*nexus
), GFP_KERNEL
);
35 pci_set_drvdata(pdev
, nexus
);
37 err
= pcim_enable_device(pdev
);
39 dev_err(&pdev
->dev
, "Failed to enable PCI device\n");
40 pci_set_drvdata(pdev
, NULL
);
44 err
= pci_request_regions(pdev
, KBUILD_MODNAME
);
46 dev_err(&pdev
->dev
, "pci_request_regions failed\n");
47 goto err_disable_device
;
50 nexus
->bar0
= pcim_iomap(pdev
, 0, pci_resource_len(pdev
, 0));
53 goto err_release_regions
;
57 device_for_each_child_node(&pdev
->dev
, fwn
) {
59 struct mii_bus
*mii_bus
;
60 struct cavium_mdiobus
*bus
;
61 union cvmx_smix_en smi_en
;
63 /* If it is not an OF node we cannot handle it yet, so
66 node
= to_of_node(fwn
);
70 err
= of_address_to_resource(node
, 0, &r
);
73 "Couldn't translate address for \"%pOFn\"\n",
78 mii_bus
= devm_mdiobus_alloc_size(&pdev
->dev
, sizeof(*bus
));
82 bus
->mii_bus
= mii_bus
;
84 nexus
->buses
[i
] = bus
;
87 bus
->register_base
= (u64
)nexus
->bar0
+
88 r
.start
- pci_resource_start(pdev
, 0);
92 oct_mdio_writeq(smi_en
.u64
, bus
->register_base
+ SMI_EN
);
93 bus
->mii_bus
->name
= KBUILD_MODNAME
;
94 snprintf(bus
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%llx", r
.start
);
95 bus
->mii_bus
->parent
= &pdev
->dev
;
96 bus
->mii_bus
->read
= cavium_mdiobus_read
;
97 bus
->mii_bus
->write
= cavium_mdiobus_write
;
99 err
= of_mdiobus_register(bus
->mii_bus
, node
);
101 dev_err(&pdev
->dev
, "of_mdiobus_register failed\n");
103 dev_info(&pdev
->dev
, "Added bus at %llx\n", r
.start
);
104 if (i
>= ARRAY_SIZE(nexus
->buses
))
110 pci_release_regions(pdev
);
113 pci_set_drvdata(pdev
, NULL
);
117 static void thunder_mdiobus_pci_remove(struct pci_dev
*pdev
)
120 struct thunder_mdiobus_nexus
*nexus
= pci_get_drvdata(pdev
);
122 for (i
= 0; i
< ARRAY_SIZE(nexus
->buses
); i
++) {
123 struct cavium_mdiobus
*bus
= nexus
->buses
[i
];
128 mdiobus_unregister(bus
->mii_bus
);
129 mdiobus_free(bus
->mii_bus
);
130 oct_mdio_writeq(0, bus
->register_base
+ SMI_EN
);
132 pci_release_regions(pdev
);
133 pci_set_drvdata(pdev
, NULL
);
136 static const struct pci_device_id thunder_mdiobus_id_table
[] = {
137 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xa02b) },
138 { 0, } /* End of table. */
140 MODULE_DEVICE_TABLE(pci
, thunder_mdiobus_id_table
);
142 static struct pci_driver thunder_mdiobus_driver
= {
143 .name
= KBUILD_MODNAME
,
144 .id_table
= thunder_mdiobus_id_table
,
145 .probe
= thunder_mdiobus_pci_probe
,
146 .remove
= thunder_mdiobus_pci_remove
,
149 module_pci_driver(thunder_mdiobus_driver
);
151 MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver");
152 MODULE_LICENSE("GPL v2");