1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) Tehuti Networks Ltd. */
3
4 #include <linux/netdevice.h>
5 #include <linux/pci.h>
6 #include <linux/phylink.h>
7
8 #include "tn40.h"
9
10 #define TN40_MDIO_DEVAD_MASK GENMASK(4, 0)
11 #define TN40_MDIO_PRTAD_MASK GENMASK(9, 5)
12 #define TN40_MDIO_CMD_VAL(device, port) \
13 (FIELD_PREP(TN40_MDIO_DEVAD_MASK, (device)) | \
14 (FIELD_PREP(TN40_MDIO_PRTAD_MASK, (port))))
15 #define TN40_MDIO_CMD_READ BIT(15)
16
17 #define AQR105_FIRMWARE "tehuti/aqr105-tn40xx.cld"
18
tn40_mdio_set_speed(struct tn40_priv * priv,u32 speed)19 static void tn40_mdio_set_speed(struct tn40_priv *priv, u32 speed)
20 {
21 void __iomem *regs = priv->regs;
22 int mdio_cfg;
23
24 if (speed == TN40_MDIO_SPEED_1MHZ)
25 mdio_cfg = (0x7d << 7) | 0x08; /* 1MHz */
26 else
27 mdio_cfg = 0xA08; /* 6MHz */
28 mdio_cfg |= (1 << 6);
29 writel(mdio_cfg, regs + TN40_REG_MDIO_CMD_STAT);
30 msleep(100);
31 }
32
tn40_mdio_stat(struct tn40_priv * priv)33 static u32 tn40_mdio_stat(struct tn40_priv *priv)
34 {
35 void __iomem *regs = priv->regs;
36
37 return readl(regs + TN40_REG_MDIO_CMD_STAT);
38 }
39
tn40_mdio_wait_nobusy(struct tn40_priv * priv,u32 * val)40 static int tn40_mdio_wait_nobusy(struct tn40_priv *priv, u32 *val)
41 {
42 u32 stat;
43 int ret;
44
45 ret = readx_poll_timeout_atomic(tn40_mdio_stat, priv, stat,
46 TN40_GET_MDIO_BUSY(stat) == 0, 10,
47 10000);
48 if (val)
49 *val = stat;
50 return ret;
51 }
52
tn40_mdio_read(struct tn40_priv * priv,int port,int device,u16 regnum)53 static int tn40_mdio_read(struct tn40_priv *priv, int port, int device,
54 u16 regnum)
55 {
56 void __iomem *regs = priv->regs;
57 u32 i;
58
59 /* wait until MDIO is not busy */
60 if (tn40_mdio_wait_nobusy(priv, NULL))
61 return -EIO;
62
63 i = TN40_MDIO_CMD_VAL(device, port);
64 writel(i, regs + TN40_REG_MDIO_CMD);
65 writel((u32)regnum, regs + TN40_REG_MDIO_ADDR);
66 if (tn40_mdio_wait_nobusy(priv, NULL))
67 return -EIO;
68
69 writel(TN40_MDIO_CMD_READ | i, regs + TN40_REG_MDIO_CMD);
70 /* read CMD_STAT until not busy */
71 if (tn40_mdio_wait_nobusy(priv, NULL))
72 return -EIO;
73
74 return lower_16_bits(readl(regs + TN40_REG_MDIO_DATA));
75 }
76
tn40_mdio_write(struct tn40_priv * priv,int port,int device,u16 regnum,u16 data)77 static int tn40_mdio_write(struct tn40_priv *priv, int port, int device,
78 u16 regnum, u16 data)
79 {
80 void __iomem *regs = priv->regs;
81 u32 tmp_reg = 0;
82 int ret;
83
84 /* wait until MDIO is not busy */
85 if (tn40_mdio_wait_nobusy(priv, NULL))
86 return -EIO;
87 writel(TN40_MDIO_CMD_VAL(device, port), regs + TN40_REG_MDIO_CMD);
88 writel((u32)regnum, regs + TN40_REG_MDIO_ADDR);
89 if (tn40_mdio_wait_nobusy(priv, NULL))
90 return -EIO;
91 writel((u32)data, regs + TN40_REG_MDIO_DATA);
92 /* read CMD_STAT until not busy */
93 ret = tn40_mdio_wait_nobusy(priv, &tmp_reg);
94 if (ret)
95 return -EIO;
96
97 if (TN40_GET_MDIO_RD_ERR(tmp_reg)) {
98 dev_err(&priv->pdev->dev, "MDIO error after write command\n");
99 return -EIO;
100 }
101 return 0;
102 }
103
tn40_mdio_read_c45(struct mii_bus * mii_bus,int addr,int devnum,int regnum)104 static int tn40_mdio_read_c45(struct mii_bus *mii_bus, int addr, int devnum,
105 int regnum)
106 {
107 return tn40_mdio_read(mii_bus->priv, addr, devnum, regnum);
108 }
109
tn40_mdio_write_c45(struct mii_bus * mii_bus,int addr,int devnum,int regnum,u16 val)110 static int tn40_mdio_write_c45(struct mii_bus *mii_bus, int addr, int devnum,
111 int regnum, u16 val)
112 {
113 return tn40_mdio_write(mii_bus->priv, addr, devnum, regnum, val);
114 }
115
116 /* registers an mdio node and an aqr105 PHY at address 1
117 * tn40_mdio-%id {
118 * ethernet-phy@1 {
119 * compatible = "ethernet-phy-id03a1.b4a3";
120 * reg = <1>;
121 * firmware-name = AQR105_FIRMWARE;
122 * };
123 * };
124 */
tn40_swnodes_register(struct tn40_priv * priv)125 static int tn40_swnodes_register(struct tn40_priv *priv)
126 {
127 struct tn40_nodes *nodes = &priv->nodes;
128 struct pci_dev *pdev = priv->pdev;
129 struct software_node *swnodes;
130 u32 id;
131
132 id = pci_dev_id(pdev);
133
134 snprintf(nodes->phy_name, sizeof(nodes->phy_name), "ethernet-phy@1");
135 snprintf(nodes->mdio_name, sizeof(nodes->mdio_name), "tn40_mdio-%x",
136 id);
137
138 swnodes = nodes->swnodes;
139
140 swnodes[SWNODE_MDIO] = NODE_PROP(nodes->mdio_name, NULL);
141
142 nodes->phy_props[0] = PROPERTY_ENTRY_STRING("compatible",
143 "ethernet-phy-id03a1.b4a3");
144 nodes->phy_props[1] = PROPERTY_ENTRY_U32("reg", 1);
145 nodes->phy_props[2] = PROPERTY_ENTRY_STRING("firmware-name",
146 AQR105_FIRMWARE);
147 swnodes[SWNODE_PHY] = NODE_PAR_PROP(nodes->phy_name,
148 &swnodes[SWNODE_MDIO],
149 nodes->phy_props);
150
151 nodes->group[SWNODE_PHY] = &swnodes[SWNODE_PHY];
152 nodes->group[SWNODE_MDIO] = &swnodes[SWNODE_MDIO];
153 return software_node_register_node_group(nodes->group);
154 }
155
tn40_swnodes_cleanup(struct tn40_priv * priv)156 void tn40_swnodes_cleanup(struct tn40_priv *priv)
157 {
158 /* cleanup of swnodes is only needed for AQR105-based cards */
159 if (priv->pdev->device == PCI_DEVICE_ID_TEHUTI_TN9510) {
160 fwnode_handle_put(dev_fwnode(&priv->mdio->dev));
161 device_remove_software_node(&priv->mdio->dev);
162 software_node_unregister_node_group(priv->nodes.group);
163 }
164 }
165
tn40_mdiobus_init(struct tn40_priv * priv)166 int tn40_mdiobus_init(struct tn40_priv *priv)
167 {
168 struct pci_dev *pdev = priv->pdev;
169 struct mii_bus *bus;
170 int ret;
171
172 bus = devm_mdiobus_alloc(&pdev->dev);
173 if (!bus)
174 return -ENOMEM;
175
176 bus->name = TN40_DRV_NAME;
177 bus->parent = &pdev->dev;
178 snprintf(bus->id, MII_BUS_ID_SIZE, "tn40xx-%x-%x",
179 pci_domain_nr(pdev->bus), pci_dev_id(pdev));
180 bus->priv = priv;
181
182 bus->read_c45 = tn40_mdio_read_c45;
183 bus->write_c45 = tn40_mdio_write_c45;
184 priv->mdio = bus;
185
186 /* provide swnodes for AQR105-based cards only */
187 if (pdev->device == PCI_DEVICE_ID_TEHUTI_TN9510) {
188 ret = tn40_swnodes_register(priv);
189 if (ret) {
190 pr_err("swnodes failed\n");
191 return ret;
192 }
193
194 ret = device_add_software_node(&bus->dev,
195 priv->nodes.group[SWNODE_MDIO]);
196 if (ret) {
197 dev_err(&pdev->dev,
198 "device_add_software_node failed: %d\n", ret);
199 goto err_swnodes_unregister;
200 }
201 }
202
203 tn40_mdio_set_speed(priv, TN40_MDIO_SPEED_6MHZ);
204 ret = devm_mdiobus_register(&pdev->dev, bus);
205 if (ret) {
206 dev_err(&pdev->dev, "failed to register mdiobus %d %u %u\n",
207 ret, bus->state, MDIOBUS_UNREGISTERED);
208 goto err_swnodes_cleanup;
209 }
210 return 0;
211
212 err_swnodes_unregister:
213 software_node_unregister_node_group(priv->nodes.group);
214 return ret;
215 err_swnodes_cleanup:
216 tn40_swnodes_cleanup(priv);
217 return ret;
218 }
219
220 MODULE_FIRMWARE(AQR105_FIRMWARE);
221