File Index
Files and directories
Sign in
FILE

tn40_mdio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/tehuti/tn40_mdio.c C
  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
 19static 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
 33static 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
 40static 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
 53static 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
 77static 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
104static 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
110static 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 */
125static 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
156void 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
166int 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
212err_swnodes_unregister:
213	software_node_unregister_node_group(priv->nodes.group);
214	return ret;
215err_swnodes_cleanup:
216	tn40_swnodes_cleanup(priv);
217	return ret;
218}
219
220MODULE_FIRMWARE(AQR105_FIRMWARE);
~/ Read-only file preview.