xref: /openbmc/u-boot/drivers/net/aspeed_mdio.c (revision 0f02bc6a)
1176338f1Sryan_chen /*
2176338f1Sryan_chen  * Copyright (C) ASPEED Technology Inc.
3176338f1Sryan_chen  * Ryan Chen <ryan_chen@aspeedtech.com>
4176338f1Sryan_chen  *
5176338f1Sryan_chen  * SPDX-License-Identifier:	GPL-2.0+
6176338f1Sryan_chen  */
7176338f1Sryan_chen 
8176338f1Sryan_chen #include <common.h>
9176338f1Sryan_chen #include <miiphy.h>
10176338f1Sryan_chen #include <phy.h>
11176338f1Sryan_chen #include <asm/io.h>
121b171c6cSryan_chen #include <reset.h>
13176338f1Sryan_chen #include <linux/errno.h>
14176338f1Sryan_chen 
15176338f1Sryan_chen /*
16176338f1Sryan_chen  * PHY control register
17176338f1Sryan_chen  */
18176338f1Sryan_chen #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0x3f
19176338f1Sryan_chen #define FTGMAC100_PHYCR_MDC_CYCTHR(x)	((x) & 0x3f)
20176338f1Sryan_chen #define FTGMAC100_PHYCR_PHYAD(x)	(((x) & 0x1f) << 16)
21176338f1Sryan_chen #define FTGMAC100_PHYCR_REGAD(x)	(((x) & 0x1f) << 21)
22176338f1Sryan_chen #define FTGMAC100_PHYCR_MIIRD		(1 << 26)
23176338f1Sryan_chen #define FTGMAC100_PHYCR_MIIWR		(1 << 27)
24176338f1Sryan_chen 
251b171c6cSryan_chen #ifdef CONFIG_ASPEED_AST2600
26176338f1Sryan_chen //G6 MDC/MDIO
27176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_FIRE		BIT(31)
28176338f1Sryan_chen #define FTGMAC100_PHYCR_ST_22			BIT(28)
29176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_WRITE		BIT(26)
30176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_READ		BIT(27)
31176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_WDATA(x)	(x & 0xffff)
32176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 21)
33176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_REGAD(x)	(((x) & 0x1f) << 16)
34176338f1Sryan_chen #else
35176338f1Sryan_chen //New MDC/MDIO
36176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_FIRE		BIT(15)
37176338f1Sryan_chen #define FTGMAC100_PHYCR_ST_22			BIT(12)
38176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_WRITE		BIT(10)
39176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_READ		BIT(11)
40176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_WDATA(x)	((x & 0xffff) << 16)
41176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 5)
42176338f1Sryan_chen #define FTGMAC100_PHYCR_NEW_REGAD(x)	((x) & 0x1f)
43176338f1Sryan_chen #endif
44176338f1Sryan_chen 
45176338f1Sryan_chen /*
46176338f1Sryan_chen  * PHY data register
47176338f1Sryan_chen  */
48176338f1Sryan_chen #define FTGMAC100_PHYDATA_MIIWDATA(x)		((x) & 0xffff)
49176338f1Sryan_chen #define FTGMAC100_PHYDATA_MIIRDATA(phydata)	(((phydata) >> 16) & 0xffff)
50176338f1Sryan_chen 
51176338f1Sryan_chen #define FTGMAC100_PHYDATA_NEW_MIIWDATA(x)		((x) & 0xffff)
52176338f1Sryan_chen 
53176338f1Sryan_chen struct aspeed_mdio_regs {
54176338f1Sryan_chen 	unsigned int	phycr;
55176338f1Sryan_chen 	unsigned int	phydata;
56176338f1Sryan_chen };
57176338f1Sryan_chen 
aspeed_mdio_read(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr)58176338f1Sryan_chen extern int aspeed_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
59176338f1Sryan_chen 					int reg_addr)
60176338f1Sryan_chen {
61176338f1Sryan_chen 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
62176338f1Sryan_chen 	u32 phycr;
63176338f1Sryan_chen 	int i;
64176338f1Sryan_chen 
65176338f1Sryan_chen #if 1
66176338f1Sryan_chen 	phycr = FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | FTGMAC100_PHYCR_NEW_READ |
671b171c6cSryan_chen 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) |
681b171c6cSryan_chen 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr);
69176338f1Sryan_chen 
70176338f1Sryan_chen 	writel(phycr, &mdio_regs->phycr);
71176338f1Sryan_chen 	mb();
72176338f1Sryan_chen 
73176338f1Sryan_chen 	for (i = 0; i < 10; i++) {
74176338f1Sryan_chen 		phycr = readl(&mdio_regs->phycr);
75176338f1Sryan_chen 
76176338f1Sryan_chen 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
77176338f1Sryan_chen 			u32 data;
78176338f1Sryan_chen 
79176338f1Sryan_chen 			data = readl(&mdio_regs->phydata);
80176338f1Sryan_chen 			return FTGMAC100_PHYDATA_NEW_MIIWDATA(data);
81176338f1Sryan_chen 		}
82176338f1Sryan_chen 
83176338f1Sryan_chen 		mdelay(10);
84176338f1Sryan_chen 	}
85176338f1Sryan_chen #else
86176338f1Sryan_chen 	phycr = readl(&mdio_regs->phycr);
87176338f1Sryan_chen 
88176338f1Sryan_chen 	/* preserve MDC cycle threshold */
89176338f1Sryan_chen //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
90176338f1Sryan_chen 
91176338f1Sryan_chen 	phycr = FTGMAC100_PHYCR_PHYAD(addr)
92176338f1Sryan_chen 		  |  FTGMAC100_PHYCR_REGAD(reg)
93176338f1Sryan_chen 		  |  FTGMAC100_PHYCR_MIIRD | 0x34;
94176338f1Sryan_chen 
95176338f1Sryan_chen 	writel(phycr, &mdio_regs->phycr);
96176338f1Sryan_chen 
97176338f1Sryan_chen 	for (i = 0; i < 10; i++) {
98176338f1Sryan_chen 		phycr = readl(&mdio_regs->phycr);
99176338f1Sryan_chen 
100176338f1Sryan_chen 		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
101176338f1Sryan_chen 			int data;
102176338f1Sryan_chen 
103176338f1Sryan_chen 			data = readl(&mdio_regs->phydata);
104176338f1Sryan_chen 			return FTGMAC100_PHYDATA_MIIRDATA(data);
105176338f1Sryan_chen 		}
106176338f1Sryan_chen 
107176338f1Sryan_chen 		mdelay(10);
108176338f1Sryan_chen 	}
109176338f1Sryan_chen #endif
110176338f1Sryan_chen 	debug("mdio read timed out\n");
111176338f1Sryan_chen 	return -1;
112176338f1Sryan_chen 
113176338f1Sryan_chen }
114176338f1Sryan_chen 
aspeed_mdio_write(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr,u16 value)115176338f1Sryan_chen extern int aspeed_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
116176338f1Sryan_chen 				int reg_addr, u16 value)
117176338f1Sryan_chen {
118176338f1Sryan_chen 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
119176338f1Sryan_chen 	int phycr;
120176338f1Sryan_chen 	int i;
121176338f1Sryan_chen 
122176338f1Sryan_chen #ifdef CONFIG_MACH_ASPEED_G4
123176338f1Sryan_chen 	int data;
124176338f1Sryan_chen 
125176338f1Sryan_chen 	phycr = readl(&mdio_regs->phycr);
126176338f1Sryan_chen 
127176338f1Sryan_chen 	/* preserve MDC cycle threshold */
128176338f1Sryan_chen //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
129176338f1Sryan_chen 
130176338f1Sryan_chen 	phycr = FTGMAC100_PHYCR_PHYAD(phy_addr)
131176338f1Sryan_chen 		  |  FTGMAC100_PHYCR_REGAD(reg_addr)
132176338f1Sryan_chen 		  |  FTGMAC100_PHYCR_MIIWR | 0x34;
133176338f1Sryan_chen 
134176338f1Sryan_chen 	data = FTGMAC100_PHYDATA_MIIWDATA(value);
135176338f1Sryan_chen 
136176338f1Sryan_chen 	writel(data, &mdio_regs->phydata);
137176338f1Sryan_chen 	writel(phycr, &mdio_regs->phycr);
138176338f1Sryan_chen 
139176338f1Sryan_chen 	for (i = 0; i < 10; i++) {
140176338f1Sryan_chen 		phycr = readl(&mdio_regs->phycr);
141176338f1Sryan_chen 
142176338f1Sryan_chen 		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
143176338f1Sryan_chen 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
144176338f1Sryan_chen 				"phy_addr: %x\n", phy_addr);
145176338f1Sryan_chen 			return 0;
146176338f1Sryan_chen 		}
147176338f1Sryan_chen 
148176338f1Sryan_chen 		mdelay(1);
149176338f1Sryan_chen 	}
150176338f1Sryan_chen #else
151176338f1Sryan_chen 
152176338f1Sryan_chen 	phycr = FTGMAC100_PHYCR_NEW_WDATA(value) |
153176338f1Sryan_chen 			FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 |
154176338f1Sryan_chen 			FTGMAC100_PHYCR_NEW_WRITE |
155176338f1Sryan_chen 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) |
156176338f1Sryan_chen 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr);
157176338f1Sryan_chen 
158176338f1Sryan_chen 	writel(phycr, &mdio_regs->phycr);
159176338f1Sryan_chen 	mb();
160176338f1Sryan_chen 
161176338f1Sryan_chen 	for (i = 0; i < 10; i++) {
162176338f1Sryan_chen 		phycr = readl(&mdio_regs->phycr);
163176338f1Sryan_chen 
164176338f1Sryan_chen 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
165176338f1Sryan_chen 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
166176338f1Sryan_chen 				"phy_addr: %x\n", phy_addr);
167176338f1Sryan_chen 			return 0;
168176338f1Sryan_chen 		}
169176338f1Sryan_chen 
170176338f1Sryan_chen 		mdelay(10);
171176338f1Sryan_chen 	}
172176338f1Sryan_chen #endif
173176338f1Sryan_chen 	debug("mdio write timed out\n");
174176338f1Sryan_chen 
175176338f1Sryan_chen 	return -1;
176176338f1Sryan_chen }
1771b171c6cSryan_chen 
aspeed_mdio_probe(struct udevice * dev)1781b171c6cSryan_chen static int aspeed_mdio_probe(struct udevice *dev)
1791b171c6cSryan_chen {
180*0f02bc6aSryan_chen //	struct mii_dev *bus = (struct mii_dev *)dev_get_uclass_platdata(dev);
1811b171c6cSryan_chen 	struct reset_ctl reset_ctl;
1821b171c6cSryan_chen 	int ret = 0;
1831b171c6cSryan_chen 
1841b171c6cSryan_chen 	debug("%s(dev=%p) \n", __func__, dev);
1851b171c6cSryan_chen 
1861b171c6cSryan_chen 	ret = reset_get_by_index(dev, 0, &reset_ctl);
1871b171c6cSryan_chen 
1881b171c6cSryan_chen 	if (ret) {
1891b171c6cSryan_chen 		printf("%s(): Failed to get reset signal\n", __func__);
1901b171c6cSryan_chen 		return ret;
1911b171c6cSryan_chen 	}
1921b171c6cSryan_chen 
1931b171c6cSryan_chen 	reset_assert(&reset_ctl);
1941b171c6cSryan_chen 	reset_deassert(&reset_ctl);
1951b171c6cSryan_chen 
1961b171c6cSryan_chen 	return 0;
1971b171c6cSryan_chen }
1981b171c6cSryan_chen 
1991b171c6cSryan_chen static const struct udevice_id aspeed_mdio_ids[] = {
2001b171c6cSryan_chen 	{ .compatible = "aspeed,aspeed-mdio" },
2011b171c6cSryan_chen 	{ }
2021b171c6cSryan_chen };
2031b171c6cSryan_chen 
2041b171c6cSryan_chen U_BOOT_DRIVER(aspeed_mdio) = {
2051b171c6cSryan_chen 	.name		= "aspeed_mdio",
2061b171c6cSryan_chen 	.id			= UCLASS_MDIO,
2071b171c6cSryan_chen 	.of_match	= aspeed_mdio_ids,
2081b171c6cSryan_chen 	.probe		= aspeed_mdio_probe,
2091b171c6cSryan_chen 	.priv_auto_alloc_size = sizeof(struct mii_dev),
2101b171c6cSryan_chen };
2111b171c6cSryan_chen 
2121b171c6cSryan_chen 
213