blob: 805dbd5865dcd9923733f5648c2f625440f64f80 [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
84static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
85{
86 int ret;
87
88 ret = genphy_read_abilities(phydev);
89 if (ret)
90 return ret;
91
developerd4abc8c2022-10-28 10:45:36 +080092 /* We don't support HDX at MAC layer on mt798x.
93 * So mask phy's HDX capabilities, too.
94 */
95 linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
developer2cdaeb12022-10-04 20:25:05 +080096 phydev->supported);
97 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
98 phydev->supported);
99 linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
100 phydev->supported);
101 linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
102 phydev->supported);
103 linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
104
105 return 0;
106}
107
developer284cd6e2022-12-15 22:19:39 +0800108static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
109{
110 int ret;
developer284cd6e2022-12-15 22:19:39 +0800111
developere7f61612022-12-30 11:34:52 +0800112 ret = genphy_update_link(phydev);
113 if (ret)
114 return ret;
developer284cd6e2022-12-15 22:19:39 +0800115
developere7f61612022-12-30 11:34:52 +0800116 phydev->speed = SPEED_UNKNOWN;
117 phydev->duplex = DUPLEX_UNKNOWN;
118 phydev->pause = 0;
119 phydev->asym_pause = 0;
developer284cd6e2022-12-15 22:19:39 +0800120
developere7f61612022-12-30 11:34:52 +0800121 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
122 ret = genphy_c45_read_lpa(phydev);
123 if (ret < 0)
124 return ret;
125
126 /* Read the link partner's 1G advertisement */
127 ret = phy_read(phydev, MII_STAT1000);
128 if (ret < 0)
129 return ret;
130 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
131 } else if (phydev->autoneg == AUTONEG_DISABLE) {
132 linkmode_zero(phydev->lp_advertising);
developer284cd6e2022-12-15 22:19:39 +0800133 }
134
developere7f61612022-12-30 11:34:52 +0800135 ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
136 if (ret < 0)
137 return ret;
138
139 /* Actually this phy supports only FDX */
140 phydev->duplex = (ret & PHY_AUX_DPX_MASK) ? DUPLEX_FULL : DUPLEX_HALF;
141 switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
142 case PHY_AUX_SPD_10:
developer284cd6e2022-12-15 22:19:39 +0800143 phydev->speed = SPEED_10;
developere7f61612022-12-30 11:34:52 +0800144 break;
145 case PHY_AUX_SPD_100:
146 phydev->speed = SPEED_100;
147 break;
148 case PHY_AUX_SPD_1000:
149 phydev->speed = SPEED_1000;
150 break;
151 case PHY_AUX_SPD_2500:
152 phydev->speed = SPEED_2500;
153 phydev->duplex = DUPLEX_FULL; /* 2.5G must be FDX */
154 break;
developer284cd6e2022-12-15 22:19:39 +0800155 }
156
developere7f61612022-12-30 11:34:52 +0800157 return 0;
developer284cd6e2022-12-15 22:19:39 +0800158}
159
developer2cdaeb12022-10-04 20:25:05 +0800160static struct phy_driver mtk_gephy_driver[] = {
161 {
162 PHY_ID_MATCH_EXACT(0x00339c11),
163 .name = "MediaTek MT798x 2.5GbE PHY",
164 .config_init = mt798x_2p5ge_phy_config_init,
165 .config_aneg = genphy_c45_config_aneg,
166 .get_features = mt798x_2p5ge_phy_get_features,
developer284cd6e2022-12-15 22:19:39 +0800167 .read_status = mt798x_2p5ge_phy_read_status,
developer2cdaeb12022-10-04 20:25:05 +0800168 //.config_intr = genphy_no_config_intr,
169 //.handle_interrupt = genphy_no_ack_interrupt,
170 //.suspend = genphy_suspend,
171 //.resume = genphy_resume,
172 },
173};
174
175module_phy_driver(mtk_gephy_driver);
176
177static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
178 { PHY_ID_MATCH_VENDOR(0x00339c00) },
179 { }
180};
181
182MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
183MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
184MODULE_LICENSE("GPL");
185
186MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);