1*26948c24SSky Huang // SPDX-License-Identifier: GPL-2.0+
2*26948c24SSky Huang #include <linux/bitfield.h>
3*26948c24SSky Huang #include <linux/firmware.h>
4*26948c24SSky Huang #include <linux/module.h>
5*26948c24SSky Huang #include <linux/of_address.h>
6*26948c24SSky Huang #include <linux/of_platform.h>
7*26948c24SSky Huang #include <linux/pinctrl/consumer.h>
8*26948c24SSky Huang #include <linux/phy.h>
9*26948c24SSky Huang
10*26948c24SSky Huang #include "mtk.h"
11*26948c24SSky Huang
12*26948c24SSky Huang #define MTK_2P5GPHY_ID_MT7988 0x00339c11
13*26948c24SSky Huang
14*26948c24SSky Huang #define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin"
15*26948c24SSky Huang #define MT7988_2P5GE_PMB_FW_SIZE 0x20000
16*26948c24SSky Huang #define MT7988_2P5GE_PMB_FW_BASE 0x0f100000
17*26948c24SSky Huang #define MT7988_2P5GE_PMB_FW_LEN 0x20000
18*26948c24SSky Huang #define MTK_2P5GPHY_MCU_CSR_BASE 0x0f0f0000
19*26948c24SSky Huang #define MTK_2P5GPHY_MCU_CSR_LEN 0x20
20*26948c24SSky Huang #define MD32_EN_CFG 0x18
21*26948c24SSky Huang #define MD32_EN BIT(0)
22*26948c24SSky Huang
23*26948c24SSky Huang #define BASE100T_STATUS_EXTEND 0x10
24*26948c24SSky Huang #define BASE1000T_STATUS_EXTEND 0x11
25*26948c24SSky Huang #define EXTEND_CTRL_AND_STATUS 0x16
26*26948c24SSky Huang
27*26948c24SSky Huang #define PHY_AUX_CTRL_STATUS 0x1d
28*26948c24SSky Huang #define PHY_AUX_DPX_MASK GENMASK(5, 5)
29*26948c24SSky Huang #define PHY_AUX_SPEED_MASK GENMASK(4, 2)
30*26948c24SSky Huang
31*26948c24SSky Huang /* Registers on MDIO_MMD_VEND1 */
32*26948c24SSky Huang #define MTK_PHY_LPI_PCS_DSP_CTRL 0x121
33*26948c24SSky Huang #define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8)
34*26948c24SSky Huang
35*26948c24SSky Huang #define MTK_PHY_HOST_CMD1 0x800e
36*26948c24SSky Huang #define MTK_PHY_HOST_CMD2 0x800f
37*26948c24SSky Huang /* Registers on Token Ring debug nodes */
38*26948c24SSky Huang /* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
39*26948c24SSky Huang #define AUTO_NP_10XEN BIT(6)
40*26948c24SSky Huang
41*26948c24SSky Huang enum {
42*26948c24SSky Huang PHY_AUX_SPD_10 = 0,
43*26948c24SSky Huang PHY_AUX_SPD_100,
44*26948c24SSky Huang PHY_AUX_SPD_1000,
45*26948c24SSky Huang PHY_AUX_SPD_2500,
46*26948c24SSky Huang };
47*26948c24SSky Huang
mt798x_2p5ge_phy_load_fw(struct phy_device * phydev)48*26948c24SSky Huang static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev)
49*26948c24SSky Huang {
50*26948c24SSky Huang struct device *dev = &phydev->mdio.dev;
51*26948c24SSky Huang void __iomem *mcu_csr_base, *pmb_addr;
52*26948c24SSky Huang const struct firmware *fw;
53*26948c24SSky Huang int ret, i;
54*26948c24SSky Huang u32 reg;
55*26948c24SSky Huang
56*26948c24SSky Huang pmb_addr = ioremap(MT7988_2P5GE_PMB_FW_BASE, MT7988_2P5GE_PMB_FW_LEN);
57*26948c24SSky Huang if (!pmb_addr)
58*26948c24SSky Huang return -ENOMEM;
59*26948c24SSky Huang mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE,
60*26948c24SSky Huang MTK_2P5GPHY_MCU_CSR_LEN);
61*26948c24SSky Huang if (!mcu_csr_base) {
62*26948c24SSky Huang ret = -ENOMEM;
63*26948c24SSky Huang goto free_pmb;
64*26948c24SSky Huang }
65*26948c24SSky Huang
66*26948c24SSky Huang ret = request_firmware_direct(&fw, MT7988_2P5GE_PMB_FW, dev);
67*26948c24SSky Huang if (ret) {
68*26948c24SSky Huang dev_err(dev, "failed to load firmware: %s, ret: %d\n",
69*26948c24SSky Huang MT7988_2P5GE_PMB_FW, ret);
70*26948c24SSky Huang goto free;
71*26948c24SSky Huang }
72*26948c24SSky Huang
73*26948c24SSky Huang if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) {
74*26948c24SSky Huang dev_err(dev, "Firmware size 0x%zx != 0x%x\n",
75*26948c24SSky Huang fw->size, MT7988_2P5GE_PMB_FW_SIZE);
76*26948c24SSky Huang ret = -EINVAL;
77*26948c24SSky Huang goto release_fw;
78*26948c24SSky Huang }
79*26948c24SSky Huang
80*26948c24SSky Huang reg = readw(mcu_csr_base + MD32_EN_CFG);
81*26948c24SSky Huang if (reg & MD32_EN) {
82*26948c24SSky Huang phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
83*26948c24SSky Huang usleep_range(10000, 11000);
84*26948c24SSky Huang }
85*26948c24SSky Huang phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
86*26948c24SSky Huang
87*26948c24SSky Huang /* Write magic number to safely stall MCU */
88*26948c24SSky Huang phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD1, 0x1100);
89*26948c24SSky Huang phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD2, 0x00df);
90*26948c24SSky Huang
91*26948c24SSky Huang for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4)
92*26948c24SSky Huang writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
93*26948c24SSky Huang
94*26948c24SSky Huang writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG);
95*26948c24SSky Huang writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG);
96*26948c24SSky Huang phy_set_bits(phydev, MII_BMCR, BMCR_RESET);
97*26948c24SSky Huang /* We need a delay here to stabilize initialization of MCU */
98*26948c24SSky Huang usleep_range(7000, 8000);
99*26948c24SSky Huang
100*26948c24SSky Huang dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n",
101*26948c24SSky Huang be16_to_cpu(*((__be16 *)(fw->data +
102*26948c24SSky Huang MT7988_2P5GE_PMB_FW_SIZE - 8))),
103*26948c24SSky Huang *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6),
104*26948c24SSky Huang *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5),
105*26948c24SSky Huang *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2),
106*26948c24SSky Huang *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1));
107*26948c24SSky Huang
108*26948c24SSky Huang release_fw:
109*26948c24SSky Huang release_firmware(fw);
110*26948c24SSky Huang free:
111*26948c24SSky Huang iounmap(mcu_csr_base);
112*26948c24SSky Huang free_pmb:
113*26948c24SSky Huang iounmap(pmb_addr);
114*26948c24SSky Huang
115*26948c24SSky Huang return ret;
116*26948c24SSky Huang }
117*26948c24SSky Huang
mt798x_2p5ge_phy_config_init(struct phy_device * phydev)118*26948c24SSky Huang static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
119*26948c24SSky Huang {
120*26948c24SSky Huang /* Check if PHY interface type is compatible */
121*26948c24SSky Huang if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
122*26948c24SSky Huang return -ENODEV;
123*26948c24SSky Huang
124*26948c24SSky Huang phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
125*26948c24SSky Huang MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
126*26948c24SSky Huang
127*26948c24SSky Huang /* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */
128*26948c24SSky Huang mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN,
129*26948c24SSky Huang FIELD_PREP(AUTO_NP_10XEN, 0x1));
130*26948c24SSky Huang
131*26948c24SSky Huang /* Enable HW auto downshift */
132*26948c24SSky Huang phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1,
133*26948c24SSky Huang MTK_PHY_AUX_CTRL_AND_STATUS,
134*26948c24SSky Huang 0, MTK_PHY_ENABLE_DOWNSHIFT);
135*26948c24SSky Huang
136*26948c24SSky Huang return 0;
137*26948c24SSky Huang }
138*26948c24SSky Huang
mt798x_2p5ge_phy_config_aneg(struct phy_device * phydev)139*26948c24SSky Huang static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
140*26948c24SSky Huang {
141*26948c24SSky Huang bool changed = false;
142*26948c24SSky Huang u32 adv;
143*26948c24SSky Huang int ret;
144*26948c24SSky Huang
145*26948c24SSky Huang ret = genphy_c45_an_config_aneg(phydev);
146*26948c24SSky Huang if (ret < 0)
147*26948c24SSky Huang return ret;
148*26948c24SSky Huang if (ret > 0)
149*26948c24SSky Huang changed = true;
150*26948c24SSky Huang
151*26948c24SSky Huang /* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in
152*26948c24SSky Huang * our design.
153*26948c24SSky Huang */
154*26948c24SSky Huang adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
155*26948c24SSky Huang ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv);
156*26948c24SSky Huang if (ret < 0)
157*26948c24SSky Huang return ret;
158*26948c24SSky Huang if (ret > 0)
159*26948c24SSky Huang changed = true;
160*26948c24SSky Huang
161*26948c24SSky Huang return genphy_c45_check_and_restart_aneg(phydev, changed);
162*26948c24SSky Huang }
163*26948c24SSky Huang
mt798x_2p5ge_phy_get_features(struct phy_device * phydev)164*26948c24SSky Huang static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
165*26948c24SSky Huang {
166*26948c24SSky Huang int ret;
167*26948c24SSky Huang
168*26948c24SSky Huang ret = genphy_c45_pma_read_abilities(phydev);
169*26948c24SSky Huang if (ret)
170*26948c24SSky Huang return ret;
171*26948c24SSky Huang
172*26948c24SSky Huang /* This phy can't handle collision, and neither can (XFI)MAC it's
173*26948c24SSky Huang * connected to. Although it can do HDX handshake, it doesn't support
174*26948c24SSky Huang * CSMA/CD that HDX requires.
175*26948c24SSky Huang */
176*26948c24SSky Huang linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
177*26948c24SSky Huang phydev->supported);
178*26948c24SSky Huang
179*26948c24SSky Huang return 0;
180*26948c24SSky Huang }
181*26948c24SSky Huang
mt798x_2p5ge_phy_read_status(struct phy_device * phydev)182*26948c24SSky Huang static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
183*26948c24SSky Huang {
184*26948c24SSky Huang int ret;
185*26948c24SSky Huang
186*26948c24SSky Huang /* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy
187*26948c24SSky Huang * actually hasn't finished AN. So use CL22's link update function
188*26948c24SSky Huang * instead.
189*26948c24SSky Huang */
190*26948c24SSky Huang ret = genphy_update_link(phydev);
191*26948c24SSky Huang if (ret)
192*26948c24SSky Huang return ret;
193*26948c24SSky Huang
194*26948c24SSky Huang phydev->speed = SPEED_UNKNOWN;
195*26948c24SSky Huang phydev->duplex = DUPLEX_UNKNOWN;
196*26948c24SSky Huang phydev->pause = 0;
197*26948c24SSky Huang phydev->asym_pause = 0;
198*26948c24SSky Huang
199*26948c24SSky Huang /* We'll read link speed through vendor specific registers down below.
200*26948c24SSky Huang * So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma
201*26948c24SSky Huang * (AN off).
202*26948c24SSky Huang */
203*26948c24SSky Huang if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
204*26948c24SSky Huang ret = genphy_c45_read_lpa(phydev);
205*26948c24SSky Huang if (ret < 0)
206*26948c24SSky Huang return ret;
207*26948c24SSky Huang
208*26948c24SSky Huang /* Clause 45 doesn't define 1000BaseT support. Read the link
209*26948c24SSky Huang * partner's 1G advertisement via Clause 22.
210*26948c24SSky Huang */
211*26948c24SSky Huang ret = phy_read(phydev, MII_STAT1000);
212*26948c24SSky Huang if (ret < 0)
213*26948c24SSky Huang return ret;
214*26948c24SSky Huang mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
215*26948c24SSky Huang } else if (phydev->autoneg == AUTONEG_DISABLE) {
216*26948c24SSky Huang linkmode_zero(phydev->lp_advertising);
217*26948c24SSky Huang }
218*26948c24SSky Huang
219*26948c24SSky Huang if (phydev->link) {
220*26948c24SSky Huang ret = phy_read(phydev, PHY_AUX_CTRL_STATUS);
221*26948c24SSky Huang if (ret < 0)
222*26948c24SSky Huang return ret;
223*26948c24SSky Huang
224*26948c24SSky Huang switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) {
225*26948c24SSky Huang case PHY_AUX_SPD_10:
226*26948c24SSky Huang phydev->speed = SPEED_10;
227*26948c24SSky Huang break;
228*26948c24SSky Huang case PHY_AUX_SPD_100:
229*26948c24SSky Huang phydev->speed = SPEED_100;
230*26948c24SSky Huang break;
231*26948c24SSky Huang case PHY_AUX_SPD_1000:
232*26948c24SSky Huang phydev->speed = SPEED_1000;
233*26948c24SSky Huang break;
234*26948c24SSky Huang case PHY_AUX_SPD_2500:
235*26948c24SSky Huang phydev->speed = SPEED_2500;
236*26948c24SSky Huang break;
237*26948c24SSky Huang }
238*26948c24SSky Huang
239*26948c24SSky Huang phydev->duplex = DUPLEX_FULL;
240*26948c24SSky Huang phydev->rate_matching = RATE_MATCH_PAUSE;
241*26948c24SSky Huang }
242*26948c24SSky Huang
243*26948c24SSky Huang return 0;
244*26948c24SSky Huang }
245*26948c24SSky Huang
mt798x_2p5ge_phy_get_rate_matching(struct phy_device * phydev,phy_interface_t iface)246*26948c24SSky Huang static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
247*26948c24SSky Huang phy_interface_t iface)
248*26948c24SSky Huang {
249*26948c24SSky Huang return RATE_MATCH_PAUSE;
250*26948c24SSky Huang }
251*26948c24SSky Huang
mt798x_2p5ge_phy_probe(struct phy_device * phydev)252*26948c24SSky Huang static int mt798x_2p5ge_phy_probe(struct phy_device *phydev)
253*26948c24SSky Huang {
254*26948c24SSky Huang struct pinctrl *pinctrl;
255*26948c24SSky Huang int ret;
256*26948c24SSky Huang
257*26948c24SSky Huang switch (phydev->drv->phy_id) {
258*26948c24SSky Huang case MTK_2P5GPHY_ID_MT7988:
259*26948c24SSky Huang /* This built-in 2.5GbE hardware only sets MDIO_DEVS_PMAPMD.
260*26948c24SSky Huang * Set the rest by this driver since PCS/AN/VEND1/VEND2 MDIO
261*26948c24SSky Huang * manageable devices actually exist.
262*26948c24SSky Huang */
263*26948c24SSky Huang phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS |
264*26948c24SSky Huang MDIO_DEVS_AN |
265*26948c24SSky Huang MDIO_DEVS_VEND1 |
266*26948c24SSky Huang MDIO_DEVS_VEND2;
267*26948c24SSky Huang break;
268*26948c24SSky Huang default:
269*26948c24SSky Huang return -EINVAL;
270*26948c24SSky Huang }
271*26948c24SSky Huang
272*26948c24SSky Huang ret = mt798x_2p5ge_phy_load_fw(phydev);
273*26948c24SSky Huang if (ret < 0)
274*26948c24SSky Huang return ret;
275*26948c24SSky Huang
276*26948c24SSky Huang /* Setup LED */
277*26948c24SSky Huang phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
278*26948c24SSky Huang MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 |
279*26948c24SSky Huang MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 |
280*26948c24SSky Huang MTK_PHY_LED_ON_LINK2500);
281*26948c24SSky Huang phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL,
282*26948c24SSky Huang MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX);
283*26948c24SSky Huang
284*26948c24SSky Huang /* Switch pinctrl after setting polarity to avoid bogus blinking */
285*26948c24SSky Huang pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led");
286*26948c24SSky Huang if (IS_ERR(pinctrl))
287*26948c24SSky Huang dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n");
288*26948c24SSky Huang
289*26948c24SSky Huang return 0;
290*26948c24SSky Huang }
291*26948c24SSky Huang
292*26948c24SSky Huang static struct phy_driver mtk_2p5gephy_driver[] = {
293*26948c24SSky Huang {
294*26948c24SSky Huang PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988),
295*26948c24SSky Huang .name = "MediaTek MT7988 2.5GbE PHY",
296*26948c24SSky Huang .probe = mt798x_2p5ge_phy_probe,
297*26948c24SSky Huang .config_init = mt798x_2p5ge_phy_config_init,
298*26948c24SSky Huang .config_aneg = mt798x_2p5ge_phy_config_aneg,
299*26948c24SSky Huang .get_features = mt798x_2p5ge_phy_get_features,
300*26948c24SSky Huang .read_status = mt798x_2p5ge_phy_read_status,
301*26948c24SSky Huang .get_rate_matching = mt798x_2p5ge_phy_get_rate_matching,
302*26948c24SSky Huang .suspend = genphy_suspend,
303*26948c24SSky Huang .resume = genphy_resume,
304*26948c24SSky Huang .read_page = mtk_phy_read_page,
305*26948c24SSky Huang .write_page = mtk_phy_write_page,
306*26948c24SSky Huang },
307*26948c24SSky Huang };
308*26948c24SSky Huang
309*26948c24SSky Huang module_phy_driver(mtk_2p5gephy_driver);
310*26948c24SSky Huang
311*26948c24SSky Huang static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
312*26948c24SSky Huang { PHY_ID_MATCH_VENDOR(0x00339c00) },
313*26948c24SSky Huang { }
314*26948c24SSky Huang };
315*26948c24SSky Huang
316*26948c24SSky Huang MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
317*26948c24SSky Huang MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
318*26948c24SSky Huang MODULE_LICENSE("GPL");
319*26948c24SSky Huang
320*26948c24SSky Huang MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
321*26948c24SSky Huang MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW);
322