blob: 30f53fcbbf6acf518b9b89cdb8008d731fc5b4ed [file] [log] [blame]
developer2cdaeb12022-10-04 20:25:05 +08001// SPDX-License-Identifier: GPL-2.0+
2#include <linux/bitfield.h>
3#include <linux/firmware.h>
4#include <linux/module.h>
5#include <linux/nvmem-consumer.h>
6#include <linux/of_address.h>
7#include <linux/of_platform.h>
8#include <linux/phy.h>
9
10#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek-2p5ge-phy-dmb.bin"
11#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek-2p5ge-phy-pmb.bin"
12
13#define MD32_EN_CFG 0x18
14#define MD32_EN BIT(0)
15
developer284cd6e2022-12-15 22:19:39 +080016#define BASE100T_STATUS_EXTEND (0x10)
17#define BASE1000T_STATUS_EXTEND (0x11)
18#define EXTEND_CTRL_AND_STATUS (0x16)
19
developere7f61612022-12-30 11:34:52 +080020#define PHY_AUX_CTRL_STATUS (0x1d)
21#define PHY_AUX_DPX_MASK GENMASK(5, 5)
22#define PHY_AUX_SPEED_MASK GENMASK(4, 2)
23
24enum {
25 PHY_AUX_SPD_10 = 0,
26 PHY_AUX_SPD_100,
27 PHY_AUX_SPD_1000,
28 PHY_AUX_SPD_2500,
29};
30
developer2cdaeb12022-10-04 20:25:05 +080031static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
32{
33 int ret;
34 int i;
35 const struct firmware *fw;
36 struct device *dev = &phydev->mdio.dev;
37 struct device_node *np;
38 void __iomem *dmb_addr;
39 void __iomem *pmb_addr;
40 void __iomem *mcucsr_base;
41 u16 reg;
42
43 np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
44 if (!np)
45 return -ENOENT;
46
47 dmb_addr = of_iomap(np, 0);
48 if (!dmb_addr)
49 return -ENOMEM;
50 pmb_addr = of_iomap(np, 1);
51 if (!pmb_addr)
52 return -ENOMEM;
53 mcucsr_base = of_iomap(np, 2);
54 if (!mcucsr_base)
55 return -ENOMEM;
56
57 ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev);
58 if (ret) {
59 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
60 MEDAITEK_2P5GE_PHY_DMB_FW, ret);
61 return ret;
62 }
63 for (i = 0; i < fw->size - 1; i += 4)
64 writel(*((uint32_t *)(fw->data + i)), dmb_addr + i);
65 release_firmware(fw);
66
67 ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev);
68 if (ret) {
69 dev_err(dev, "failed to load firmware: %s, ret: %d\n",
70 MEDIATEK_2P5GE_PHY_PMB_FW, ret);
71 return ret;
72 }
73 for (i = 0; i < fw->size - 1; i += 4)
74 writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
75 release_firmware(fw);
76
77 reg = readw(mcucsr_base + MD32_EN_CFG);
78 writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
79 dev_info(dev, "Firmware loading/trigger ok.\n");
80
81 return 0;
82}
83
developer1302b252022-12-30 19:04:55 +080084static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
85{
86 bool changed = false;
87 u32 adv;
88 int ret;
89
90 if (phydev->autoneg == AUTONEG_DISABLE) {
91 /* Configure half duplex with genphy_setup_forced,
92 * because genphy_c45_pma_setup_forced does not support.
93 */
94 return phydev->duplex != DUPLEX_FULL
95 ? genphy_setup_forced(phydev)
96 : genphy_c45_pma_setup_forced(phydev);
97 }
98
99 ret = genphy_c45_an_config_aneg(phydev);
100 if (ret < 0)
101 return ret;
102 if (ret > 0)
103 changed = true;
104
105 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
106 ret = phy_modify_changed(phydev, MII_CTRL1000,
107 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
108 adv);
109 if (ret < 0)
110 return ret;
111 if (ret > 0)
112 changed = true;
113
114 return genphy_c45_check_and_restart_aneg(phydev, changed);
115}
116
developer2cdaeb12022-10-04 20:25:05 +0800117static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
118{
119 int ret;
120
121 ret = genphy_read_abilities(phydev);
122 if (ret)
123 return ret;
124
developerd4abc8c2022-10-28 10:45:36 +0800125 /* We don't support HDX at MAC layer on mt798x.
126 * So mask phy's HDX capabilities, too.
127 */
128 linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
developer2cdaeb12022-10-04 20:25:05 +0800129 phydev->supported);
130 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
131 phydev->supported);
132 linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
133 phydev->supported);
134 linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
135 phydev->supported);
136 linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
137
138 return 0;
139}
140
developer284cd6e2022-12-15 22:19:39 +0800141static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
142{
143 int ret;
developer284cd6e2022-12-15 22:19:39 +0800144
developere7f61612022-12-30 11:34:52 +0800145 ret = genphy_update_link(phydev);
146 if (ret)
147 return ret;
developer284cd6e2022-12-15 22:19:39 +0800148
developere7f61612022-12-30 11:34:52 +0800149 phydev->speed = SPEED_UNKNOWN;
150 phydev->duplex = DUPLEX_UNKNOWN;
151 phydev->pause = 0;
152 phydev->asym_pause = 0;
developer284cd6e2022-12-15 22:19:39 +0800153
developere7f61612022-12-30 11:34:52 +0800154 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
155 ret = genphy_c45_read_lpa(phydev);
156 if (ret < 0)
157 return ret;
158
159 /* Read the link partner's 1G advertisement */
160 ret = phy_read(phydev, MII_STAT1000);
161 if (ret < 0)
162 return ret;
163 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
164 } else if (phydev->autoneg == AUTONEG_DISABLE) {
165 linkmode_zero(phydev->lp_advertising);
developer284cd6e2022-12-15 22:19:39 +0800166 }
167
developere7f61612022-12-30 11:34:52 +0800168 ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
169 if (ret < 0)
170 return ret;
171
172 /* Actually this phy supports only FDX */
173 phydev->duplex = (ret & PHY_AUX_DPX_MASK) ? DUPLEX_FULL : DUPLEX_HALF;
174 switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
175 case PHY_AUX_SPD_10:
developer284cd6e2022-12-15 22:19:39 +0800176 phydev->speed = SPEED_10;
developere7f61612022-12-30 11:34:52 +0800177 break;
178 case PHY_AUX_SPD_100:
179 phydev->speed = SPEED_100;
180 break;
181 case PHY_AUX_SPD_1000:
182 phydev->speed = SPEED_1000;
183 break;
184 case PHY_AUX_SPD_2500:
185 phydev->speed = SPEED_2500;
186 phydev->duplex = DUPLEX_FULL; /* 2.5G must be FDX */
187 break;
developer284cd6e2022-12-15 22:19:39 +0800188 }
189
developere7f61612022-12-30 11:34:52 +0800190 return 0;
developer284cd6e2022-12-15 22:19:39 +0800191}
192
developer2cdaeb12022-10-04 20:25:05 +0800193static struct phy_driver mtk_gephy_driver[] = {
194 {
195 PHY_ID_MATCH_EXACT(0x00339c11),
196 .name = "MediaTek MT798x 2.5GbE PHY",
197 .config_init = mt798x_2p5ge_phy_config_init,
developer1302b252022-12-30 19:04:55 +0800198 .config_aneg = mt798x_2p5ge_phy_config_aneg,
developer2cdaeb12022-10-04 20:25:05 +0800199 .get_features = mt798x_2p5ge_phy_get_features,
developer284cd6e2022-12-15 22:19:39 +0800200 .read_status = mt798x_2p5ge_phy_read_status,
developer2cdaeb12022-10-04 20:25:05 +0800201 //.config_intr = genphy_no_config_intr,
202 //.handle_interrupt = genphy_no_ack_interrupt,
203 //.suspend = genphy_suspend,
204 //.resume = genphy_resume,
205 },
206};
207
208module_phy_driver(mtk_gephy_driver);
209
210static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
211 { PHY_ID_MATCH_VENDOR(0x00339c00) },
212 { }
213};
214
215MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
216MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
217MODULE_LICENSE("GPL");
218
219MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);