xref: /linux/drivers/net/ethernet/tehuti/tn40_mdio.c (revision 1a9239bb4253f9076b5b4b2a1a4e8d7defd77a95)
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