brintos

brintos / linux-shallow public Read only

0
0
Text · 26.9 KiB · 8d076b9 Raw
1091 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Driver for the Airoha EN8811H 2.5 Gigabit PHY.4 *5 * Limitations of the EN8811H:6 * - Only full duplex supported7 * - Forced speed (AN off) is not supported by hardware (100Mbps)8 *9 * Source originated from airoha's en8811h.c and en8811h.h v1.2.110 *11 * Copyright (C) 2023 Airoha Technology Corp.12 */13 14#include <linux/phy.h>15#include <linux/firmware.h>16#include <linux/property.h>17#include <linux/wordpart.h>18#include <linux/unaligned.h>19 20#define EN8811H_PHY_ID		0x03a2a41121 22#define EN8811H_MD32_DM		"airoha/EthMD32.dm.bin"23#define EN8811H_MD32_DSP	"airoha/EthMD32.DSP.bin"24 25#define AIR_FW_ADDR_DM	0x0000000026#define AIR_FW_ADDR_DSP	0x0010000027 28/* MII Registers */29#define AIR_AUX_CTRL_STATUS		0x1d30#define   AIR_AUX_CTRL_STATUS_SPEED_MASK	GENMASK(4, 2)31#define   AIR_AUX_CTRL_STATUS_SPEED_100		0x432#define   AIR_AUX_CTRL_STATUS_SPEED_1000	0x833#define   AIR_AUX_CTRL_STATUS_SPEED_2500	0xc34 35#define AIR_EXT_PAGE_ACCESS		0x1f36#define   AIR_PHY_PAGE_STANDARD			0x000037#define   AIR_PHY_PAGE_EXTENDED_4		0x000438 39/* MII Registers Page 4*/40#define AIR_BPBUS_MODE			0x1041#define   AIR_BPBUS_MODE_ADDR_FIXED		0x000042#define   AIR_BPBUS_MODE_ADDR_INCR		BIT(15)43#define AIR_BPBUS_WR_ADDR_HIGH		0x1144#define AIR_BPBUS_WR_ADDR_LOW		0x1245#define AIR_BPBUS_WR_DATA_HIGH		0x1346#define AIR_BPBUS_WR_DATA_LOW		0x1447#define AIR_BPBUS_RD_ADDR_HIGH		0x1548#define AIR_BPBUS_RD_ADDR_LOW		0x1649#define AIR_BPBUS_RD_DATA_HIGH		0x1750#define AIR_BPBUS_RD_DATA_LOW		0x1851 52/* Registers on MDIO_MMD_VEND1 */53#define EN8811H_PHY_FW_STATUS		0x800954#define   EN8811H_PHY_READY			0x0255 56#define AIR_PHY_MCU_CMD_1		0x800c57#define AIR_PHY_MCU_CMD_1_MODE1			0x058#define AIR_PHY_MCU_CMD_2		0x800d59#define AIR_PHY_MCU_CMD_2_MODE1			0x060#define AIR_PHY_MCU_CMD_3		0x800e61#define AIR_PHY_MCU_CMD_3_MODE1			0x110162#define AIR_PHY_MCU_CMD_3_DOCMD			0x110063#define AIR_PHY_MCU_CMD_4		0x800f64#define AIR_PHY_MCU_CMD_4_MODE1			0x000265#define AIR_PHY_MCU_CMD_4_INTCLR		0x00e466 67/* Registers on MDIO_MMD_VEND2 */68#define AIR_PHY_LED_BCR			0x02169#define   AIR_PHY_LED_BCR_MODE_MASK		GENMASK(1, 0)70#define   AIR_PHY_LED_BCR_TIME_TEST		BIT(2)71#define   AIR_PHY_LED_BCR_CLK_EN		BIT(3)72#define   AIR_PHY_LED_BCR_EXT_CTRL		BIT(15)73 74#define AIR_PHY_LED_DUR_ON		0x02275 76#define AIR_PHY_LED_DUR_BLINK		0x02377 78#define AIR_PHY_LED_ON(i)	       (0x024 + ((i) * 2))79#define   AIR_PHY_LED_ON_MASK			(GENMASK(6, 0) | BIT(8))80#define   AIR_PHY_LED_ON_LINK1000		BIT(0)81#define   AIR_PHY_LED_ON_LINK100		BIT(1)82#define   AIR_PHY_LED_ON_LINK10			BIT(2)83#define   AIR_PHY_LED_ON_LINKDOWN		BIT(3)84#define   AIR_PHY_LED_ON_FDX			BIT(4) /* Full duplex */85#define   AIR_PHY_LED_ON_HDX			BIT(5) /* Half duplex */86#define   AIR_PHY_LED_ON_FORCE_ON		BIT(6)87#define   AIR_PHY_LED_ON_LINK2500		BIT(8)88#define   AIR_PHY_LED_ON_POLARITY		BIT(14)89#define   AIR_PHY_LED_ON_ENABLE			BIT(15)90 91#define AIR_PHY_LED_BLINK(i)	       (0x025 + ((i) * 2))92#define   AIR_PHY_LED_BLINK_1000TX		BIT(0)93#define   AIR_PHY_LED_BLINK_1000RX		BIT(1)94#define   AIR_PHY_LED_BLINK_100TX		BIT(2)95#define   AIR_PHY_LED_BLINK_100RX		BIT(3)96#define   AIR_PHY_LED_BLINK_10TX		BIT(4)97#define   AIR_PHY_LED_BLINK_10RX		BIT(5)98#define   AIR_PHY_LED_BLINK_COLLISION		BIT(6)99#define   AIR_PHY_LED_BLINK_RX_CRC_ERR		BIT(7)100#define   AIR_PHY_LED_BLINK_RX_IDLE_ERR		BIT(8)101#define   AIR_PHY_LED_BLINK_FORCE_BLINK		BIT(9)102#define   AIR_PHY_LED_BLINK_2500TX		BIT(10)103#define   AIR_PHY_LED_BLINK_2500RX		BIT(11)104 105/* Registers on BUCKPBUS */106#define EN8811H_2P5G_LPA		0x3b30107#define   EN8811H_2P5G_LPA_2P5G			BIT(0)108 109#define EN8811H_FW_VERSION		0x3b3c110 111#define EN8811H_POLARITY		0xca0f8112#define   EN8811H_POLARITY_TX_NORMAL		BIT(0)113#define   EN8811H_POLARITY_RX_REVERSE		BIT(1)114 115#define EN8811H_GPIO_OUTPUT		0xcf8b8116#define   EN8811H_GPIO_OUTPUT_345		(BIT(3) | BIT(4) | BIT(5))117 118#define EN8811H_FW_CTRL_1		0x0f0018119#define   EN8811H_FW_CTRL_1_START		0x0120#define   EN8811H_FW_CTRL_1_FINISH		0x1121#define EN8811H_FW_CTRL_2		0x800000122#define EN8811H_FW_CTRL_2_LOADING		BIT(11)123 124/* Led definitions */125#define EN8811H_LED_COUNT	3126 127/* Default LED setup:128 * GPIO5 <-> LED0  On: Link detected, blink Rx/Tx129 * GPIO4 <-> LED1  On: Link detected at 2500 or 1000 Mbps130 * GPIO3 <-> LED2  On: Link detected at 2500 or  100 Mbps131 */132#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK)      | \133				  BIT(TRIGGER_NETDEV_RX)        | \134				  BIT(TRIGGER_NETDEV_TX))135#define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \136				  BIT(TRIGGER_NETDEV_LINK_1000))137#define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \138				  BIT(TRIGGER_NETDEV_LINK_100))139 140struct led {141	unsigned long rules;142	unsigned long state;143};144 145struct en8811h_priv {146	u32		firmware_version;147	bool		mcu_needs_restart;148	struct led	led[EN8811H_LED_COUNT];149};150 151enum {152	AIR_PHY_LED_STATE_FORCE_ON,153	AIR_PHY_LED_STATE_FORCE_BLINK,154};155 156enum {157	AIR_PHY_LED_DUR_BLINK_32MS,158	AIR_PHY_LED_DUR_BLINK_64MS,159	AIR_PHY_LED_DUR_BLINK_128MS,160	AIR_PHY_LED_DUR_BLINK_256MS,161	AIR_PHY_LED_DUR_BLINK_512MS,162	AIR_PHY_LED_DUR_BLINK_1024MS,163};164 165enum {166	AIR_LED_DISABLE,167	AIR_LED_ENABLE,168};169 170enum {171	AIR_ACTIVE_LOW,172	AIR_ACTIVE_HIGH,173};174 175enum {176	AIR_LED_MODE_DISABLE,177	AIR_LED_MODE_USER_DEFINE,178};179 180#define AIR_PHY_LED_DUR_UNIT	1024181#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)182 183static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) |184					      BIT(TRIGGER_NETDEV_LINK)        |185					      BIT(TRIGGER_NETDEV_LINK_10)     |186					      BIT(TRIGGER_NETDEV_LINK_100)    |187					      BIT(TRIGGER_NETDEV_LINK_1000)   |188					      BIT(TRIGGER_NETDEV_LINK_2500)   |189					      BIT(TRIGGER_NETDEV_RX)          |190					      BIT(TRIGGER_NETDEV_TX);191 192static int air_phy_read_page(struct phy_device *phydev)193{194	return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);195}196 197static int air_phy_write_page(struct phy_device *phydev, int page)198{199	return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);200}201 202static int __air_buckpbus_reg_write(struct phy_device *phydev,203				    u32 pbus_address, u32 pbus_data)204{205	int ret;206 207	ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);208	if (ret < 0)209		return ret;210 211	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,212			  upper_16_bits(pbus_address));213	if (ret < 0)214		return ret;215 216	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,217			  lower_16_bits(pbus_address));218	if (ret < 0)219		return ret;220 221	ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,222			  upper_16_bits(pbus_data));223	if (ret < 0)224		return ret;225 226	ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,227			  lower_16_bits(pbus_data));228	if (ret < 0)229		return ret;230 231	return 0;232}233 234static int air_buckpbus_reg_write(struct phy_device *phydev,235				  u32 pbus_address, u32 pbus_data)236{237	int saved_page;238	int ret = 0;239 240	saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);241 242	if (saved_page >= 0) {243		ret = __air_buckpbus_reg_write(phydev, pbus_address,244					       pbus_data);245		if (ret < 0)246			phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,247				   pbus_address, ret);248	}249 250	return phy_restore_page(phydev, saved_page, ret);251}252 253static int __air_buckpbus_reg_read(struct phy_device *phydev,254				   u32 pbus_address, u32 *pbus_data)255{256	int pbus_data_low, pbus_data_high;257	int ret;258 259	ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);260	if (ret < 0)261		return ret;262 263	ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,264			  upper_16_bits(pbus_address));265	if (ret < 0)266		return ret;267 268	ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,269			  lower_16_bits(pbus_address));270	if (ret < 0)271		return ret;272 273	pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);274	if (pbus_data_high < 0)275		return pbus_data_high;276 277	pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);278	if (pbus_data_low < 0)279		return pbus_data_low;280 281	*pbus_data = pbus_data_low | (pbus_data_high << 16);282	return 0;283}284 285static int air_buckpbus_reg_read(struct phy_device *phydev,286				 u32 pbus_address, u32 *pbus_data)287{288	int saved_page;289	int ret = 0;290 291	saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);292 293	if (saved_page >= 0) {294		ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);295		if (ret < 0)296			phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,297				   pbus_address, ret);298	}299 300	return phy_restore_page(phydev, saved_page, ret);301}302 303static int __air_buckpbus_reg_modify(struct phy_device *phydev,304				     u32 pbus_address, u32 mask, u32 set)305{306	int pbus_data_low, pbus_data_high;307	u32 pbus_data_old, pbus_data_new;308	int ret;309 310	ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);311	if (ret < 0)312		return ret;313 314	ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,315			  upper_16_bits(pbus_address));316	if (ret < 0)317		return ret;318 319	ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,320			  lower_16_bits(pbus_address));321	if (ret < 0)322		return ret;323 324	pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);325	if (pbus_data_high < 0)326		return pbus_data_high;327 328	pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);329	if (pbus_data_low < 0)330		return pbus_data_low;331 332	pbus_data_old = pbus_data_low | (pbus_data_high << 16);333	pbus_data_new = (pbus_data_old & ~mask) | set;334	if (pbus_data_new == pbus_data_old)335		return 0;336 337	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,338			  upper_16_bits(pbus_address));339	if (ret < 0)340		return ret;341 342	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,343			  lower_16_bits(pbus_address));344	if (ret < 0)345		return ret;346 347	ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,348			  upper_16_bits(pbus_data_new));349	if (ret < 0)350		return ret;351 352	ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,353			  lower_16_bits(pbus_data_new));354	if (ret < 0)355		return ret;356 357	return 0;358}359 360static int air_buckpbus_reg_modify(struct phy_device *phydev,361				   u32 pbus_address, u32 mask, u32 set)362{363	int saved_page;364	int ret = 0;365 366	saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);367 368	if (saved_page >= 0) {369		ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,370						set);371		if (ret < 0)372			phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,373				   pbus_address, ret);374	}375 376	return phy_restore_page(phydev, saved_page, ret);377}378 379static int __air_write_buf(struct phy_device *phydev, u32 address,380			   const struct firmware *fw)381{382	unsigned int offset;383	int ret;384	u16 val;385 386	ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);387	if (ret < 0)388		return ret;389 390	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,391			  upper_16_bits(address));392	if (ret < 0)393		return ret;394 395	ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,396			  lower_16_bits(address));397	if (ret < 0)398		return ret;399 400	for (offset = 0; offset < fw->size; offset += 4) {401		val = get_unaligned_le16(&fw->data[offset + 2]);402		ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val);403		if (ret < 0)404			return ret;405 406		val = get_unaligned_le16(&fw->data[offset]);407		ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val);408		if (ret < 0)409			return ret;410	}411 412	return 0;413}414 415static int air_write_buf(struct phy_device *phydev, u32 address,416			 const struct firmware *fw)417{418	int saved_page;419	int ret = 0;420 421	saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);422 423	if (saved_page >= 0) {424		ret = __air_write_buf(phydev, address, fw);425		if (ret < 0)426			phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,427				   address, ret);428	}429 430	return phy_restore_page(phydev, saved_page, ret);431}432 433static int en8811h_wait_mcu_ready(struct phy_device *phydev)434{435	int ret, reg_value;436 437	/* Because of mdio-lock, may have to wait for multiple loads */438	ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,439					EN8811H_PHY_FW_STATUS, reg_value,440					reg_value == EN8811H_PHY_READY,441					20000, 7500000, true);442	if (ret) {443		phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value);444		return -ENODEV;445	}446 447	return 0;448}449 450static int en8811h_load_firmware(struct phy_device *phydev)451{452	struct en8811h_priv *priv = phydev->priv;453	struct device *dev = &phydev->mdio.dev;454	const struct firmware *fw1, *fw2;455	int ret;456 457	ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev);458	if (ret < 0)459		return ret;460 461	ret = request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev);462	if (ret < 0)463		goto en8811h_load_firmware_rel1;464 465	ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,466				     EN8811H_FW_CTRL_1_START);467	if (ret < 0)468		goto en8811h_load_firmware_out;469 470	ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,471				      EN8811H_FW_CTRL_2_LOADING,472				      EN8811H_FW_CTRL_2_LOADING);473	if (ret < 0)474		goto en8811h_load_firmware_out;475 476	ret = air_write_buf(phydev, AIR_FW_ADDR_DM,  fw1);477	if (ret < 0)478		goto en8811h_load_firmware_out;479 480	ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, fw2);481	if (ret < 0)482		goto en8811h_load_firmware_out;483 484	ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,485				      EN8811H_FW_CTRL_2_LOADING, 0);486	if (ret < 0)487		goto en8811h_load_firmware_out;488 489	ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,490				     EN8811H_FW_CTRL_1_FINISH);491	if (ret < 0)492		goto en8811h_load_firmware_out;493 494	ret = en8811h_wait_mcu_ready(phydev);495 496	air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,497			      &priv->firmware_version);498	phydev_info(phydev, "MD32 firmware version: %08x\n",499		    priv->firmware_version);500 501en8811h_load_firmware_out:502	release_firmware(fw2);503 504en8811h_load_firmware_rel1:505	release_firmware(fw1);506 507	if (ret < 0)508		phydev_err(phydev, "Load firmware failed: %d\n", ret);509 510	return ret;511}512 513static int en8811h_restart_mcu(struct phy_device *phydev)514{515	int ret;516 517	ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,518				     EN8811H_FW_CTRL_1_START);519	if (ret < 0)520		return ret;521 522	ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,523				     EN8811H_FW_CTRL_1_FINISH);524	if (ret < 0)525		return ret;526 527	return en8811h_wait_mcu_ready(phydev);528}529 530static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on)531{532	struct en8811h_priv *priv = phydev->priv;533	bool changed;534 535	if (index >= EN8811H_LED_COUNT)536		return -EINVAL;537 538	if (on)539		changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_ON,540					    &priv->led[index].state);541	else542		changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_ON,543					       &priv->led[index].state);544 545	changed |= (priv->led[index].rules != 0);546 547	/* clear netdev trigger rules in case LED_OFF has been set */548	if (!on)549		priv->led[index].rules = 0;550 551	if (changed)552		return phy_modify_mmd(phydev, MDIO_MMD_VEND2,553				      AIR_PHY_LED_ON(index),554				      AIR_PHY_LED_ON_MASK,555				      on ? AIR_PHY_LED_ON_FORCE_ON : 0);556 557	return 0;558}559 560static int air_hw_led_blink_set(struct phy_device *phydev, u8 index,561				bool blinking)562{563	struct en8811h_priv *priv = phydev->priv;564	bool changed;565 566	if (index >= EN8811H_LED_COUNT)567		return -EINVAL;568 569	if (blinking)570		changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_BLINK,571					    &priv->led[index].state);572	else573		changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,574					       &priv->led[index].state);575 576	changed |= (priv->led[index].rules != 0);577 578	if (changed)579		return phy_write_mmd(phydev, MDIO_MMD_VEND2,580				     AIR_PHY_LED_BLINK(index),581				     blinking ?582				     AIR_PHY_LED_BLINK_FORCE_BLINK : 0);583	else584		return 0;585}586 587static int air_led_blink_set(struct phy_device *phydev, u8 index,588			     unsigned long *delay_on,589			     unsigned long *delay_off)590{591	struct en8811h_priv *priv = phydev->priv;592	bool blinking = false;593	int err;594 595	if (index >= EN8811H_LED_COUNT)596		return -EINVAL;597 598	if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {599		blinking = true;600		*delay_on = 50;601		*delay_off = 50;602	}603 604	err = air_hw_led_blink_set(phydev, index, blinking);605	if (err)606		return err;607 608	/* led-blink set, so switch led-on off */609	err = air_hw_led_on_set(phydev, index, false);610	if (err)611		return err;612 613	/* hw-control is off*/614	if (!!test_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state))615		priv->led[index].rules = 0;616 617	return 0;618}619 620static int air_led_brightness_set(struct phy_device *phydev, u8 index,621				  enum led_brightness value)622{623	struct en8811h_priv *priv = phydev->priv;624	int err;625 626	if (index >= EN8811H_LED_COUNT)627		return -EINVAL;628 629	/* led-on set, so switch led-blink off */630	err = air_hw_led_blink_set(phydev, index, false);631	if (err)632		return err;633 634	err = air_hw_led_on_set(phydev, index, (value != LED_OFF));635	if (err)636		return err;637 638	/* hw-control is off */639	if (!!test_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state))640		priv->led[index].rules = 0;641 642	return 0;643}644 645static int air_led_hw_control_get(struct phy_device *phydev, u8 index,646				  unsigned long *rules)647{648	struct en8811h_priv *priv = phydev->priv;649 650	if (index >= EN8811H_LED_COUNT)651		return -EINVAL;652 653	*rules = priv->led[index].rules;654 655	return 0;656};657 658static int air_led_hw_control_set(struct phy_device *phydev, u8 index,659				  unsigned long rules)660{661	struct en8811h_priv *priv = phydev->priv;662	u16 on = 0, blink = 0;663	int ret;664 665	if (index >= EN8811H_LED_COUNT)666		return -EINVAL;667 668	priv->led[index].rules = rules;669 670	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))671		on |= AIR_PHY_LED_ON_FDX;672 673	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))674		on |= AIR_PHY_LED_ON_LINK10;675 676	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))677		on |= AIR_PHY_LED_ON_LINK100;678 679	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))680		on |= AIR_PHY_LED_ON_LINK1000;681 682	if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))683		on |= AIR_PHY_LED_ON_LINK2500;684 685	if (rules & BIT(TRIGGER_NETDEV_RX)) {686		blink |= AIR_PHY_LED_BLINK_10RX   |687			 AIR_PHY_LED_BLINK_100RX  |688			 AIR_PHY_LED_BLINK_1000RX |689			 AIR_PHY_LED_BLINK_2500RX;690	}691 692	if (rules & BIT(TRIGGER_NETDEV_TX)) {693		blink |= AIR_PHY_LED_BLINK_10TX   |694			 AIR_PHY_LED_BLINK_100TX  |695			 AIR_PHY_LED_BLINK_1000TX |696			 AIR_PHY_LED_BLINK_2500TX;697	}698 699	if (blink || on) {700		/* switch hw-control on, so led-on and led-blink are off */701		clear_bit(AIR_PHY_LED_STATE_FORCE_ON,702			  &priv->led[index].state);703		clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,704			  &priv->led[index].state);705	} else {706		priv->led[index].rules = 0;707	}708 709	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),710			     AIR_PHY_LED_ON_MASK, on);711 712	if (ret < 0)713		return ret;714 715	return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),716			     blink);717};718 719static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)720{721	int val = 0;722	int err;723 724	if (index >= EN8811H_LED_COUNT)725		return -EINVAL;726 727	if (state == AIR_LED_ENABLE)728		val |= AIR_PHY_LED_ON_ENABLE;729	else730		val &= ~AIR_PHY_LED_ON_ENABLE;731 732	if (pol == AIR_ACTIVE_HIGH)733		val |= AIR_PHY_LED_ON_POLARITY;734	else735		val &= ~AIR_PHY_LED_ON_POLARITY;736 737	err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),738			     AIR_PHY_LED_ON_ENABLE |739			     AIR_PHY_LED_ON_POLARITY, val);740 741	if (err < 0)742		return err;743 744	return 0;745}746 747static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)748{749	struct en8811h_priv *priv = phydev->priv;750	int ret, i;751 752	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK,753			    dur);754	if (ret < 0)755		return ret;756 757	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON,758			    dur >> 1);759	if (ret < 0)760		return ret;761 762	switch (mode) {763	case AIR_LED_MODE_DISABLE:764		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,765				     AIR_PHY_LED_BCR_EXT_CTRL |766				     AIR_PHY_LED_BCR_MODE_MASK, 0);767		if (ret < 0)768			return ret;769		break;770	case AIR_LED_MODE_USER_DEFINE:771		ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,772				     AIR_PHY_LED_BCR_EXT_CTRL |773				     AIR_PHY_LED_BCR_CLK_EN,774				     AIR_PHY_LED_BCR_EXT_CTRL |775				     AIR_PHY_LED_BCR_CLK_EN);776		if (ret < 0)777			return ret;778		break;779	default:780		phydev_err(phydev, "LED mode %d is not supported\n", mode);781		return -EINVAL;782	}783 784	for (i = 0; i < num; ++i) {785		ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);786		if (ret < 0) {787			phydev_err(phydev, "LED%d init failed: %d\n", i, ret);788			return ret;789		}790		air_led_hw_control_set(phydev, i, priv->led[i].rules);791	}792 793	return 0;794}795 796static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,797				       unsigned long rules)798{799	if (index >= EN8811H_LED_COUNT)800		return -EINVAL;801 802	/* All combinations of the supported triggers are allowed */803	if (rules & ~en8811h_led_trig)804		return -EOPNOTSUPP;805 806	return 0;807};808 809static int en8811h_probe(struct phy_device *phydev)810{811	struct en8811h_priv *priv;812	int ret;813 814	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv),815			    GFP_KERNEL);816	if (!priv)817		return -ENOMEM;818	phydev->priv = priv;819 820	ret = en8811h_load_firmware(phydev);821	if (ret < 0)822		return ret;823 824	/* mcu has just restarted after firmware load */825	priv->mcu_needs_restart = false;826 827	priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;828	priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;829	priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;830 831	/* MDIO_DEVS1/2 empty, so set mmds_present bits here */832	phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;833 834	ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,835			    AIR_LED_MODE_DISABLE);836	if (ret < 0) {837		phydev_err(phydev, "Failed to disable leds: %d\n", ret);838		return ret;839	}840 841	/* Configure led gpio pins as output */842	ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,843				      EN8811H_GPIO_OUTPUT_345,844				      EN8811H_GPIO_OUTPUT_345);845	if (ret < 0)846		return ret;847 848	return 0;849}850 851static int en8811h_config_init(struct phy_device *phydev)852{853	struct en8811h_priv *priv = phydev->priv;854	struct device *dev = &phydev->mdio.dev;855	u32 pbus_value;856	int ret;857 858	/* If restart happened in .probe(), no need to restart now */859	if (priv->mcu_needs_restart) {860		ret = en8811h_restart_mcu(phydev);861		if (ret < 0)862			return ret;863	} else {864		/* Next calls to .config_init() mcu needs to restart */865		priv->mcu_needs_restart = true;866	}867 868	/* Select mode 1, the only mode supported.869	 * Configures the SerDes for 2500Base-X with rate adaptation870	 */871	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1,872			    AIR_PHY_MCU_CMD_1_MODE1);873	if (ret < 0)874		return ret;875	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2,876			    AIR_PHY_MCU_CMD_2_MODE1);877	if (ret < 0)878		return ret;879	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,880			    AIR_PHY_MCU_CMD_3_MODE1);881	if (ret < 0)882		return ret;883	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,884			    AIR_PHY_MCU_CMD_4_MODE1);885	if (ret < 0)886		return ret;887 888	/* Serdes polarity */889	pbus_value = 0;890	if (device_property_read_bool(dev, "airoha,pnswap-rx"))891		pbus_value |=  EN8811H_POLARITY_RX_REVERSE;892	else893		pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;894	if (device_property_read_bool(dev, "airoha,pnswap-tx"))895		pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;896	else897		pbus_value |=  EN8811H_POLARITY_TX_NORMAL;898	ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,899				      EN8811H_POLARITY_RX_REVERSE |900				      EN8811H_POLARITY_TX_NORMAL, pbus_value);901	if (ret < 0)902		return ret;903 904	ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,905			    AIR_LED_MODE_USER_DEFINE);906	if (ret < 0) {907		phydev_err(phydev, "Failed to initialize leds: %d\n", ret);908		return ret;909	}910 911	return 0;912}913 914static int en8811h_get_features(struct phy_device *phydev)915{916	linkmode_set_bit_array(phy_basic_ports_array,917			       ARRAY_SIZE(phy_basic_ports_array),918			       phydev->supported);919 920	return genphy_c45_pma_read_abilities(phydev);921}922 923static int en8811h_get_rate_matching(struct phy_device *phydev,924				     phy_interface_t iface)925{926	return RATE_MATCH_PAUSE;927}928 929static int en8811h_config_aneg(struct phy_device *phydev)930{931	bool changed = false;932	int ret;933	u32 adv;934 935	if (phydev->autoneg == AUTONEG_DISABLE) {936		phydev_warn(phydev, "Disabling autoneg is not supported\n");937		return -EINVAL;938	}939 940	adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);941 942	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,943				     MDIO_AN_10GBT_CTRL_ADV2_5G, adv);944	if (ret < 0)945		return ret;946	if (ret > 0)947		changed = true;948 949	return __genphy_config_aneg(phydev, changed);950}951 952static int en8811h_read_status(struct phy_device *phydev)953{954	struct en8811h_priv *priv = phydev->priv;955	u32 pbus_value;956	int ret, val;957 958	ret = genphy_update_link(phydev);959	if (ret)960		return ret;961 962	phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED;963	phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;964	phydev->speed = SPEED_UNKNOWN;965	phydev->duplex = DUPLEX_UNKNOWN;966	phydev->pause = 0;967	phydev->asym_pause = 0;968	phydev->rate_matching = RATE_MATCH_PAUSE;969 970	ret = genphy_read_master_slave(phydev);971	if (ret < 0)972		return ret;973 974	ret = genphy_read_lpa(phydev);975	if (ret < 0)976		return ret;977 978	/* Get link partner 2.5GBASE-T ability from vendor register */979	ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value);980	if (ret < 0)981		return ret;982	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,983			 phydev->lp_advertising,984			 pbus_value & EN8811H_2P5G_LPA_2P5G);985 986	if (phydev->autoneg_complete)987		phy_resolve_aneg_pause(phydev);988 989	if (!phydev->link)990		return 0;991 992	/* Get real speed from vendor register */993	val = phy_read(phydev, AIR_AUX_CTRL_STATUS);994	if (val < 0)995		return val;996	switch (val & AIR_AUX_CTRL_STATUS_SPEED_MASK) {997	case AIR_AUX_CTRL_STATUS_SPEED_2500:998		phydev->speed = SPEED_2500;999		break;1000	case AIR_AUX_CTRL_STATUS_SPEED_1000:1001		phydev->speed = SPEED_1000;1002		break;1003	case AIR_AUX_CTRL_STATUS_SPEED_100:1004		phydev->speed = SPEED_100;1005		break;1006	}1007 1008	/* Firmware before version 24011202 has no vendor register 2P5G_LPA.1009	 * Assume link partner advertised it if connected at 2500Mbps.1010	 */1011	if (priv->firmware_version < 0x24011202) {1012		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,1013				 phydev->lp_advertising,1014				 phydev->speed == SPEED_2500);1015	}1016 1017	/* Only supports full duplex */1018	phydev->duplex = DUPLEX_FULL;1019 1020	return 0;1021}1022 1023static int en8811h_clear_intr(struct phy_device *phydev)1024{1025	int ret;1026 1027	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,1028			    AIR_PHY_MCU_CMD_3_DOCMD);1029	if (ret < 0)1030		return ret;1031 1032	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,1033			    AIR_PHY_MCU_CMD_4_INTCLR);1034	if (ret < 0)1035		return ret;1036 1037	return 0;1038}1039 1040static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev)1041{1042	int ret;1043 1044	ret = en8811h_clear_intr(phydev);1045	if (ret < 0) {1046		phy_error(phydev);1047		return IRQ_NONE;1048	}1049 1050	phy_trigger_machine(phydev);1051 1052	return IRQ_HANDLED;1053}1054 1055static struct phy_driver en8811h_driver[] = {1056{1057	PHY_ID_MATCH_MODEL(EN8811H_PHY_ID),1058	.name			= "Airoha EN8811H",1059	.probe			= en8811h_probe,1060	.get_features		= en8811h_get_features,1061	.config_init		= en8811h_config_init,1062	.get_rate_matching	= en8811h_get_rate_matching,1063	.config_aneg		= en8811h_config_aneg,1064	.read_status		= en8811h_read_status,1065	.config_intr		= en8811h_clear_intr,1066	.handle_interrupt	= en8811h_handle_interrupt,1067	.led_hw_is_supported	= en8811h_led_hw_is_supported,1068	.read_page		= air_phy_read_page,1069	.write_page		= air_phy_write_page,1070	.led_blink_set		= air_led_blink_set,1071	.led_brightness_set	= air_led_brightness_set,1072	.led_hw_control_set	= air_led_hw_control_set,1073	.led_hw_control_get	= air_led_hw_control_get,1074} };1075 1076module_phy_driver(en8811h_driver);1077 1078static struct mdio_device_id __maybe_unused en8811h_tbl[] = {1079	{ PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) },1080	{ }1081};1082 1083MODULE_DEVICE_TABLE(mdio, en8811h_tbl);1084MODULE_FIRMWARE(EN8811H_MD32_DM);1085MODULE_FIRMWARE(EN8811H_MD32_DSP);1086 1087MODULE_DESCRIPTION("Airoha EN8811H PHY drivers");1088MODULE_AUTHOR("Airoha");1089MODULE_AUTHOR("Eric Woudstra <ericwouds@gmail.com>");1090MODULE_LICENSE("GPL");1091