2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2009-2016 Cavium, Inc.
9 #include <linux/of_address.h>
10 #include <linux/of_mdio.h>
11 #include <linux/module.h>
12 #include <linux/gfp.h>
13 #include <linux/phy.h>
15 #include <linux/acpi.h>
16 #include <linux/pci.h>
18 #include "mdio-cavium.h"
20 struct thunder_mdiobus_nexus
{
22 struct cavium_mdiobus
*buses
[4];
25 static int thunder_mdiobus_pci_probe(struct pci_dev
*pdev
,
26 const struct pci_device_id
*ent
)
28 struct device_node
*node
;
29 struct fwnode_handle
*fwn
;
30 struct thunder_mdiobus_nexus
*nexus
;
34 nexus
= devm_kzalloc(&pdev
->dev
, sizeof(*nexus
), GFP_KERNEL
);
38 pci_set_drvdata(pdev
, nexus
);
40 err
= pcim_enable_device(pdev
);
42 dev_err(&pdev
->dev
, "Failed to enable PCI device\n");
43 pci_set_drvdata(pdev
, NULL
);
47 err
= pci_request_regions(pdev
, KBUILD_MODNAME
);
49 dev_err(&pdev
->dev
, "pci_request_regions failed\n");
50 goto err_disable_device
;
53 nexus
->bar0
= pcim_iomap(pdev
, 0, pci_resource_len(pdev
, 0));
56 goto err_release_regions
;
60 device_for_each_child_node(&pdev
->dev
, fwn
) {
62 struct mii_bus
*mii_bus
;
63 struct cavium_mdiobus
*bus
;
64 union cvmx_smix_en smi_en
;
66 /* If it is not an OF node we cannot handle it yet, so
69 node
= to_of_node(fwn
);
73 err
= of_address_to_resource(node
, 0, &r
);
76 "Couldn't translate address for \"%s\"\n",
81 mii_bus
= devm_mdiobus_alloc_size(&pdev
->dev
, sizeof(*bus
));
85 bus
->mii_bus
= mii_bus
;
87 nexus
->buses
[i
] = bus
;
90 bus
->register_base
= (u64
)nexus
->bar0
+
91 r
.start
- pci_resource_start(pdev
, 0);
95 oct_mdio_writeq(smi_en
.u64
, bus
->register_base
+ SMI_EN
);
96 bus
->mii_bus
->name
= KBUILD_MODNAME
;
97 snprintf(bus
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%llx", r
.start
);
98 bus
->mii_bus
->parent
= &pdev
->dev
;
99 bus
->mii_bus
->read
= cavium_mdiobus_read
;
100 bus
->mii_bus
->write
= cavium_mdiobus_write
;
102 err
= of_mdiobus_register(bus
->mii_bus
, node
);
104 dev_err(&pdev
->dev
, "of_mdiobus_register failed\n");
106 dev_info(&pdev
->dev
, "Added bus at %llx\n", r
.start
);
107 if (i
>= ARRAY_SIZE(nexus
->buses
))
113 pci_release_regions(pdev
);
116 pci_set_drvdata(pdev
, NULL
);
120 static void thunder_mdiobus_pci_remove(struct pci_dev
*pdev
)
123 struct thunder_mdiobus_nexus
*nexus
= pci_get_drvdata(pdev
);
125 for (i
= 0; i
< ARRAY_SIZE(nexus
->buses
); i
++) {
126 struct cavium_mdiobus
*bus
= nexus
->buses
[i
];
131 mdiobus_unregister(bus
->mii_bus
);
132 mdiobus_free(bus
->mii_bus
);
133 oct_mdio_writeq(0, bus
->register_base
+ SMI_EN
);
135 pci_set_drvdata(pdev
, NULL
);
138 static const struct pci_device_id thunder_mdiobus_id_table
[] = {
139 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM
, 0xa02b) },
140 { 0, } /* End of table. */
142 MODULE_DEVICE_TABLE(pci
, thunder_mdiobus_id_table
);
144 static struct pci_driver thunder_mdiobus_driver
= {
145 .name
= KBUILD_MODNAME
,
146 .id_table
= thunder_mdiobus_id_table
,
147 .probe
= thunder_mdiobus_pci_probe
,
148 .remove
= thunder_mdiobus_pci_remove
,
151 module_pci_driver(thunder_mdiobus_driver
);
153 MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver");
154 MODULE_LICENSE("GPL");