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