xref: /openbmc/u-boot/drivers/net/fsl_mdio.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2063c1263SAndy Fleming /*
35be00a01SClaudiu Manoil  * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
4063c1263SAndy Fleming  *	Jun-jie Zhang <b18070@freescale.com>
5063c1263SAndy Fleming  *	Mingkai Hu <Mingkai.hu@freescale.com>
6063c1263SAndy Fleming  */
79872b736SBin Meng 
8063c1263SAndy Fleming #include <common.h>
9063c1263SAndy Fleming #include <miiphy.h>
10063c1263SAndy Fleming #include <phy.h>
11063c1263SAndy Fleming #include <fsl_mdio.h>
12063c1263SAndy Fleming #include <asm/io.h>
131221ce45SMasahiro Yamada #include <linux/errno.h>
14063c1263SAndy Fleming 
tsec_local_mdio_write(struct tsec_mii_mng __iomem * phyregs,int port_addr,int dev_addr,int regnum,int value)155be00a01SClaudiu Manoil void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
16063c1263SAndy Fleming 		int dev_addr, int regnum, int value)
17063c1263SAndy Fleming {
18063c1263SAndy Fleming 	int timeout = 1000000;
19063c1263SAndy Fleming 
20063c1263SAndy Fleming 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
21063c1263SAndy Fleming 	out_be32(&phyregs->miimcon, value);
22d2614ea0SAlison Wang 	/* Memory barrier */
23d2614ea0SAlison Wang 	mb();
24063c1263SAndy Fleming 
25063c1263SAndy Fleming 	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
26063c1263SAndy Fleming 		;
27063c1263SAndy Fleming }
28063c1263SAndy Fleming 
tsec_local_mdio_read(struct tsec_mii_mng __iomem * phyregs,int port_addr,int dev_addr,int regnum)295be00a01SClaudiu Manoil int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
30063c1263SAndy Fleming 		int dev_addr, int regnum)
31063c1263SAndy Fleming {
32063c1263SAndy Fleming 	int value;
33063c1263SAndy Fleming 	int timeout = 1000000;
34063c1263SAndy Fleming 
359872b736SBin Meng 	/* Put the address of the phy, and the register number into MIIMADD */
36063c1263SAndy Fleming 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
37063c1263SAndy Fleming 
38063c1263SAndy Fleming 	/* Clear the command register, and wait */
39063c1263SAndy Fleming 	out_be32(&phyregs->miimcom, 0);
40d2614ea0SAlison Wang 	/* Memory barrier */
41d2614ea0SAlison Wang 	mb();
42063c1263SAndy Fleming 
43063c1263SAndy Fleming 	/* Initiate a read command, and wait */
44063c1263SAndy Fleming 	out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
45d2614ea0SAlison Wang 	/* Memory barrier */
46d2614ea0SAlison Wang 	mb();
47063c1263SAndy Fleming 
48063c1263SAndy Fleming 	/* Wait for the the indication that the read is done */
49063c1263SAndy Fleming 	while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
50063c1263SAndy Fleming 			&& timeout--)
51063c1263SAndy Fleming 		;
52063c1263SAndy Fleming 
53063c1263SAndy Fleming 	/* Grab the value read from the PHY */
54063c1263SAndy Fleming 	value = in_be32(&phyregs->miimstat);
55063c1263SAndy Fleming 
56063c1263SAndy Fleming 	return value;
57063c1263SAndy Fleming }
58063c1263SAndy Fleming 
fsl_pq_mdio_reset(struct mii_dev * bus)59063c1263SAndy Fleming static int fsl_pq_mdio_reset(struct mii_dev *bus)
60063c1263SAndy Fleming {
615be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *regs =
625be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
63063c1263SAndy Fleming 
64063c1263SAndy Fleming 	/* Reset MII (due to new addresses) */
65063c1263SAndy Fleming 	out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
66063c1263SAndy Fleming 
67063c1263SAndy Fleming 	out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
68063c1263SAndy Fleming 
69063c1263SAndy Fleming 	while (in_be32(&regs->miimind) & MIIMIND_BUSY)
70063c1263SAndy Fleming 		;
71063c1263SAndy Fleming 
72063c1263SAndy Fleming 	return 0;
73063c1263SAndy Fleming }
74063c1263SAndy Fleming 
tsec_phy_read(struct mii_dev * bus,int addr,int dev_addr,int regnum)75063c1263SAndy Fleming int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
76063c1263SAndy Fleming {
775be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *phyregs =
785be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
79063c1263SAndy Fleming 
80063c1263SAndy Fleming 	return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
81063c1263SAndy Fleming }
82063c1263SAndy Fleming 
tsec_phy_write(struct mii_dev * bus,int addr,int dev_addr,int regnum,u16 value)83063c1263SAndy Fleming int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
84063c1263SAndy Fleming 			u16 value)
85063c1263SAndy Fleming {
865be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *phyregs =
875be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
88063c1263SAndy Fleming 
89063c1263SAndy Fleming 	tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
90063c1263SAndy Fleming 
91063c1263SAndy Fleming 	return 0;
92063c1263SAndy Fleming }
93063c1263SAndy Fleming 
fsl_pq_mdio_init(bd_t * bis,struct fsl_pq_mdio_info * info)94063c1263SAndy Fleming int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info)
95063c1263SAndy Fleming {
96063c1263SAndy Fleming 	struct mii_dev *bus = mdio_alloc();
97063c1263SAndy Fleming 
98063c1263SAndy Fleming 	if (!bus) {
99063c1263SAndy Fleming 		printf("Failed to allocate FSL MDIO bus\n");
100063c1263SAndy Fleming 		return -1;
101063c1263SAndy Fleming 	}
102063c1263SAndy Fleming 
103063c1263SAndy Fleming 	bus->read = tsec_phy_read;
104063c1263SAndy Fleming 	bus->write = tsec_phy_write;
105063c1263SAndy Fleming 	bus->reset = fsl_pq_mdio_reset;
106192bc694SBen Whitten 	strcpy(bus->name, info->name);
107063c1263SAndy Fleming 
1085be00a01SClaudiu Manoil 	bus->priv = (void *)info->regs;
109063c1263SAndy Fleming 
110063c1263SAndy Fleming 	return mdio_register(bus);
111063c1263SAndy Fleming }
112