Loading...
Note: File does not exist in v4.17.
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2/* Copyright 2019 NXP */
3#include <linux/fsl/enetc_mdio.h>
4#include <linux/of_mdio.h>
5#include "enetc_pf.h"
6
7#define NETC_EMDIO_VEN_ID 0x1131
8#define NETC_EMDIO_DEV_ID 0xee00
9#define ENETC_MDIO_DEV_ID 0xee01
10#define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO"
11#define ENETC_MDIO_BUS_NAME ENETC_MDIO_DEV_NAME " Bus"
12#define ENETC_MDIO_DRV_NAME ENETC_MDIO_DEV_NAME " driver"
13
14DEFINE_STATIC_KEY_FALSE(enetc_has_err050089);
15EXPORT_SYMBOL_GPL(enetc_has_err050089);
16
17static void enetc_emdio_enable_err050089(struct pci_dev *pdev)
18{
19 if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
20 pdev->device == ENETC_MDIO_DEV_ID) {
21 static_branch_inc(&enetc_has_err050089);
22 dev_info(&pdev->dev, "Enabled ERR050089 workaround\n");
23 }
24}
25
26static void enetc_emdio_disable_err050089(struct pci_dev *pdev)
27{
28 if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
29 pdev->device == ENETC_MDIO_DEV_ID) {
30 static_branch_dec(&enetc_has_err050089);
31 if (!static_key_enabled(&enetc_has_err050089.key))
32 dev_info(&pdev->dev, "Disabled ERR050089 workaround\n");
33 }
34}
35
36static int enetc_pci_mdio_probe(struct pci_dev *pdev,
37 const struct pci_device_id *ent)
38{
39 struct enetc_mdio_priv *mdio_priv;
40 struct device *dev = &pdev->dev;
41 void __iomem *port_regs;
42 struct enetc_hw *hw;
43 struct mii_bus *bus;
44 int err;
45
46 port_regs = pci_iomap(pdev, 0, 0);
47 if (!port_regs) {
48 dev_err(dev, "iomap failed\n");
49 err = -ENXIO;
50 goto err_ioremap;
51 }
52
53 hw = enetc_hw_alloc(dev, port_regs);
54 if (IS_ERR(hw)) {
55 err = PTR_ERR(hw);
56 goto err_hw_alloc;
57 }
58
59 bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
60 if (!bus) {
61 err = -ENOMEM;
62 goto err_mdiobus_alloc;
63 }
64
65 bus->name = ENETC_MDIO_BUS_NAME;
66 bus->read = enetc_mdio_read_c22;
67 bus->write = enetc_mdio_write_c22;
68 bus->read_c45 = enetc_mdio_read_c45;
69 bus->write_c45 = enetc_mdio_write_c45;
70 bus->parent = dev;
71 mdio_priv = bus->priv;
72 mdio_priv->hw = hw;
73 mdio_priv->mdio_base = ENETC_EMDIO_BASE;
74 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
75
76 pcie_flr(pdev);
77 err = pci_enable_device_mem(pdev);
78 if (err) {
79 dev_err(dev, "device enable failed\n");
80 goto err_pci_enable;
81 }
82
83 err = pci_request_region(pdev, 0, KBUILD_MODNAME);
84 if (err) {
85 dev_err(dev, "pci_request_region failed\n");
86 goto err_pci_mem_reg;
87 }
88
89 enetc_emdio_enable_err050089(pdev);
90
91 err = of_mdiobus_register(bus, dev->of_node);
92 if (err)
93 goto err_mdiobus_reg;
94
95 pci_set_drvdata(pdev, bus);
96
97 return 0;
98
99err_mdiobus_reg:
100 enetc_emdio_disable_err050089(pdev);
101 pci_release_region(pdev, 0);
102err_pci_mem_reg:
103 pci_disable_device(pdev);
104err_pci_enable:
105err_mdiobus_alloc:
106err_hw_alloc:
107 iounmap(port_regs);
108err_ioremap:
109 return err;
110}
111
112static void enetc_pci_mdio_remove(struct pci_dev *pdev)
113{
114 struct mii_bus *bus = pci_get_drvdata(pdev);
115 struct enetc_mdio_priv *mdio_priv;
116
117 mdiobus_unregister(bus);
118
119 enetc_emdio_disable_err050089(pdev);
120
121 mdio_priv = bus->priv;
122 iounmap(mdio_priv->hw->port);
123 pci_release_region(pdev, 0);
124 pci_disable_device(pdev);
125}
126
127static const struct pci_device_id enetc_pci_mdio_id_table[] = {
128 { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) },
129 { PCI_DEVICE(NETC_EMDIO_VEN_ID, NETC_EMDIO_DEV_ID) },
130 { 0, } /* End of table. */
131};
132MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table);
133
134static struct pci_driver enetc_pci_mdio_driver = {
135 .name = KBUILD_MODNAME,
136 .id_table = enetc_pci_mdio_id_table,
137 .probe = enetc_pci_mdio_probe,
138 .remove = enetc_pci_mdio_remove,
139};
140module_pci_driver(enetc_pci_mdio_driver);
141
142MODULE_DESCRIPTION(ENETC_MDIO_DRV_NAME);
143MODULE_LICENSE("Dual BSD/GPL");