brintos

brintos / linux-shallow public Read only

0
0
Text · 12.2 KiB · 65dc07d Raw
472 lines · c
1/*2 * QorIQ 10G MDIO Controller3 *4 * Copyright 2012 Freescale Semiconductor, Inc.5 * Copyright 2021 NXP6 *7 * Authors: Andy Fleming <afleming@freescale.com>8 *          Timur Tabi <timur@freescale.com>9 *10 * This file is licensed under the terms of the GNU General Public License11 * version 2.  This program is licensed "as is" without any warranty of any12 * kind, whether express or implied.13 */14 15#include <linux/acpi.h>16#include <linux/acpi_mdio.h>17#include <linux/clk.h>18#include <linux/interrupt.h>19#include <linux/kernel.h>20#include <linux/mdio.h>21#include <linux/module.h>22#include <linux/of.h>23#include <linux/of_mdio.h>24#include <linux/phy.h>25#include <linux/platform_device.h>26#include <linux/slab.h>27 28/* Number of microseconds to wait for a register to respond */29#define TIMEOUT	100030 31struct tgec_mdio_controller {32	__be32	reserved[12];33	__be32	mdio_stat;	/* MDIO configuration and status */34	__be32	mdio_ctl;	/* MDIO control */35	__be32	mdio_data;	/* MDIO data */36	__be32	mdio_addr;	/* MDIO address */37} __packed;38 39#define MDIO_STAT_ENC		BIT(6)40#define MDIO_STAT_CLKDIV(x)	(((x) & 0x1ff) << 7)41#define MDIO_STAT_BSY		BIT(0)42#define MDIO_STAT_RD_ER		BIT(1)43#define MDIO_STAT_PRE_DIS	BIT(5)44#define MDIO_CTL_DEV_ADDR(x) 	(x & 0x1f)45#define MDIO_CTL_PORT_ADDR(x)	((x & 0x1f) << 5)46#define MDIO_CTL_PRE_DIS	BIT(10)47#define MDIO_CTL_SCAN_EN	BIT(11)48#define MDIO_CTL_POST_INC	BIT(14)49#define MDIO_CTL_READ		BIT(15)50 51#define MDIO_DATA(x)		(x & 0xffff)52 53struct mdio_fsl_priv {54	struct	tgec_mdio_controller __iomem *mdio_base;55	struct	clk *enet_clk;56	u32	mdc_freq;57	bool	is_little_endian;58	bool	has_a009885;59	bool	has_a011043;60};61 62static u32 xgmac_read32(void __iomem *regs,63			bool is_little_endian)64{65	if (is_little_endian)66		return ioread32(regs);67	else68		return ioread32be(regs);69}70 71static void xgmac_write32(u32 value,72			  void __iomem *regs,73			  bool is_little_endian)74{75	if (is_little_endian)76		iowrite32(value, regs);77	else78		iowrite32be(value, regs);79}80 81/*82 * Wait until the MDIO bus is free83 */84static int xgmac_wait_until_free(struct device *dev,85				 struct tgec_mdio_controller __iomem *regs,86				 bool is_little_endian)87{88	unsigned int timeout;89 90	/* Wait till the bus is free */91	timeout = TIMEOUT;92	while ((xgmac_read32(&regs->mdio_stat, is_little_endian) &93		MDIO_STAT_BSY) && timeout) {94		cpu_relax();95		timeout--;96	}97 98	if (!timeout) {99		dev_err(dev, "timeout waiting for bus to be free\n");100		return -ETIMEDOUT;101	}102 103	return 0;104}105 106/*107 * Wait till the MDIO read or write operation is complete108 */109static int xgmac_wait_until_done(struct device *dev,110				 struct tgec_mdio_controller __iomem *regs,111				 bool is_little_endian)112{113	unsigned int timeout;114 115	/* Wait till the MDIO write is complete */116	timeout = TIMEOUT;117	while ((xgmac_read32(&regs->mdio_stat, is_little_endian) &118		MDIO_STAT_BSY) && timeout) {119		cpu_relax();120		timeout--;121	}122 123	if (!timeout) {124		dev_err(dev, "timeout waiting for operation to complete\n");125		return -ETIMEDOUT;126	}127 128	return 0;129}130 131static int xgmac_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,132				u16 value)133{134	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;135	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;136	bool endian = priv->is_little_endian;137	u16 dev_addr = regnum & 0x1f;138	u32 mdio_ctl, mdio_stat;139	int ret;140 141	mdio_stat = xgmac_read32(&regs->mdio_stat, endian);142	mdio_stat &= ~MDIO_STAT_ENC;143	xgmac_write32(mdio_stat, &regs->mdio_stat, endian);144 145	ret = xgmac_wait_until_free(&bus->dev, regs, endian);146	if (ret)147		return ret;148 149	/* Set the port and dev addr */150	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);151	xgmac_write32(mdio_ctl, &regs->mdio_ctl, endian);152 153	/* Write the value to the register */154	xgmac_write32(MDIO_DATA(value), &regs->mdio_data, endian);155 156	ret = xgmac_wait_until_done(&bus->dev, regs, endian);157	if (ret)158		return ret;159 160	return 0;161}162 163static int xgmac_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,164				int regnum, u16 value)165{166	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;167	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;168	bool endian = priv->is_little_endian;169	u32 mdio_ctl, mdio_stat;170	int ret;171 172	mdio_stat = xgmac_read32(&regs->mdio_stat, endian);173	mdio_stat |= MDIO_STAT_ENC;174 175	xgmac_write32(mdio_stat, &regs->mdio_stat, endian);176 177	ret = xgmac_wait_until_free(&bus->dev, regs, endian);178	if (ret)179		return ret;180 181	/* Set the port and dev addr */182	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);183	xgmac_write32(mdio_ctl, &regs->mdio_ctl, endian);184 185	/* Set the register address */186	xgmac_write32(regnum & 0xffff, &regs->mdio_addr, endian);187 188	ret = xgmac_wait_until_free(&bus->dev, regs, endian);189	if (ret)190		return ret;191 192	/* Write the value to the register */193	xgmac_write32(MDIO_DATA(value), &regs->mdio_data, endian);194 195	ret = xgmac_wait_until_done(&bus->dev, regs, endian);196	if (ret)197		return ret;198 199	return 0;200}201 202/* Reads from register regnum in the PHY for device dev, returning the value.203 * Clears miimcom first.  All PHY configuration has to be done through the204 * TSEC1 MIIM regs.205 */206static int xgmac_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)207{208	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;209	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;210	bool endian = priv->is_little_endian;211	u16 dev_addr = regnum & 0x1f;212	unsigned long flags;213	uint32_t mdio_stat;214	uint32_t mdio_ctl;215	int ret;216 217	mdio_stat = xgmac_read32(&regs->mdio_stat, endian);218	mdio_stat &= ~MDIO_STAT_ENC;219	xgmac_write32(mdio_stat, &regs->mdio_stat, endian);220 221	ret = xgmac_wait_until_free(&bus->dev, regs, endian);222	if (ret)223		return ret;224 225	/* Set the Port and Device Addrs */226	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);227	xgmac_write32(mdio_ctl, &regs->mdio_ctl, endian);228 229	if (priv->has_a009885)230		/* Once the operation completes, i.e. MDIO_STAT_BSY clears, we231		 * must read back the data register within 16 MDC cycles.232		 */233		local_irq_save(flags);234 235	/* Initiate the read */236	xgmac_write32(mdio_ctl | MDIO_CTL_READ, &regs->mdio_ctl, endian);237 238	ret = xgmac_wait_until_done(&bus->dev, regs, endian);239	if (ret)240		goto irq_restore;241 242	/* Return all Fs if nothing was there */243	if ((xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) &&244	    !priv->has_a011043) {245		dev_dbg(&bus->dev,246			"Error while reading PHY%d reg at %d.%d\n",247			phy_id, dev_addr, regnum);248		ret = 0xffff;249	} else {250		ret = xgmac_read32(&regs->mdio_data, endian) & 0xffff;251		dev_dbg(&bus->dev, "read %04x\n", ret);252	}253 254irq_restore:255	if (priv->has_a009885)256		local_irq_restore(flags);257 258	return ret;259}260 261/* Reads from register regnum in the PHY for device dev, returning the value.262 * Clears miimcom first.  All PHY configuration has to be done through the263 * TSEC1 MIIM regs.264 */265static int xgmac_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,266			       int regnum)267{268	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;269	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;270	bool endian = priv->is_little_endian;271	u32 mdio_stat, mdio_ctl;272	unsigned long flags;273	int ret;274 275	mdio_stat = xgmac_read32(&regs->mdio_stat, endian);276	mdio_stat |= MDIO_STAT_ENC;277 278	xgmac_write32(mdio_stat, &regs->mdio_stat, endian);279 280	ret = xgmac_wait_until_free(&bus->dev, regs, endian);281	if (ret)282		return ret;283 284	/* Set the Port and Device Addrs */285	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);286	xgmac_write32(mdio_ctl, &regs->mdio_ctl, endian);287 288	/* Set the register address */289	xgmac_write32(regnum & 0xffff, &regs->mdio_addr, endian);290 291	ret = xgmac_wait_until_free(&bus->dev, regs, endian);292	if (ret)293		return ret;294 295	if (priv->has_a009885)296		/* Once the operation completes, i.e. MDIO_STAT_BSY clears, we297		 * must read back the data register within 16 MDC cycles.298		 */299		local_irq_save(flags);300 301	/* Initiate the read */302	xgmac_write32(mdio_ctl | MDIO_CTL_READ, &regs->mdio_ctl, endian);303 304	ret = xgmac_wait_until_done(&bus->dev, regs, endian);305	if (ret)306		goto irq_restore;307 308	/* Return all Fs if nothing was there */309	if ((xgmac_read32(&regs->mdio_stat, endian) & MDIO_STAT_RD_ER) &&310	    !priv->has_a011043) {311		dev_dbg(&bus->dev,312			"Error while reading PHY%d reg at %d.%d\n",313			phy_id, dev_addr, regnum);314		ret = 0xffff;315	} else {316		ret = xgmac_read32(&regs->mdio_data, endian) & 0xffff;317		dev_dbg(&bus->dev, "read %04x\n", ret);318	}319 320irq_restore:321	if (priv->has_a009885)322		local_irq_restore(flags);323 324	return ret;325}326 327static int xgmac_mdio_set_mdc_freq(struct mii_bus *bus)328{329	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;330	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;331	struct device *dev = bus->parent;332	u32 mdio_stat, div;333 334	if (device_property_read_u32(dev, "clock-frequency", &priv->mdc_freq))335		return 0;336 337	priv->enet_clk = devm_clk_get(dev, NULL);338	if (IS_ERR(priv->enet_clk)) {339		dev_err(dev, "Input clock unknown, not changing MDC frequency");340		return PTR_ERR(priv->enet_clk);341	}342 343	div = ((clk_get_rate(priv->enet_clk) / priv->mdc_freq) - 1) / 2;344	if (div < 5 || div > 0x1ff) {345		dev_err(dev, "Requested MDC frequency is out of range, ignoring");346		return -EINVAL;347	}348 349	mdio_stat = xgmac_read32(&regs->mdio_stat, priv->is_little_endian);350	mdio_stat &= ~MDIO_STAT_CLKDIV(0x1ff);351	mdio_stat |= MDIO_STAT_CLKDIV(div);352	xgmac_write32(mdio_stat, &regs->mdio_stat, priv->is_little_endian);353	return 0;354}355 356static void xgmac_mdio_set_suppress_preamble(struct mii_bus *bus)357{358	struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;359	struct tgec_mdio_controller __iomem *regs = priv->mdio_base;360	struct device *dev = bus->parent;361	u32 mdio_stat;362 363	if (!device_property_read_bool(dev, "suppress-preamble"))364		return;365 366	mdio_stat = xgmac_read32(&regs->mdio_stat, priv->is_little_endian);367	mdio_stat |= MDIO_STAT_PRE_DIS;368	xgmac_write32(mdio_stat, &regs->mdio_stat, priv->is_little_endian);369}370 371static int xgmac_mdio_probe(struct platform_device *pdev)372{373	struct fwnode_handle *fwnode;374	struct mdio_fsl_priv *priv;375	struct resource *res;376	struct mii_bus *bus;377	int ret;378 379	/* In DPAA-1, MDIO is one of the many FMan sub-devices. The FMan380	 * defines a register space that spans a large area, covering all the381	 * subdevice areas. Therefore, MDIO cannot claim exclusive access to382	 * this register area.383	 */384	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);385	if (!res) {386		dev_err(&pdev->dev, "could not obtain address\n");387		return -EINVAL;388	}389 390	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(struct mdio_fsl_priv));391	if (!bus)392		return -ENOMEM;393 394	bus->name = "Freescale XGMAC MDIO Bus";395	bus->read = xgmac_mdio_read_c22;396	bus->write = xgmac_mdio_write_c22;397	bus->read_c45 = xgmac_mdio_read_c45;398	bus->write_c45 = xgmac_mdio_write_c45;399	bus->parent = &pdev->dev;400	snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res->start);401 402	priv = bus->priv;403	priv->mdio_base = devm_ioremap(&pdev->dev, res->start,404				       resource_size(res));405	if (!priv->mdio_base)406		return -ENOMEM;407 408	/* For both ACPI and DT cases, endianness of MDIO controller409	 * needs to be specified using "little-endian" property.410	 */411	priv->is_little_endian = device_property_read_bool(&pdev->dev,412							   "little-endian");413 414	priv->has_a009885 = device_property_read_bool(&pdev->dev,415						      "fsl,erratum-a009885");416	priv->has_a011043 = device_property_read_bool(&pdev->dev,417						      "fsl,erratum-a011043");418 419	xgmac_mdio_set_suppress_preamble(bus);420 421	ret = xgmac_mdio_set_mdc_freq(bus);422	if (ret)423		return ret;424 425	fwnode = dev_fwnode(&pdev->dev);426	if (is_of_node(fwnode))427		ret = of_mdiobus_register(bus, to_of_node(fwnode));428	else if (is_acpi_node(fwnode))429		ret = acpi_mdiobus_register(bus, fwnode);430	else431		ret = -EINVAL;432	if (ret) {433		dev_err(&pdev->dev, "cannot register MDIO bus\n");434		return ret;435	}436 437	platform_set_drvdata(pdev, bus);438 439	return 0;440}441 442static const struct of_device_id xgmac_mdio_match[] = {443	{444		.compatible = "fsl,fman-xmdio",445	},446	{447		.compatible = "fsl,fman-memac-mdio",448	},449	{},450};451MODULE_DEVICE_TABLE(of, xgmac_mdio_match);452 453static const struct acpi_device_id xgmac_acpi_match[] = {454	{ "NXP0006" },455	{ }456};457MODULE_DEVICE_TABLE(acpi, xgmac_acpi_match);458 459static struct platform_driver xgmac_mdio_driver = {460	.driver = {461		.name = "fsl-fman_xmdio",462		.of_match_table = xgmac_mdio_match,463		.acpi_match_table = xgmac_acpi_match,464	},465	.probe = xgmac_mdio_probe,466};467 468module_platform_driver(xgmac_mdio_driver);469 470MODULE_DESCRIPTION("Freescale QorIQ 10G MDIO Controller");471MODULE_LICENSE("GPL v2");472