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