xref: /openbmc/u-boot/drivers/net/fsl_mdio.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
1063c1263SAndy Fleming /*
25be00a01SClaudiu Manoil  * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
3063c1263SAndy Fleming  *	Jun-jie Zhang <b18070@freescale.com>
4063c1263SAndy Fleming  *	Mingkai Hu <Mingkai.hu@freescale.com>
5063c1263SAndy Fleming  *
61a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
7063c1263SAndy Fleming  */
89872b736SBin Meng 
9063c1263SAndy Fleming #include <common.h>
10063c1263SAndy Fleming #include <miiphy.h>
11063c1263SAndy Fleming #include <phy.h>
12063c1263SAndy Fleming #include <fsl_mdio.h>
13063c1263SAndy Fleming #include <asm/io.h>
14*1221ce45SMasahiro Yamada #include <linux/errno.h>
15063c1263SAndy Fleming 
165be00a01SClaudiu Manoil void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
17063c1263SAndy Fleming 		int dev_addr, int regnum, int value)
18063c1263SAndy Fleming {
19063c1263SAndy Fleming 	int timeout = 1000000;
20063c1263SAndy Fleming 
21063c1263SAndy Fleming 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
22063c1263SAndy Fleming 	out_be32(&phyregs->miimcon, value);
23d2614ea0SAlison Wang 	/* Memory barrier */
24d2614ea0SAlison Wang 	mb();
25063c1263SAndy Fleming 
26063c1263SAndy Fleming 	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
27063c1263SAndy Fleming 		;
28063c1263SAndy Fleming }
29063c1263SAndy Fleming 
305be00a01SClaudiu Manoil int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
31063c1263SAndy Fleming 		int dev_addr, int regnum)
32063c1263SAndy Fleming {
33063c1263SAndy Fleming 	int value;
34063c1263SAndy Fleming 	int timeout = 1000000;
35063c1263SAndy Fleming 
369872b736SBin Meng 	/* Put the address of the phy, and the register number into MIIMADD */
37063c1263SAndy Fleming 	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
38063c1263SAndy Fleming 
39063c1263SAndy Fleming 	/* Clear the command register, and wait */
40063c1263SAndy Fleming 	out_be32(&phyregs->miimcom, 0);
41d2614ea0SAlison Wang 	/* Memory barrier */
42d2614ea0SAlison Wang 	mb();
43063c1263SAndy Fleming 
44063c1263SAndy Fleming 	/* Initiate a read command, and wait */
45063c1263SAndy Fleming 	out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
46d2614ea0SAlison Wang 	/* Memory barrier */
47d2614ea0SAlison Wang 	mb();
48063c1263SAndy Fleming 
49063c1263SAndy Fleming 	/* Wait for the the indication that the read is done */
50063c1263SAndy Fleming 	while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
51063c1263SAndy Fleming 			&& timeout--)
52063c1263SAndy Fleming 		;
53063c1263SAndy Fleming 
54063c1263SAndy Fleming 	/* Grab the value read from the PHY */
55063c1263SAndy Fleming 	value = in_be32(&phyregs->miimstat);
56063c1263SAndy Fleming 
57063c1263SAndy Fleming 	return value;
58063c1263SAndy Fleming }
59063c1263SAndy Fleming 
60063c1263SAndy Fleming static int fsl_pq_mdio_reset(struct mii_dev *bus)
61063c1263SAndy Fleming {
625be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *regs =
635be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
64063c1263SAndy Fleming 
65063c1263SAndy Fleming 	/* Reset MII (due to new addresses) */
66063c1263SAndy Fleming 	out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
67063c1263SAndy Fleming 
68063c1263SAndy Fleming 	out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
69063c1263SAndy Fleming 
70063c1263SAndy Fleming 	while (in_be32(&regs->miimind) & MIIMIND_BUSY)
71063c1263SAndy Fleming 		;
72063c1263SAndy Fleming 
73063c1263SAndy Fleming 	return 0;
74063c1263SAndy Fleming }
75063c1263SAndy Fleming 
76063c1263SAndy Fleming int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
77063c1263SAndy Fleming {
785be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *phyregs =
795be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
80063c1263SAndy Fleming 
81063c1263SAndy Fleming 	return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
82063c1263SAndy Fleming }
83063c1263SAndy Fleming 
84063c1263SAndy Fleming int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
85063c1263SAndy Fleming 			u16 value)
86063c1263SAndy Fleming {
875be00a01SClaudiu Manoil 	struct tsec_mii_mng __iomem *phyregs =
885be00a01SClaudiu Manoil 		(struct tsec_mii_mng __iomem *)bus->priv;
89063c1263SAndy Fleming 
90063c1263SAndy Fleming 	tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
91063c1263SAndy Fleming 
92063c1263SAndy Fleming 	return 0;
93063c1263SAndy Fleming }
94063c1263SAndy Fleming 
95063c1263SAndy Fleming int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info)
96063c1263SAndy Fleming {
97063c1263SAndy Fleming 	struct mii_dev *bus = mdio_alloc();
98063c1263SAndy Fleming 
99063c1263SAndy Fleming 	if (!bus) {
100063c1263SAndy Fleming 		printf("Failed to allocate FSL MDIO bus\n");
101063c1263SAndy Fleming 		return -1;
102063c1263SAndy Fleming 	}
103063c1263SAndy Fleming 
104063c1263SAndy Fleming 	bus->read = tsec_phy_read;
105063c1263SAndy Fleming 	bus->write = tsec_phy_write;
106063c1263SAndy Fleming 	bus->reset = fsl_pq_mdio_reset;
107192bc694SBen Whitten 	strcpy(bus->name, info->name);
108063c1263SAndy Fleming 
1095be00a01SClaudiu Manoil 	bus->priv = (void *)info->regs;
110063c1263SAndy Fleming 
111063c1263SAndy Fleming 	return mdio_register(bus);
112063c1263SAndy Fleming }
113