brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · af18615 Raw
143 lines · 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 17static void tn40_mdio_set_speed(struct tn40_priv *priv, u32 speed)18{19	void __iomem *regs = priv->regs;20	int mdio_cfg;21 22	if (speed == TN40_MDIO_SPEED_1MHZ)23		mdio_cfg = (0x7d << 7) | 0x08;	/* 1MHz */24	else25		mdio_cfg = 0xA08;	/* 6MHz */26	mdio_cfg |= (1 << 6);27	writel(mdio_cfg, regs + TN40_REG_MDIO_CMD_STAT);28	msleep(100);29}30 31static u32 tn40_mdio_stat(struct tn40_priv *priv)32{33	void __iomem *regs = priv->regs;34 35	return readl(regs + TN40_REG_MDIO_CMD_STAT);36}37 38static int tn40_mdio_wait_nobusy(struct tn40_priv *priv, u32 *val)39{40	u32 stat;41	int ret;42 43	ret = readx_poll_timeout_atomic(tn40_mdio_stat, priv, stat,44					TN40_GET_MDIO_BUSY(stat) == 0, 10,45					10000);46	if (val)47		*val = stat;48	return ret;49}50 51static int tn40_mdio_read(struct tn40_priv *priv, int port, int device,52			  u16 regnum)53{54	void __iomem *regs = priv->regs;55	u32 i;56 57	/* wait until MDIO is not busy */58	if (tn40_mdio_wait_nobusy(priv, NULL))59		return -EIO;60 61	i = TN40_MDIO_CMD_VAL(device, port);62	writel(i, regs + TN40_REG_MDIO_CMD);63	writel((u32)regnum, regs + TN40_REG_MDIO_ADDR);64	if (tn40_mdio_wait_nobusy(priv, NULL))65		return -EIO;66 67	writel(TN40_MDIO_CMD_READ | i, regs + TN40_REG_MDIO_CMD);68	/* read CMD_STAT until not busy */69	if (tn40_mdio_wait_nobusy(priv, NULL))70		return -EIO;71 72	return lower_16_bits(readl(regs + TN40_REG_MDIO_DATA));73}74 75static int tn40_mdio_write(struct tn40_priv *priv, int port, int device,76			   u16 regnum, u16 data)77{78	void __iomem *regs = priv->regs;79	u32 tmp_reg = 0;80	int ret;81 82	/* wait until MDIO is not busy */83	if (tn40_mdio_wait_nobusy(priv, NULL))84		return -EIO;85	writel(TN40_MDIO_CMD_VAL(device, port), regs + TN40_REG_MDIO_CMD);86	writel((u32)regnum, regs + TN40_REG_MDIO_ADDR);87	if (tn40_mdio_wait_nobusy(priv, NULL))88		return -EIO;89	writel((u32)data, regs + TN40_REG_MDIO_DATA);90	/* read CMD_STAT until not busy */91	ret = tn40_mdio_wait_nobusy(priv, &tmp_reg);92	if (ret)93		return -EIO;94 95	if (TN40_GET_MDIO_RD_ERR(tmp_reg)) {96		dev_err(&priv->pdev->dev, "MDIO error after write command\n");97		return -EIO;98	}99	return 0;100}101 102static int tn40_mdio_read_c45(struct mii_bus *mii_bus, int addr, int devnum,103			      int regnum)104{105	return tn40_mdio_read(mii_bus->priv, addr, devnum, regnum);106}107 108static int tn40_mdio_write_c45(struct mii_bus *mii_bus, int addr, int devnum,109			       int regnum, u16 val)110{111	return  tn40_mdio_write(mii_bus->priv, addr, devnum, regnum, val);112}113 114int tn40_mdiobus_init(struct tn40_priv *priv)115{116	struct pci_dev *pdev = priv->pdev;117	struct mii_bus *bus;118	int ret;119 120	bus = devm_mdiobus_alloc(&pdev->dev);121	if (!bus)122		return -ENOMEM;123 124	bus->name = TN40_DRV_NAME;125	bus->parent = &pdev->dev;126	snprintf(bus->id, MII_BUS_ID_SIZE, "tn40xx-%x-%x",127		 pci_domain_nr(pdev->bus), pci_dev_id(pdev));128	bus->priv = priv;129 130	bus->read_c45 = tn40_mdio_read_c45;131	bus->write_c45 = tn40_mdio_write_c45;132 133	ret = devm_mdiobus_register(&pdev->dev, bus);134	if (ret) {135		dev_err(&pdev->dev, "failed to register mdiobus %d %u %u\n",136			ret, bus->state, MDIOBUS_UNREGISTERED);137		return ret;138	}139	tn40_mdio_set_speed(priv, TN40_MDIO_SPEED_6MHZ);140	priv->mdio = bus;141	return 0;142}143