xref: /openbmc/u-boot/drivers/net/aspeed_mdio.c (revision b0a2e3f1)
1 /*
2  * Copyright (C) ASPEED Technology Inc.
3  * Ryan Chen <ryan_chen@aspeedtech.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <miiphy.h>
10 #include <phy.h>
11 #include <asm/io.h>
12 #include <reset.h>
13 #include <linux/errno.h>
14 
15 /*
16  * PHY control register
17  */
18 #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0x3f
19 #define FTGMAC100_PHYCR_MDC_CYCTHR(x)	((x) & 0x3f)
20 #define FTGMAC100_PHYCR_PHYAD(x)	(((x) & 0x1f) << 16)
21 #define FTGMAC100_PHYCR_REGAD(x)	(((x) & 0x1f) << 21)
22 #define FTGMAC100_PHYCR_MIIRD		(1 << 26)
23 #define FTGMAC100_PHYCR_MIIWR		(1 << 27)
24 
25 #ifdef CONFIG_ASPEED_AST2600
26 //G6 MDC/MDIO
27 #define FTGMAC100_PHYCR_NEW_FIRE		BIT(31)
28 #define FTGMAC100_PHYCR_ST_22			BIT(28)
29 #define FTGMAC100_PHYCR_NEW_WRITE		BIT(26)
30 #define FTGMAC100_PHYCR_NEW_READ		BIT(27)
31 #define FTGMAC100_PHYCR_NEW_WDATA(x)	(x & 0xffff)
32 #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 21)
33 #define FTGMAC100_PHYCR_NEW_REGAD(x)	(((x) & 0x1f) << 16)
34 #else
35 //New MDC/MDIO
36 #define FTGMAC100_PHYCR_NEW_FIRE		BIT(15)
37 #define FTGMAC100_PHYCR_ST_22			BIT(12)
38 #define FTGMAC100_PHYCR_NEW_WRITE		BIT(10)
39 #define FTGMAC100_PHYCR_NEW_READ		BIT(11)
40 #define FTGMAC100_PHYCR_NEW_WDATA(x)	((x & 0xffff) << 16)
41 #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 5)
42 #define FTGMAC100_PHYCR_NEW_REGAD(x)	((x) & 0x1f)
43 #endif
44 
45 /*
46  * PHY data register
47  */
48 #define FTGMAC100_PHYDATA_MIIWDATA(x)		((x) & 0xffff)
49 #define FTGMAC100_PHYDATA_MIIRDATA(phydata)	(((phydata) >> 16) & 0xffff)
50 
51 #define FTGMAC100_PHYDATA_NEW_MIIWDATA(x)		((x) & 0xffff)
52 
53 struct aspeed_mdio_regs {
54 	unsigned int	phycr;
55 	unsigned int	phydata;
56 };
57 
58 extern int aspeed_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
59 					int reg_addr)
60 {
61 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
62 	u32 phycr;
63 	int i;
64 
65 #if 1
66 	phycr = FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | FTGMAC100_PHYCR_NEW_READ |
67 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) |
68 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr);
69 
70 	writel(phycr, &mdio_regs->phycr);
71 	mb();
72 
73 	for (i = 0; i < 10; i++) {
74 		phycr = readl(&mdio_regs->phycr);
75 
76 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
77 			u32 data;
78 
79 			data = readl(&mdio_regs->phydata);
80 			return FTGMAC100_PHYDATA_NEW_MIIWDATA(data);
81 		}
82 
83 		mdelay(10);
84 	}
85 #else
86 	phycr = readl(&mdio_regs->phycr);
87 
88 	/* preserve MDC cycle threshold */
89 //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
90 
91 	phycr = FTGMAC100_PHYCR_PHYAD(addr)
92 		  |  FTGMAC100_PHYCR_REGAD(reg)
93 		  |  FTGMAC100_PHYCR_MIIRD | 0x34;
94 
95 	writel(phycr, &mdio_regs->phycr);
96 
97 	for (i = 0; i < 10; i++) {
98 		phycr = readl(&mdio_regs->phycr);
99 
100 		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
101 			int data;
102 
103 			data = readl(&mdio_regs->phydata);
104 			return FTGMAC100_PHYDATA_MIIRDATA(data);
105 		}
106 
107 		mdelay(10);
108 	}
109 #endif
110 	debug("mdio read timed out\n");
111 	return -1;
112 
113 }
114 
115 extern int aspeed_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
116 				int reg_addr, u16 value)
117 {
118 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
119 	int phycr;
120 	int i;
121 
122 #ifdef CONFIG_MACH_ASPEED_G4
123 	int data;
124 
125 	phycr = readl(&mdio_regs->phycr);
126 
127 	/* preserve MDC cycle threshold */
128 //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
129 
130 	phycr = FTGMAC100_PHYCR_PHYAD(phy_addr)
131 		  |  FTGMAC100_PHYCR_REGAD(reg_addr)
132 		  |  FTGMAC100_PHYCR_MIIWR | 0x34;
133 
134 	data = FTGMAC100_PHYDATA_MIIWDATA(value);
135 
136 	writel(data, &mdio_regs->phydata);
137 	writel(phycr, &mdio_regs->phycr);
138 
139 	for (i = 0; i < 10; i++) {
140 		phycr = readl(&mdio_regs->phycr);
141 
142 		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
143 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
144 				"phy_addr: %x\n", phy_addr);
145 			return 0;
146 		}
147 
148 		mdelay(1);
149 	}
150 #else
151 
152 	phycr = FTGMAC100_PHYCR_NEW_WDATA(value) |
153 			FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 |
154 			FTGMAC100_PHYCR_NEW_WRITE |
155 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) |
156 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr);
157 
158 	writel(phycr, &mdio_regs->phycr);
159 	mb();
160 
161 	for (i = 0; i < 10; i++) {
162 		phycr = readl(&mdio_regs->phycr);
163 
164 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
165 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
166 				"phy_addr: %x\n", phy_addr);
167 			return 0;
168 		}
169 
170 		mdelay(10);
171 	}
172 #endif
173 	debug("mdio write timed out\n");
174 
175 	return -1;
176 }
177 
178 static int aspeed_mdio_probe(struct udevice *dev)
179 {
180 //	struct mii_dev *bus = (struct mii_dev *)dev_get_uclass_platdata(dev);
181 	struct reset_ctl reset_ctl;
182 	int ret = 0;
183 
184 	debug("%s(dev=%p) \n", __func__, dev);
185 
186 	ret = reset_get_by_index(dev, 0, &reset_ctl);
187 
188 	if (ret) {
189 		printf("%s(): Failed to get reset signal\n", __func__);
190 		return ret;
191 	}
192 
193 	reset_assert(&reset_ctl);
194 	reset_deassert(&reset_ctl);
195 
196 	return 0;
197 }
198 
199 static const struct udevice_id aspeed_mdio_ids[] = {
200 	{ .compatible = "aspeed,aspeed-mdio" },
201 	{ }
202 };
203 
204 U_BOOT_DRIVER(aspeed_mdio) = {
205 	.name		= "aspeed_mdio",
206 	.id			= UCLASS_MDIO,
207 	.of_match	= aspeed_mdio_ids,
208 	.probe		= aspeed_mdio_probe,
209 	.priv_auto_alloc_size = sizeof(struct mii_dev),
210 };
211 
212 
213