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
aspeed_mdio_read(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr)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
aspeed_mdio_write(struct mii_dev * bus,int phy_addr,int dev_addr,int reg_addr,u16 value)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
aspeed_mdio_probe(struct udevice * dev)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