1f7c38cf8SShaohui Xie /*
2f7c38cf8SShaohui Xie * Aquantia PHY drivers
3f7c38cf8SShaohui Xie *
4f7c38cf8SShaohui Xie * SPDX-License-Identifier: GPL-2.0+
5f7c38cf8SShaohui Xie *
6f7c38cf8SShaohui Xie * Copyright 2014 Freescale Semiconductor, Inc.
7f7c38cf8SShaohui Xie */
8f7c38cf8SShaohui Xie #include <config.h>
9f7c38cf8SShaohui Xie #include <common.h>
10f7c38cf8SShaohui Xie #include <phy.h>
11f7c38cf8SShaohui Xie
12f7c38cf8SShaohui Xie #ifndef CONFIG_PHYLIB_10G
13f7c38cf8SShaohui Xie #error The Aquantia PHY needs 10G support
14f7c38cf8SShaohui Xie #endif
15f7c38cf8SShaohui Xie
16f7c38cf8SShaohui Xie #define AQUNTIA_10G_CTL 0x20
17f7c38cf8SShaohui Xie #define AQUNTIA_VENDOR_P1 0xc400
18f7c38cf8SShaohui Xie
19f7c38cf8SShaohui Xie #define AQUNTIA_SPEED_LSB_MASK 0x2000
20f7c38cf8SShaohui Xie #define AQUNTIA_SPEED_MSB_MASK 0x40
21f7c38cf8SShaohui Xie
aquantia_config(struct phy_device * phydev)22f7c38cf8SShaohui Xie int aquantia_config(struct phy_device *phydev)
23f7c38cf8SShaohui Xie {
24f7c38cf8SShaohui Xie u32 val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
25f7c38cf8SShaohui Xie
26f7c38cf8SShaohui Xie if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
27f7c38cf8SShaohui Xie /* 1000BASE-T mode */
28f7c38cf8SShaohui Xie phydev->advertising = SUPPORTED_1000baseT_Full;
29f7c38cf8SShaohui Xie phydev->supported = phydev->advertising;
30f7c38cf8SShaohui Xie
31f7c38cf8SShaohui Xie val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK;
32f7c38cf8SShaohui Xie phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
33f7c38cf8SShaohui Xie } else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) {
34f7c38cf8SShaohui Xie /* 10GBASE-T mode */
35f7c38cf8SShaohui Xie phydev->advertising = SUPPORTED_10000baseT_Full;
36f7c38cf8SShaohui Xie phydev->supported = phydev->advertising;
37f7c38cf8SShaohui Xie
38f7c38cf8SShaohui Xie if (!(val & AQUNTIA_SPEED_LSB_MASK) ||
39f7c38cf8SShaohui Xie !(val & AQUNTIA_SPEED_MSB_MASK))
40f7c38cf8SShaohui Xie phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR,
41f7c38cf8SShaohui Xie AQUNTIA_SPEED_LSB_MASK |
42f7c38cf8SShaohui Xie AQUNTIA_SPEED_MSB_MASK);
43f7c38cf8SShaohui Xie } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) {
44f7c38cf8SShaohui Xie /* 2.5GBASE-T mode */
45f7c38cf8SShaohui Xie phydev->advertising = SUPPORTED_1000baseT_Full;
46f7c38cf8SShaohui Xie phydev->supported = phydev->advertising;
47f7c38cf8SShaohui Xie
48f7c38cf8SShaohui Xie phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1);
49f7c38cf8SShaohui Xie phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440);
50f7c38cf8SShaohui Xie } else if (phydev->interface == PHY_INTERFACE_MODE_MII) {
51f7c38cf8SShaohui Xie /* 100BASE-TX mode */
52f7c38cf8SShaohui Xie phydev->advertising = SUPPORTED_100baseT_Full;
53f7c38cf8SShaohui Xie phydev->supported = phydev->advertising;
54f7c38cf8SShaohui Xie
55f7c38cf8SShaohui Xie val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK;
56f7c38cf8SShaohui Xie phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val);
57f7c38cf8SShaohui Xie }
58f7c38cf8SShaohui Xie return 0;
59f7c38cf8SShaohui Xie }
60f7c38cf8SShaohui Xie
aquantia_startup(struct phy_device * phydev)61f7c38cf8SShaohui Xie int aquantia_startup(struct phy_device *phydev)
62f7c38cf8SShaohui Xie {
63f7c38cf8SShaohui Xie u32 reg, speed;
64f7c38cf8SShaohui Xie int i = 0;
65f7c38cf8SShaohui Xie
66f7c38cf8SShaohui Xie phydev->duplex = DUPLEX_FULL;
67f7c38cf8SShaohui Xie
68f7c38cf8SShaohui Xie /* if the AN is still in progress, wait till timeout. */
69f7c38cf8SShaohui Xie phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
70f7c38cf8SShaohui Xie reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
71f7c38cf8SShaohui Xie if (!(reg & MDIO_AN_STAT1_COMPLETE)) {
72f7c38cf8SShaohui Xie printf("%s Waiting for PHY auto negotiation to complete",
73f7c38cf8SShaohui Xie phydev->dev->name);
74f7c38cf8SShaohui Xie do {
75f7c38cf8SShaohui Xie udelay(1000);
76f7c38cf8SShaohui Xie reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
77f7c38cf8SShaohui Xie if ((i++ % 500) == 0)
78f7c38cf8SShaohui Xie printf(".");
79f7c38cf8SShaohui Xie } while (!(reg & MDIO_AN_STAT1_COMPLETE) &&
80f7c38cf8SShaohui Xie i < (4 * PHY_ANEG_TIMEOUT));
81f7c38cf8SShaohui Xie
82f7c38cf8SShaohui Xie if (i > PHY_ANEG_TIMEOUT)
83f7c38cf8SShaohui Xie printf(" TIMEOUT !\n");
84f7c38cf8SShaohui Xie }
85f7c38cf8SShaohui Xie
86f7c38cf8SShaohui Xie /* Read twice because link state is latched and a
87f7c38cf8SShaohui Xie * read moves the current state into the register */
88f7c38cf8SShaohui Xie phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
89f7c38cf8SShaohui Xie reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1);
90f7c38cf8SShaohui Xie if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
91f7c38cf8SShaohui Xie phydev->link = 0;
92f7c38cf8SShaohui Xie else
93f7c38cf8SShaohui Xie phydev->link = 1;
94f7c38cf8SShaohui Xie
95f7c38cf8SShaohui Xie speed = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR);
96f7c38cf8SShaohui Xie if (speed & AQUNTIA_SPEED_MSB_MASK) {
97f7c38cf8SShaohui Xie if (speed & AQUNTIA_SPEED_LSB_MASK)
98f7c38cf8SShaohui Xie phydev->speed = SPEED_10000;
99f7c38cf8SShaohui Xie else
100f7c38cf8SShaohui Xie phydev->speed = SPEED_1000;
101f7c38cf8SShaohui Xie } else {
102f7c38cf8SShaohui Xie if (speed & AQUNTIA_SPEED_LSB_MASK)
103f7c38cf8SShaohui Xie phydev->speed = SPEED_100;
104f7c38cf8SShaohui Xie else
105f7c38cf8SShaohui Xie phydev->speed = SPEED_10;
106f7c38cf8SShaohui Xie }
107f7c38cf8SShaohui Xie
108f7c38cf8SShaohui Xie return 0;
109f7c38cf8SShaohui Xie }
110f7c38cf8SShaohui Xie
111f7c38cf8SShaohui Xie struct phy_driver aq1202_driver = {
112f7c38cf8SShaohui Xie .name = "Aquantia AQ1202",
113f7c38cf8SShaohui Xie .uid = 0x3a1b445,
114f7c38cf8SShaohui Xie .mask = 0xfffffff0,
115f7c38cf8SShaohui Xie .features = PHY_10G_FEATURES,
116f7c38cf8SShaohui Xie .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
117f7c38cf8SShaohui Xie MDIO_MMD_PHYXS | MDIO_MMD_AN |
118f7c38cf8SShaohui Xie MDIO_MMD_VEND1),
119f7c38cf8SShaohui Xie .config = &aquantia_config,
120f7c38cf8SShaohui Xie .startup = &aquantia_startup,
121f7c38cf8SShaohui Xie .shutdown = &gen10g_shutdown,
122f7c38cf8SShaohui Xie };
123f7c38cf8SShaohui Xie
124f7c38cf8SShaohui Xie struct phy_driver aq2104_driver = {
125f7c38cf8SShaohui Xie .name = "Aquantia AQ2104",
126f7c38cf8SShaohui Xie .uid = 0x3a1b460,
127f7c38cf8SShaohui Xie .mask = 0xfffffff0,
128f7c38cf8SShaohui Xie .features = PHY_10G_FEATURES,
129f7c38cf8SShaohui Xie .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
130f7c38cf8SShaohui Xie MDIO_MMD_PHYXS | MDIO_MMD_AN |
131f7c38cf8SShaohui Xie MDIO_MMD_VEND1),
132f7c38cf8SShaohui Xie .config = &aquantia_config,
133f7c38cf8SShaohui Xie .startup = &aquantia_startup,
134f7c38cf8SShaohui Xie .shutdown = &gen10g_shutdown,
135f7c38cf8SShaohui Xie };
136f7c38cf8SShaohui Xie
137f7c38cf8SShaohui Xie struct phy_driver aqr105_driver = {
138f7c38cf8SShaohui Xie .name = "Aquantia AQR105",
139f7c38cf8SShaohui Xie .uid = 0x3a1b4a2,
140f7c38cf8SShaohui Xie .mask = 0xfffffff0,
141f7c38cf8SShaohui Xie .features = PHY_10G_FEATURES,
142f7c38cf8SShaohui Xie .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
143f7c38cf8SShaohui Xie MDIO_MMD_PHYXS | MDIO_MMD_AN |
144f7c38cf8SShaohui Xie MDIO_MMD_VEND1),
145f7c38cf8SShaohui Xie .config = &aquantia_config,
146f7c38cf8SShaohui Xie .startup = &aquantia_startup,
147f7c38cf8SShaohui Xie .shutdown = &gen10g_shutdown,
148f7c38cf8SShaohui Xie };
149f8642ba6SShaohui Xie
150*19c9ddaaSMingkai Hu struct phy_driver aqr106_driver = {
151*19c9ddaaSMingkai Hu .name = "Aquantia AQR106",
152*19c9ddaaSMingkai Hu .uid = 0x3a1b4d0,
153*19c9ddaaSMingkai Hu .mask = 0xfffffff0,
154*19c9ddaaSMingkai Hu .features = PHY_10G_FEATURES,
155*19c9ddaaSMingkai Hu .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
156*19c9ddaaSMingkai Hu MDIO_MMD_PHYXS | MDIO_MMD_AN |
157*19c9ddaaSMingkai Hu MDIO_MMD_VEND1),
158*19c9ddaaSMingkai Hu .config = &aquantia_config,
159*19c9ddaaSMingkai Hu .startup = &aquantia_startup,
160*19c9ddaaSMingkai Hu .shutdown = &gen10g_shutdown,
161*19c9ddaaSMingkai Hu };
162*19c9ddaaSMingkai Hu
163*19c9ddaaSMingkai Hu struct phy_driver aqr107_driver = {
164*19c9ddaaSMingkai Hu .name = "Aquantia AQR107",
165*19c9ddaaSMingkai Hu .uid = 0x3a1b4e0,
166*19c9ddaaSMingkai Hu .mask = 0xfffffff0,
167*19c9ddaaSMingkai Hu .features = PHY_10G_FEATURES,
168*19c9ddaaSMingkai Hu .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
169*19c9ddaaSMingkai Hu MDIO_MMD_PHYXS | MDIO_MMD_AN |
170*19c9ddaaSMingkai Hu MDIO_MMD_VEND1),
171*19c9ddaaSMingkai Hu .config = &aquantia_config,
172*19c9ddaaSMingkai Hu .startup = &aquantia_startup,
173*19c9ddaaSMingkai Hu .shutdown = &gen10g_shutdown,
174*19c9ddaaSMingkai Hu };
175*19c9ddaaSMingkai Hu
176f8642ba6SShaohui Xie struct phy_driver aqr405_driver = {
177f8642ba6SShaohui Xie .name = "Aquantia AQR405",
178f8642ba6SShaohui Xie .uid = 0x3a1b4b2,
179f8642ba6SShaohui Xie .mask = 0xfffffff0,
180f8642ba6SShaohui Xie .features = PHY_10G_FEATURES,
181f8642ba6SShaohui Xie .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
182f8642ba6SShaohui Xie MDIO_MMD_PHYXS | MDIO_MMD_AN |
183f8642ba6SShaohui Xie MDIO_MMD_VEND1),
184f8642ba6SShaohui Xie .config = &aquantia_config,
185f8642ba6SShaohui Xie .startup = &aquantia_startup,
186f8642ba6SShaohui Xie .shutdown = &gen10g_shutdown,
187f8642ba6SShaohui Xie };
188f8642ba6SShaohui Xie
phy_aquantia_init(void)189f7c38cf8SShaohui Xie int phy_aquantia_init(void)
190f7c38cf8SShaohui Xie {
191f7c38cf8SShaohui Xie phy_register(&aq1202_driver);
192f7c38cf8SShaohui Xie phy_register(&aq2104_driver);
193f7c38cf8SShaohui Xie phy_register(&aqr105_driver);
194*19c9ddaaSMingkai Hu phy_register(&aqr106_driver);
195*19c9ddaaSMingkai Hu phy_register(&aqr107_driver);
196f8642ba6SShaohui Xie phy_register(&aqr405_driver);
197f7c38cf8SShaohui Xie
198f7c38cf8SShaohui Xie return 0;
199f7c38cf8SShaohui Xie }
200