1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2009-2016 Cavium, Inc.
6 #include <linux/acpi.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_mdio.h>
12 #include <linux/pci.h>
13 #include <linux/phy.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 thunder_mdiobus_nexus
*nexus
;
30 nexus
= devm_kzalloc(&pdev
->dev
, sizeof(*nexus
), GFP_KERNEL
);
34 pci_set_drvdata(pdev
, nexus
);
36 err
= pcim_enable_device(pdev
);
38 dev_err(&pdev
->dev
, "Failed to enable PCI device\n");
39 pci_set_drvdata(pdev
, NULL
);
43 err
= pci_request_regions(pdev
, KBUILD_MODNAME
);
45 dev_err(&pdev
->dev
, "pci_request_regions failed\n");
46 goto err_disable_device
;
49 nexus
->bar0
= pcim_iomap(pdev
, 0, pci_resource_len(pdev
, 0));
52 goto err_release_regions
;
56 device_for_each_child_node_scoped(&pdev
->dev
, fwn
) {
58 struct mii_bus
*mii_bus
;
59 struct cavium_mdiobus
*bus
;
60 union cvmx_smix_en smi_en
;
62 /* If it is not an OF node we cannot handle it yet, so
65 node
= to_of_node(fwn
);
69 err
= of_address_to_resource(node
, 0, &r
);
72 "Couldn't translate address for \"%pOFn\"\n",
77 mii_bus
= devm_mdiobus_alloc_size(&pdev
->dev
, sizeof(*bus
));
81 bus
->mii_bus
= mii_bus
;
83 nexus
->buses
[i
] = bus
;
86 bus
->register_base
= nexus
->bar0
+
87 r
.start
- pci_resource_start(pdev
, 0);
91 oct_mdio_writeq(smi_en
.u64
, bus
->register_base
+ SMI_EN
);
92 bus
->mii_bus
->name
= KBUILD_MODNAME
;
93 snprintf(bus
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%llx", r
.start
);
94 bus
->mii_bus
->parent
= &pdev
->dev
;
95 bus
->mii_bus
->read
= cavium_mdiobus_read_c22
;
96 bus
->mii_bus
->write
= cavium_mdiobus_write_c22
;
97 bus
->mii_bus
->read_c45
= cavium_mdiobus_read_c45
;
98 bus
->mii_bus
->write_c45
= cavium_mdiobus_write_c45
;
100 err
= of_mdiobus_register(bus
->mii_bus
, node
);
102 dev_err(&pdev
->dev
, "of_mdiobus_register failed\n");
104 dev_info(&pdev
->dev
, "Added bus at %llx\n", r
.start
);
105 if (i
>= ARRAY_SIZE(nexus
->buses
))
111 pci_release_regions(pdev
);
114 pci_set_drvdata(pdev
, NULL
);
118 static void thunder_mdiobus_pci_remove(struct pci_dev
*pdev
)
121 struct thunder_mdiobus_nexus
*nexus
= pci_get_drvdata(pdev
);
123 for (i
= 0; i
< ARRAY_SIZE(nexus
->buses
); i
++) {
124 struct cavium_mdiobus
*bus
= nexus
->buses
[i
];
129 mdiobus_unregister(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");