xref: /openbmc/u-boot/drivers/net/aspeed_mdio.c (revision e6b48dfde594339538ac59361a838ab3b3d7fdd8)
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 <linux/errno.h>
13 
14 /*
15  * PHY control register
16  */
17 #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0x3f
18 #define FTGMAC100_PHYCR_MDC_CYCTHR(x)	((x) & 0x3f)
19 #define FTGMAC100_PHYCR_PHYAD(x)	(((x) & 0x1f) << 16)
20 #define FTGMAC100_PHYCR_REGAD(x)	(((x) & 0x1f) << 21)
21 #define FTGMAC100_PHYCR_MIIRD		(1 << 26)
22 #define FTGMAC100_PHYCR_MIIWR		(1 << 27)
23 
24 #ifdef CONFIG_MACH_ASPEED_G6
25 //G6 MDC/MDIO
26 #define FTGMAC100_PHYCR_NEW_FIRE		BIT(31)
27 #define FTGMAC100_PHYCR_ST_22			BIT(28)
28 #define FTGMAC100_PHYCR_NEW_WRITE		BIT(26)
29 #define FTGMAC100_PHYCR_NEW_READ		BIT(27)
30 #define FTGMAC100_PHYCR_NEW_WDATA(x)	(x & 0xffff)
31 #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 21)
32 #define FTGMAC100_PHYCR_NEW_REGAD(x)	(((x) & 0x1f) << 16)
33 #else
34 //New MDC/MDIO
35 #define FTGMAC100_PHYCR_NEW_FIRE		BIT(15)
36 #define FTGMAC100_PHYCR_ST_22			BIT(12)
37 #define FTGMAC100_PHYCR_NEW_WRITE		BIT(10)
38 #define FTGMAC100_PHYCR_NEW_READ		BIT(11)
39 #define FTGMAC100_PHYCR_NEW_WDATA(x)	((x & 0xffff) << 16)
40 #define FTGMAC100_PHYCR_NEW_PHYAD(x)	(((x) & 0x1f) << 5)
41 #define FTGMAC100_PHYCR_NEW_REGAD(x)	((x) & 0x1f)
42 #endif
43 
44 /*
45  * PHY data register
46  */
47 #define FTGMAC100_PHYDATA_MIIWDATA(x)		((x) & 0xffff)
48 #define FTGMAC100_PHYDATA_MIIRDATA(phydata)	(((phydata) >> 16) & 0xffff)
49 
50 #define FTGMAC100_PHYDATA_NEW_MIIWDATA(x)		((x) & 0xffff)
51 
52 struct aspeed_mdio_regs {
53 	unsigned int	phycr;
54 	unsigned int	phydata;
55 };
56 
57 extern int aspeed_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
58 					int reg_addr)
59 {
60 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
61 	u32 phycr;
62 	int i;
63 
64 #if 1
65 	phycr = FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 | FTGMAC100_PHYCR_NEW_READ |
66 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) | // 20141114
67 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr); // 20141114
68 
69 	writel(phycr, &mdio_regs->phycr);
70 	mb();
71 
72 	for (i = 0; i < 10; i++) {
73 		phycr = readl(&mdio_regs->phycr);
74 
75 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
76 			u32 data;
77 
78 			data = readl(&mdio_regs->phydata);
79 			return FTGMAC100_PHYDATA_NEW_MIIWDATA(data);
80 		}
81 
82 		mdelay(10);
83 	}
84 #else
85 	phycr = readl(&mdio_regs->phycr);
86 
87 	/* preserve MDC cycle threshold */
88 //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
89 
90 	phycr = FTGMAC100_PHYCR_PHYAD(addr)
91 		  |  FTGMAC100_PHYCR_REGAD(reg)
92 		  |  FTGMAC100_PHYCR_MIIRD | 0x34;
93 
94 	writel(phycr, &mdio_regs->phycr);
95 
96 	for (i = 0; i < 10; i++) {
97 		phycr = readl(&mdio_regs->phycr);
98 
99 		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
100 			int data;
101 
102 			data = readl(&mdio_regs->phydata);
103 			return FTGMAC100_PHYDATA_MIIRDATA(data);
104 		}
105 
106 		mdelay(10);
107 	}
108 #endif
109 	debug("mdio read timed out\n");
110 	return -1;
111 
112 }
113 
114 extern int aspeed_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
115 				int reg_addr, u16 value)
116 {
117 	struct aspeed_mdio_regs __iomem *mdio_regs = (struct aspeed_mdio_regs __iomem *)bus->priv;
118 	int phycr;
119 	int i;
120 
121 #ifdef CONFIG_MACH_ASPEED_G4
122 	int data;
123 
124 	phycr = readl(&mdio_regs->phycr);
125 
126 	/* preserve MDC cycle threshold */
127 //	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
128 
129 	phycr = FTGMAC100_PHYCR_PHYAD(phy_addr)
130 		  |  FTGMAC100_PHYCR_REGAD(reg_addr)
131 		  |  FTGMAC100_PHYCR_MIIWR | 0x34;
132 
133 	data = FTGMAC100_PHYDATA_MIIWDATA(value);
134 
135 	writel(data, &mdio_regs->phydata);
136 	writel(phycr, &mdio_regs->phycr);
137 
138 	for (i = 0; i < 10; i++) {
139 		phycr = readl(&mdio_regs->phycr);
140 
141 		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
142 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
143 				"phy_addr: %x\n", phy_addr);
144 			return 0;
145 		}
146 
147 		mdelay(1);
148 	}
149 #else
150 
151 	phycr = FTGMAC100_PHYCR_NEW_WDATA(value) |
152 			FTGMAC100_PHYCR_NEW_FIRE | FTGMAC100_PHYCR_ST_22 |
153 			FTGMAC100_PHYCR_NEW_WRITE |
154 			FTGMAC100_PHYCR_NEW_PHYAD(phy_addr) |
155 			FTGMAC100_PHYCR_NEW_REGAD(reg_addr);
156 
157 	writel(phycr, &mdio_regs->phycr);
158 	mb();
159 
160 	for (i = 0; i < 10; i++) {
161 		phycr = readl(&mdio_regs->phycr);
162 
163 		if ((phycr & FTGMAC100_PHYCR_NEW_FIRE) == 0) {
164 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
165 				"phy_addr: %x\n", phy_addr);
166 			return 0;
167 		}
168 
169 		mdelay(10);
170 	}
171 #endif
172 	debug("mdio write timed out\n");
173 
174 	return -1;
175 }
176