1 From 71e79430117d56c409c5ea485a263bc0d8083390 Mon Sep 17 00:00:00 2001
2 From: Eric Woudstra <ericwouds@gmail.com>
3 Date: Tue, 26 Mar 2024 17:23:05 +0100
4 Subject: [PATCH] net: phy: air_en8811h: Add the Airoha EN8811H PHY driver
6 Add the driver for the Airoha EN8811H 2.5 Gigabit PHY. The phy supports
7 100/1000/2500 Mbps with auto negotiation only.
9 The driver uses two firmware files, for which updated versions are added to
10 linux-firmware already.
12 Note: At phy-address + 8 there is another device on the mdio bus, that
13 belongs to the EN881H. While the original driver writes to it, Airoha
14 has confirmed this is not needed. Therefore, communication with this
15 device is not included in this driver.
17 Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
18 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
19 Link: https://lore.kernel.org/r/20240326162305.303598-3-ericwouds@gmail.com
20 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
22 drivers/net/phy/Kconfig | 5 +
23 drivers/net/phy/Makefile | 1 +
24 drivers/net/phy/air_en8811h.c | 1086 +++++++++++++++++++++++++++++++++
25 3 files changed, 1092 insertions(+)
26 create mode 100644 drivers/net/phy/air_en8811h.c
28 --- a/drivers/net/phy/Kconfig
29 +++ b/drivers/net/phy/Kconfig
30 @@ -68,6 +68,11 @@ config SFP
32 comment "MII PHY device drivers"
34 +config AIR_EN8811H_PHY
35 + tristate "Airoha EN8811H 2.5 Gigabit PHY"
37 + Currently supports the Airoha EN8811H PHY.
42 --- a/drivers/net/phy/Makefile
43 +++ b/drivers/net/phy/Makefile
44 @@ -34,6 +34,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
46 obj-$(CONFIG_ADIN_PHY) += adin.o
47 obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
48 +obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o
49 obj-$(CONFIG_AMD_PHY) += amd.o
50 obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
51 obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
53 +++ b/drivers/net/phy/air_en8811h.c
55 +// SPDX-License-Identifier: GPL-2.0+
57 + * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
59 + * Limitations of the EN8811H:
60 + * - Only full duplex supported
61 + * - Forced speed (AN off) is not supported by hardware (100Mbps)
63 + * Source originated from airoha's en8811h.c and en8811h.h v1.2.1
65 + * Copyright (C) 2023 Airoha Technology Corp.
68 +#include <linux/phy.h>
69 +#include <linux/firmware.h>
70 +#include <linux/property.h>
71 +#include <linux/wordpart.h>
72 +#include <asm/unaligned.h>
74 +#define EN8811H_PHY_ID 0x03a2a411
76 +#define EN8811H_MD32_DM "airoha/EthMD32.dm.bin"
77 +#define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin"
79 +#define AIR_FW_ADDR_DM 0x00000000
80 +#define AIR_FW_ADDR_DSP 0x00100000
83 +#define AIR_AUX_CTRL_STATUS 0x1d
84 +#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
85 +#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
86 +#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
87 +#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
89 +#define AIR_EXT_PAGE_ACCESS 0x1f
90 +#define AIR_PHY_PAGE_STANDARD 0x0000
91 +#define AIR_PHY_PAGE_EXTENDED_4 0x0004
93 +/* MII Registers Page 4*/
94 +#define AIR_BPBUS_MODE 0x10
95 +#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
96 +#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
97 +#define AIR_BPBUS_WR_ADDR_HIGH 0x11
98 +#define AIR_BPBUS_WR_ADDR_LOW 0x12
99 +#define AIR_BPBUS_WR_DATA_HIGH 0x13
100 +#define AIR_BPBUS_WR_DATA_LOW 0x14
101 +#define AIR_BPBUS_RD_ADDR_HIGH 0x15
102 +#define AIR_BPBUS_RD_ADDR_LOW 0x16
103 +#define AIR_BPBUS_RD_DATA_HIGH 0x17
104 +#define AIR_BPBUS_RD_DATA_LOW 0x18
106 +/* Registers on MDIO_MMD_VEND1 */
107 +#define EN8811H_PHY_FW_STATUS 0x8009
108 +#define EN8811H_PHY_READY 0x02
110 +#define AIR_PHY_MCU_CMD_1 0x800c
111 +#define AIR_PHY_MCU_CMD_1_MODE1 0x0
112 +#define AIR_PHY_MCU_CMD_2 0x800d
113 +#define AIR_PHY_MCU_CMD_2_MODE1 0x0
114 +#define AIR_PHY_MCU_CMD_3 0x800e
115 +#define AIR_PHY_MCU_CMD_3_MODE1 0x1101
116 +#define AIR_PHY_MCU_CMD_3_DOCMD 0x1100
117 +#define AIR_PHY_MCU_CMD_4 0x800f
118 +#define AIR_PHY_MCU_CMD_4_MODE1 0x0002
119 +#define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4
121 +/* Registers on MDIO_MMD_VEND2 */
122 +#define AIR_PHY_LED_BCR 0x021
123 +#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0)
124 +#define AIR_PHY_LED_BCR_TIME_TEST BIT(2)
125 +#define AIR_PHY_LED_BCR_CLK_EN BIT(3)
126 +#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15)
128 +#define AIR_PHY_LED_DUR_ON 0x022
130 +#define AIR_PHY_LED_DUR_BLINK 0x023
132 +#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
133 +#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
134 +#define AIR_PHY_LED_ON_LINK1000 BIT(0)
135 +#define AIR_PHY_LED_ON_LINK100 BIT(1)
136 +#define AIR_PHY_LED_ON_LINK10 BIT(2)
137 +#define AIR_PHY_LED_ON_LINKDOWN BIT(3)
138 +#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */
139 +#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */
140 +#define AIR_PHY_LED_ON_FORCE_ON BIT(6)
141 +#define AIR_PHY_LED_ON_LINK2500 BIT(8)
142 +#define AIR_PHY_LED_ON_POLARITY BIT(14)
143 +#define AIR_PHY_LED_ON_ENABLE BIT(15)
145 +#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
146 +#define AIR_PHY_LED_BLINK_1000TX BIT(0)
147 +#define AIR_PHY_LED_BLINK_1000RX BIT(1)
148 +#define AIR_PHY_LED_BLINK_100TX BIT(2)
149 +#define AIR_PHY_LED_BLINK_100RX BIT(3)
150 +#define AIR_PHY_LED_BLINK_10TX BIT(4)
151 +#define AIR_PHY_LED_BLINK_10RX BIT(5)
152 +#define AIR_PHY_LED_BLINK_COLLISION BIT(6)
153 +#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
154 +#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
155 +#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9)
156 +#define AIR_PHY_LED_BLINK_2500TX BIT(10)
157 +#define AIR_PHY_LED_BLINK_2500RX BIT(11)
159 +/* Registers on BUCKPBUS */
160 +#define EN8811H_2P5G_LPA 0x3b30
161 +#define EN8811H_2P5G_LPA_2P5G BIT(0)
163 +#define EN8811H_FW_VERSION 0x3b3c
165 +#define EN8811H_POLARITY 0xca0f8
166 +#define EN8811H_POLARITY_TX_NORMAL BIT(0)
167 +#define EN8811H_POLARITY_RX_REVERSE BIT(1)
169 +#define EN8811H_GPIO_OUTPUT 0xcf8b8
170 +#define EN8811H_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5))
172 +#define EN8811H_FW_CTRL_1 0x0f0018
173 +#define EN8811H_FW_CTRL_1_START 0x0
174 +#define EN8811H_FW_CTRL_1_FINISH 0x1
175 +#define EN8811H_FW_CTRL_2 0x800000
176 +#define EN8811H_FW_CTRL_2_LOADING BIT(11)
178 +/* Led definitions */
179 +#define EN8811H_LED_COUNT 3
181 +/* Default LED setup:
182 + * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx
183 + * GPIO4 <-> LED1 On: Link detected at 2500 or 1000 Mbps
184 + * GPIO3 <-> LED2 On: Link detected at 2500 or 100 Mbps
186 +#define AIR_DEFAULT_TRIGGER_LED0 (BIT(TRIGGER_NETDEV_LINK) | \
187 + BIT(TRIGGER_NETDEV_RX) | \
188 + BIT(TRIGGER_NETDEV_TX))
189 +#define AIR_DEFAULT_TRIGGER_LED1 (BIT(TRIGGER_NETDEV_LINK_2500) | \
190 + BIT(TRIGGER_NETDEV_LINK_1000))
191 +#define AIR_DEFAULT_TRIGGER_LED2 (BIT(TRIGGER_NETDEV_LINK_2500) | \
192 + BIT(TRIGGER_NETDEV_LINK_100))
195 + unsigned long rules;
196 + unsigned long state;
199 +struct en8811h_priv {
200 + u32 firmware_version;
201 + bool mcu_needs_restart;
202 + struct led led[EN8811H_LED_COUNT];
206 + AIR_PHY_LED_STATE_FORCE_ON,
207 + AIR_PHY_LED_STATE_FORCE_BLINK,
211 + AIR_PHY_LED_DUR_BLINK_32MS,
212 + AIR_PHY_LED_DUR_BLINK_64MS,
213 + AIR_PHY_LED_DUR_BLINK_128MS,
214 + AIR_PHY_LED_DUR_BLINK_256MS,
215 + AIR_PHY_LED_DUR_BLINK_512MS,
216 + AIR_PHY_LED_DUR_BLINK_1024MS,
230 + AIR_LED_MODE_DISABLE,
231 + AIR_LED_MODE_USER_DEFINE,
234 +#define AIR_PHY_LED_DUR_UNIT 1024
235 +#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
237 +static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
238 + BIT(TRIGGER_NETDEV_LINK) |
239 + BIT(TRIGGER_NETDEV_LINK_10) |
240 + BIT(TRIGGER_NETDEV_LINK_100) |
241 + BIT(TRIGGER_NETDEV_LINK_1000) |
242 + BIT(TRIGGER_NETDEV_LINK_2500) |
243 + BIT(TRIGGER_NETDEV_RX) |
244 + BIT(TRIGGER_NETDEV_TX);
246 +static int air_phy_read_page(struct phy_device *phydev)
248 + return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
251 +static int air_phy_write_page(struct phy_device *phydev, int page)
253 + return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);
256 +static int __air_buckpbus_reg_write(struct phy_device *phydev,
257 + u32 pbus_address, u32 pbus_data)
261 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
265 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
266 + upper_16_bits(pbus_address));
270 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
271 + lower_16_bits(pbus_address));
275 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
276 + upper_16_bits(pbus_data));
280 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
281 + lower_16_bits(pbus_data));
288 +static int air_buckpbus_reg_write(struct phy_device *phydev,
289 + u32 pbus_address, u32 pbus_data)
294 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
296 + if (saved_page >= 0) {
297 + ret = __air_buckpbus_reg_write(phydev, pbus_address,
300 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
301 + pbus_address, ret);
304 + return phy_restore_page(phydev, saved_page, ret);
307 +static int __air_buckpbus_reg_read(struct phy_device *phydev,
308 + u32 pbus_address, u32 *pbus_data)
310 + int pbus_data_low, pbus_data_high;
313 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
317 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
318 + upper_16_bits(pbus_address));
322 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
323 + lower_16_bits(pbus_address));
327 + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
328 + if (pbus_data_high < 0)
331 + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
332 + if (pbus_data_low < 0)
335 + *pbus_data = pbus_data_low | (pbus_data_high << 16);
339 +static int air_buckpbus_reg_read(struct phy_device *phydev,
340 + u32 pbus_address, u32 *pbus_data)
345 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
347 + if (saved_page >= 0) {
348 + ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);
350 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
351 + pbus_address, ret);
354 + return phy_restore_page(phydev, saved_page, ret);
357 +static int __air_buckpbus_reg_modify(struct phy_device *phydev,
358 + u32 pbus_address, u32 mask, u32 set)
360 + int pbus_data_low, pbus_data_high;
361 + u32 pbus_data_old, pbus_data_new;
364 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
368 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
369 + upper_16_bits(pbus_address));
373 + ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
374 + lower_16_bits(pbus_address));
378 + pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
379 + if (pbus_data_high < 0)
382 + pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
383 + if (pbus_data_low < 0)
386 + pbus_data_old = pbus_data_low | (pbus_data_high << 16);
387 + pbus_data_new = (pbus_data_old & ~mask) | set;
388 + if (pbus_data_new == pbus_data_old)
391 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
392 + upper_16_bits(pbus_address));
396 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
397 + lower_16_bits(pbus_address));
401 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
402 + upper_16_bits(pbus_data_new));
406 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
407 + lower_16_bits(pbus_data_new));
414 +static int air_buckpbus_reg_modify(struct phy_device *phydev,
415 + u32 pbus_address, u32 mask, u32 set)
420 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
422 + if (saved_page >= 0) {
423 + ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,
426 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
427 + pbus_address, ret);
430 + return phy_restore_page(phydev, saved_page, ret);
433 +static int __air_write_buf(struct phy_device *phydev, u32 address,
434 + const struct firmware *fw)
436 + unsigned int offset;
440 + ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);
444 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
445 + upper_16_bits(address));
449 + ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
450 + lower_16_bits(address));
454 + for (offset = 0; offset < fw->size; offset += 4) {
455 + val = get_unaligned_le16(&fw->data[offset + 2]);
456 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, val);
460 + val = get_unaligned_le16(&fw->data[offset]);
461 + ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, val);
469 +static int air_write_buf(struct phy_device *phydev, u32 address,
470 + const struct firmware *fw)
475 + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
477 + if (saved_page >= 0) {
478 + ret = __air_write_buf(phydev, address, fw);
480 + phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
484 + return phy_restore_page(phydev, saved_page, ret);
487 +static int en8811h_wait_mcu_ready(struct phy_device *phydev)
489 + int ret, reg_value;
491 + /* Because of mdio-lock, may have to wait for multiple loads */
492 + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
493 + EN8811H_PHY_FW_STATUS, reg_value,
494 + reg_value == EN8811H_PHY_READY,
495 + 20000, 7500000, true);
497 + phydev_err(phydev, "MCU not ready: 0x%x\n", reg_value);
504 +static int en8811h_load_firmware(struct phy_device *phydev)
506 + struct en8811h_priv *priv = phydev->priv;
507 + struct device *dev = &phydev->mdio.dev;
508 + const struct firmware *fw1, *fw2;
511 + ret = request_firmware_direct(&fw1, EN8811H_MD32_DM, dev);
515 + ret = request_firmware_direct(&fw2, EN8811H_MD32_DSP, dev);
517 + goto en8811h_load_firmware_rel1;
519 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
520 + EN8811H_FW_CTRL_1_START);
522 + goto en8811h_load_firmware_out;
524 + ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
525 + EN8811H_FW_CTRL_2_LOADING,
526 + EN8811H_FW_CTRL_2_LOADING);
528 + goto en8811h_load_firmware_out;
530 + ret = air_write_buf(phydev, AIR_FW_ADDR_DM, fw1);
532 + goto en8811h_load_firmware_out;
534 + ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, fw2);
536 + goto en8811h_load_firmware_out;
538 + ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
539 + EN8811H_FW_CTRL_2_LOADING, 0);
541 + goto en8811h_load_firmware_out;
543 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
544 + EN8811H_FW_CTRL_1_FINISH);
546 + goto en8811h_load_firmware_out;
548 + ret = en8811h_wait_mcu_ready(phydev);
550 + air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
551 + &priv->firmware_version);
552 + phydev_info(phydev, "MD32 firmware version: %08x\n",
553 + priv->firmware_version);
555 +en8811h_load_firmware_out:
556 + release_firmware(fw2);
558 +en8811h_load_firmware_rel1:
559 + release_firmware(fw1);
562 + phydev_err(phydev, "Load firmware failed: %d\n", ret);
567 +static int en8811h_restart_mcu(struct phy_device *phydev)
571 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
572 + EN8811H_FW_CTRL_1_START);
576 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
577 + EN8811H_FW_CTRL_1_FINISH);
581 + return en8811h_wait_mcu_ready(phydev);
584 +static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on)
586 + struct en8811h_priv *priv = phydev->priv;
589 + if (index >= EN8811H_LED_COUNT)
593 + changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_ON,
594 + &priv->led[index].state);
596 + changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_ON,
597 + &priv->led[index].state);
599 + changed |= (priv->led[index].rules != 0);
602 + return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
603 + AIR_PHY_LED_ON(index),
604 + AIR_PHY_LED_ON_MASK,
605 + on ? AIR_PHY_LED_ON_FORCE_ON : 0);
610 +static int air_hw_led_blink_set(struct phy_device *phydev, u8 index,
613 + struct en8811h_priv *priv = phydev->priv;
616 + if (index >= EN8811H_LED_COUNT)
620 + changed = !test_and_set_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
621 + &priv->led[index].state);
623 + changed = !!test_and_clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
624 + &priv->led[index].state);
626 + changed |= (priv->led[index].rules != 0);
629 + return phy_write_mmd(phydev, MDIO_MMD_VEND2,
630 + AIR_PHY_LED_BLINK(index),
632 + AIR_PHY_LED_BLINK_FORCE_BLINK : 0);
637 +static int air_led_blink_set(struct phy_device *phydev, u8 index,
638 + unsigned long *delay_on,
639 + unsigned long *delay_off)
641 + struct en8811h_priv *priv = phydev->priv;
642 + bool blinking = false;
645 + if (index >= EN8811H_LED_COUNT)
648 + if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
654 + err = air_hw_led_blink_set(phydev, index, blinking);
658 + /* led-blink set, so switch led-on off */
659 + err = air_hw_led_on_set(phydev, index, false);
663 + /* hw-control is off*/
664 + if (!!test_bit(AIR_PHY_LED_STATE_FORCE_BLINK, &priv->led[index].state))
665 + priv->led[index].rules = 0;
670 +static int air_led_brightness_set(struct phy_device *phydev, u8 index,
671 + enum led_brightness value)
673 + struct en8811h_priv *priv = phydev->priv;
676 + if (index >= EN8811H_LED_COUNT)
679 + /* led-on set, so switch led-blink off */
680 + err = air_hw_led_blink_set(phydev, index, false);
684 + err = air_hw_led_on_set(phydev, index, (value != LED_OFF));
688 + /* hw-control is off */
689 + if (!!test_bit(AIR_PHY_LED_STATE_FORCE_ON, &priv->led[index].state))
690 + priv->led[index].rules = 0;
695 +static int air_led_hw_control_get(struct phy_device *phydev, u8 index,
696 + unsigned long *rules)
698 + struct en8811h_priv *priv = phydev->priv;
700 + if (index >= EN8811H_LED_COUNT)
703 + *rules = priv->led[index].rules;
708 +static int air_led_hw_control_set(struct phy_device *phydev, u8 index,
709 + unsigned long rules)
711 + struct en8811h_priv *priv = phydev->priv;
712 + u16 on = 0, blink = 0;
715 + if (index >= EN8811H_LED_COUNT)
718 + priv->led[index].rules = rules;
720 + if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
721 + on |= AIR_PHY_LED_ON_FDX;
723 + if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
724 + on |= AIR_PHY_LED_ON_LINK10;
726 + if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
727 + on |= AIR_PHY_LED_ON_LINK100;
729 + if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
730 + on |= AIR_PHY_LED_ON_LINK1000;
732 + if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
733 + on |= AIR_PHY_LED_ON_LINK2500;
735 + if (rules & BIT(TRIGGER_NETDEV_RX)) {
736 + blink |= AIR_PHY_LED_BLINK_10RX |
737 + AIR_PHY_LED_BLINK_100RX |
738 + AIR_PHY_LED_BLINK_1000RX |
739 + AIR_PHY_LED_BLINK_2500RX;
742 + if (rules & BIT(TRIGGER_NETDEV_TX)) {
743 + blink |= AIR_PHY_LED_BLINK_10TX |
744 + AIR_PHY_LED_BLINK_100TX |
745 + AIR_PHY_LED_BLINK_1000TX |
746 + AIR_PHY_LED_BLINK_2500TX;
750 + /* switch hw-control on, so led-on and led-blink are off */
751 + clear_bit(AIR_PHY_LED_STATE_FORCE_ON,
752 + &priv->led[index].state);
753 + clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
754 + &priv->led[index].state);
756 + priv->led[index].rules = 0;
759 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
760 + AIR_PHY_LED_ON_MASK, on);
765 + return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
769 +static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
774 + if (index >= EN8811H_LED_COUNT)
777 + if (state == AIR_LED_ENABLE)
778 + val |= AIR_PHY_LED_ON_ENABLE;
780 + val &= ~AIR_PHY_LED_ON_ENABLE;
782 + if (pol == AIR_ACTIVE_HIGH)
783 + val |= AIR_PHY_LED_ON_POLARITY;
785 + val &= ~AIR_PHY_LED_ON_POLARITY;
787 + err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
788 + AIR_PHY_LED_ON_ENABLE |
789 + AIR_PHY_LED_ON_POLARITY, val);
797 +static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
799 + struct en8811h_priv *priv = phydev->priv;
802 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK,
807 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON,
813 + case AIR_LED_MODE_DISABLE:
814 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
815 + AIR_PHY_LED_BCR_EXT_CTRL |
816 + AIR_PHY_LED_BCR_MODE_MASK, 0);
820 + case AIR_LED_MODE_USER_DEFINE:
821 + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
822 + AIR_PHY_LED_BCR_EXT_CTRL |
823 + AIR_PHY_LED_BCR_CLK_EN,
824 + AIR_PHY_LED_BCR_EXT_CTRL |
825 + AIR_PHY_LED_BCR_CLK_EN);
830 + phydev_err(phydev, "LED mode %d is not supported\n", mode);
834 + for (i = 0; i < num; ++i) {
835 + ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);
837 + phydev_err(phydev, "LED%d init failed: %d\n", i, ret);
840 + air_led_hw_control_set(phydev, i, priv->led[i].rules);
846 +static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
847 + unsigned long rules)
849 + if (index >= EN8811H_LED_COUNT)
852 + /* All combinations of the supported triggers are allowed */
853 + if (rules & ~en8811h_led_trig)
854 + return -EOPNOTSUPP;
859 +static int en8811h_probe(struct phy_device *phydev)
861 + struct en8811h_priv *priv;
864 + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv),
868 + phydev->priv = priv;
870 + ret = en8811h_load_firmware(phydev);
874 + /* mcu has just restarted after firmware load */
875 + priv->mcu_needs_restart = false;
877 + priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
878 + priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
879 + priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
881 + /* MDIO_DEVS1/2 empty, so set mmds_present bits here */
882 + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
884 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
885 + AIR_LED_MODE_DISABLE);
887 + phydev_err(phydev, "Failed to disable leds: %d\n", ret);
891 + /* Configure led gpio pins as output */
892 + ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
893 + EN8811H_GPIO_OUTPUT_345,
894 + EN8811H_GPIO_OUTPUT_345);
901 +static int en8811h_config_init(struct phy_device *phydev)
903 + struct en8811h_priv *priv = phydev->priv;
904 + struct device *dev = &phydev->mdio.dev;
908 + /* If restart happened in .probe(), no need to restart now */
909 + if (priv->mcu_needs_restart) {
910 + ret = en8811h_restart_mcu(phydev);
914 + /* Next calls to .config_init() mcu needs to restart */
915 + priv->mcu_needs_restart = true;
918 + /* Select mode 1, the only mode supported.
919 + * Configures the SerDes for 2500Base-X with rate adaptation
921 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_1,
922 + AIR_PHY_MCU_CMD_1_MODE1);
925 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_2,
926 + AIR_PHY_MCU_CMD_2_MODE1);
929 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,
930 + AIR_PHY_MCU_CMD_3_MODE1);
933 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,
934 + AIR_PHY_MCU_CMD_4_MODE1);
938 + /* Serdes polarity */
940 + if (device_property_read_bool(dev, "airoha,pnswap-rx"))
941 + pbus_value |= EN8811H_POLARITY_RX_REVERSE;
943 + pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
944 + if (device_property_read_bool(dev, "airoha,pnswap-tx"))
945 + pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
947 + pbus_value |= EN8811H_POLARITY_TX_NORMAL;
948 + ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
949 + EN8811H_POLARITY_RX_REVERSE |
950 + EN8811H_POLARITY_TX_NORMAL, pbus_value);
954 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
955 + AIR_LED_MODE_USER_DEFINE);
957 + phydev_err(phydev, "Failed to initialize leds: %d\n", ret);
964 +static int en8811h_get_features(struct phy_device *phydev)
966 + linkmode_set_bit_array(phy_basic_ports_array,
967 + ARRAY_SIZE(phy_basic_ports_array),
968 + phydev->supported);
970 + return genphy_c45_pma_read_abilities(phydev);
973 +static int en8811h_get_rate_matching(struct phy_device *phydev,
974 + phy_interface_t iface)
976 + return RATE_MATCH_PAUSE;
979 +static int en8811h_config_aneg(struct phy_device *phydev)
981 + bool changed = false;
985 + if (phydev->autoneg == AUTONEG_DISABLE) {
986 + phydev_warn(phydev, "Disabling autoneg is not supported\n");
990 + adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
992 + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
993 + MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
999 + return __genphy_config_aneg(phydev, changed);
1002 +static int en8811h_read_status(struct phy_device *phydev)
1004 + struct en8811h_priv *priv = phydev->priv;
1008 + ret = genphy_update_link(phydev);
1012 + phydev->master_slave_get = MASTER_SLAVE_CFG_UNSUPPORTED;
1013 + phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
1014 + phydev->speed = SPEED_UNKNOWN;
1015 + phydev->duplex = DUPLEX_UNKNOWN;
1016 + phydev->pause = 0;
1017 + phydev->asym_pause = 0;
1018 + phydev->rate_matching = RATE_MATCH_PAUSE;
1020 + ret = genphy_read_master_slave(phydev);
1024 + ret = genphy_read_lpa(phydev);
1028 + /* Get link partner 2.5GBASE-T ability from vendor register */
1029 + ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value);
1032 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
1033 + phydev->lp_advertising,
1034 + pbus_value & EN8811H_2P5G_LPA_2P5G);
1036 + if (phydev->autoneg_complete)
1037 + phy_resolve_aneg_pause(phydev);
1039 + if (!phydev->link)
1042 + /* Get real speed from vendor register */
1043 + val = phy_read(phydev, AIR_AUX_CTRL_STATUS);
1046 + switch (val & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
1047 + case AIR_AUX_CTRL_STATUS_SPEED_2500:
1048 + phydev->speed = SPEED_2500;
1050 + case AIR_AUX_CTRL_STATUS_SPEED_1000:
1051 + phydev->speed = SPEED_1000;
1053 + case AIR_AUX_CTRL_STATUS_SPEED_100:
1054 + phydev->speed = SPEED_100;
1058 + /* Firmware before version 24011202 has no vendor register 2P5G_LPA.
1059 + * Assume link partner advertised it if connected at 2500Mbps.
1061 + if (priv->firmware_version < 0x24011202) {
1062 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
1063 + phydev->lp_advertising,
1064 + phydev->speed == SPEED_2500);
1067 + /* Only supports full duplex */
1068 + phydev->duplex = DUPLEX_FULL;
1073 +static int en8811h_clear_intr(struct phy_device *phydev)
1077 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_3,
1078 + AIR_PHY_MCU_CMD_3_DOCMD);
1082 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AIR_PHY_MCU_CMD_4,
1083 + AIR_PHY_MCU_CMD_4_INTCLR);
1090 +static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev)
1094 + ret = en8811h_clear_intr(phydev);
1096 + phy_error(phydev);
1100 + phy_trigger_machine(phydev);
1102 + return IRQ_HANDLED;
1105 +static struct phy_driver en8811h_driver[] = {
1107 + PHY_ID_MATCH_MODEL(EN8811H_PHY_ID),
1108 + .name = "Airoha EN8811H",
1109 + .probe = en8811h_probe,
1110 + .get_features = en8811h_get_features,
1111 + .config_init = en8811h_config_init,
1112 + .get_rate_matching = en8811h_get_rate_matching,
1113 + .config_aneg = en8811h_config_aneg,
1114 + .read_status = en8811h_read_status,
1115 + .config_intr = en8811h_clear_intr,
1116 + .handle_interrupt = en8811h_handle_interrupt,
1117 + .led_hw_is_supported = en8811h_led_hw_is_supported,
1118 + .read_page = air_phy_read_page,
1119 + .write_page = air_phy_write_page,
1120 + .led_blink_set = air_led_blink_set,
1121 + .led_brightness_set = air_led_brightness_set,
1122 + .led_hw_control_set = air_led_hw_control_set,
1123 + .led_hw_control_get = air_led_hw_control_get,
1126 +module_phy_driver(en8811h_driver);
1128 +static struct mdio_device_id __maybe_unused en8811h_tbl[] = {
1129 + { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) },
1133 +MODULE_DEVICE_TABLE(mdio, en8811h_tbl);
1134 +MODULE_FIRMWARE(EN8811H_MD32_DM);
1135 +MODULE_FIRMWARE(EN8811H_MD32_DSP);
1137 +MODULE_DESCRIPTION("Airoha EN8811H PHY drivers");
1138 +MODULE_AUTHOR("Airoha");
1139 +MODULE_AUTHOR("Eric Woudstra <ericwouds@gmail.com>");
1140 +MODULE_LICENSE("GPL");