xref: /linux/drivers/net/phy/mediatek/mtk-2p5ge.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce) !
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