From 6517fff7938c8549c03cf0f924d5f93e0cd08954 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Sep 2023 09:00:48 +0200 Subject: [PATCH] mediatek: add edgecore eap111 support Signed-off-by: John Crispin --- .../0059-mediatek-improve-mt7981.dtsi.patch | 132 ++ ...mediatek-add-edgecore-eap111-support.patch | 1737 +++++++++++++++++ 2 files changed, 1869 insertions(+) create mode 100644 patches/0059-mediatek-improve-mt7981.dtsi.patch create mode 100644 patches/0060-mediatek-add-edgecore-eap111-support.patch diff --git a/patches/0059-mediatek-improve-mt7981.dtsi.patch b/patches/0059-mediatek-improve-mt7981.dtsi.patch new file mode 100644 index 000000000..88e12d872 --- /dev/null +++ b/patches/0059-mediatek-improve-mt7981.dtsi.patch @@ -0,0 +1,132 @@ +From 23eafe1d6f07339e666ae1492af9b322b9769d02 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 27 Aug 2023 15:57:00 +0100 +Subject: [PATCH 59/60] mediatek: improve mt7981.dtsi + + * re-factor WED components to boot fine also on limited loaders + * add LEDs of integrated GE PHY + +Signed-off-by: Daniel Golle +(cherry picked from commit 3ef8760e876e09fa91b54a09b2a5003c175829d3) +--- + .../arch/arm64/boot/dts/mediatek/mt7981.dtsi | 71 ++++++++++++++----- + 1 file changed, 52 insertions(+), 19 deletions(-) + +diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi +index 3629a6f6dd..05d4b7d91d 100644 +--- a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi ++++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -191,21 +192,6 @@ + reg = <0 0x47dc0000 0 0x240000>; + no-map; + }; +- +- wo_ilm0: wo-ilm@151e0000 { +- reg = <0 0x151e0000 0 0x8000>; +- no-map; +- }; +- +- wo_dlm0: wo-dlm@151e8000 { +- reg = <0 0x151e8000 0 0x2000>; +- no-map; +- }; +- +- wo_boot: wo-boot@15194000 { +- reg = <0 0x15194000 0 0x1000>; +- no-map; +- }; + }; + + psci { +@@ -432,6 +418,20 @@ + drive-strength = <4>; + }; + }; ++ ++ gbe_led0_pins: gbe-led0-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led0"; ++ }; ++ }; ++ ++ gbe_led1_pins: gbe-led1-pins { ++ mux { ++ function = "led"; ++ groups = "gbe_led1"; ++ }; ++ }; + }; + + ethsys: syscon@15000000 { +@@ -452,11 +452,12 @@ + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; +- memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, +- <&wo_data>, <&wo_boot>; +- memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", +- "wo-data", "wo-boot"; ++ memory-region = <&wo_emi0>, <&wo_data>; ++ memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; ++ mediatek,wo-ilm = <&wo_ilm0>; ++ mediatek,wo-dlm = <&wo_dlm0>; ++ mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + + eth: ethernet@15100000 { +@@ -511,10 +512,42 @@ + phy-is-integrated; + nvmem-cells = <&phy_calibration>; + nvmem-cell-names = "phy-cal-data"; ++ ++ leds { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ int_gbe_phy_led0: int-gbe-phy-led0@0 { ++ reg = <0>; ++ function = LED_FUNCTION_LAN; ++ status = "disabled"; ++ }; ++ ++ int_gbe_phy_led1: int-gbe-phy-led1@1 { ++ reg = <1>; ++ function = LED_FUNCTION_LAN; ++ status = "disabled"; ++ }; ++ }; + }; + }; + }; + ++ wo_dlm0: syscon@151e8000 { ++ compatible = "mediatek,mt7986-wo-dlm", "syscon"; ++ reg = <0 0x151e8000 0 0x2000>; ++ }; ++ ++ wo_ilm0: syscon@151e0000 { ++ compatible = "mediatek,mt7986-wo-ilm", "syscon"; ++ reg = <0 0x151e0000 0 0x8000>; ++ }; ++ ++ wo_cpuboot: syscon@15194000 { ++ compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; ++ reg = <0 0x15194000 0 0x1000>; ++ }; ++ + wo_ccif0: syscon@151a5000 { + compatible = "mediatek,mt7986-wo-ccif", "syscon"; + reg = <0 0x151a5000 0 0x1000>; +-- +2.34.1 + diff --git a/patches/0060-mediatek-add-edgecore-eap111-support.patch b/patches/0060-mediatek-add-edgecore-eap111-support.patch new file mode 100644 index 000000000..18da01614 --- /dev/null +++ b/patches/0060-mediatek-add-edgecore-eap111-support.patch @@ -0,0 +1,1737 @@ +From 168061a6d41dac4650855da74c4f5f1b5e7ea925 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 5 Sep 2023 08:58:23 +0200 +Subject: [PATCH 60/60] mediatek: add edgecore eap111 support + +Signed-off-by: John Crispin +--- + .../mediatek/dts/mt7981a-edgecore-eap111.dts | 187 +++ + .../mediatek/files/drivers/net/phy/en8801sc.c | 1152 +++++++++++++++++ + .../mediatek/files/drivers/net/phy/en8801sc.h | 255 ++++ + .../filogic/base-files/etc/board.d/01_leds | 4 + + .../filogic/base-files/etc/board.d/02_network | 3 + + target/linux/mediatek/filogic/config-5.15 | 1 + + target/linux/mediatek/image/filogic.mk | 16 + + .../mediatek/patches-5.15/999-en8801sc.patch | 28 + + 8 files changed, 1646 insertions(+) + create mode 100644 target/linux/mediatek/dts/mt7981a-edgecore-eap111.dts + create mode 100644 target/linux/mediatek/files/drivers/net/phy/en8801sc.c + create mode 100644 target/linux/mediatek/files/drivers/net/phy/en8801sc.h + create mode 100644 target/linux/mediatek/patches-5.15/999-en8801sc.patch + +diff --git a/target/linux/mediatek/dts/mt7981a-edgecore-eap111.dts b/target/linux/mediatek/dts/mt7981a-edgecore-eap111.dts +new file mode 100644 +index 0000000000..aeedffecdf +--- /dev/null ++++ b/target/linux/mediatek/dts/mt7981a-edgecore-eap111.dts +@@ -0,0 +1,187 @@ ++/dts-v1/; ++ ++#include "mt7981.dtsi" ++ ++/ { ++ model = "edgecore mt7981"; ++ compatible = "edgecore,eap111", "mediatek,mt7981"; ++ ++ aliases { ++ led-boot = &led_green; ++ led-failsafe = &led_green; ++ led-running = &led_green; ++ led-upgrade = &led_green; ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ reset { ++ label = "reset"; ++ linux,code = ; ++ gpios = <&pio 1 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led_green: led@0 { ++ label = "green:power"; ++ gpios = <&pio 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led_orange: led@1 { ++ label = "orange:wan"; ++ gpios = <&pio 34 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led_blue: led@2 { ++ label = "blue:wlan5g"; ++ gpios = <&pio 35 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&uart1 { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "okay"; ++}; ++ ++ð { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mdio_pins>; ++ ++ status = "okay"; ++ ++ gmac0: mac@0 { ++ compatible = "mediatek,eth-mac"; ++ reg = <0>; ++ phy-mode = "sgmii"; ++ phy-handle = <&phy0>; ++ nvmem-cells = <&macaddr>; ++ nvmem-cell-names = "mac-address"; ++ mac-address-increment = <1>; ++ }; ++ ++ gmac1: mac@1 { ++ compatible = "mediatek,eth-mac"; ++ reg = <1>; ++ phy-mode = "gmii"; ++ phy-handle = <&int_gbe_phy>; ++ nvmem-cells = <&macaddr>; ++ nvmem-cell-names = "mac-address"; ++ }; ++}; ++ ++&mdio_bus { ++ reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <10000>; ++ reset-post-delay-us = <10000>; ++ ++ phy0: ethernet-phy@24 { ++ reg = <24>; ++ //compatible = "ethernet-phy-ieee802.3-c45"; ++ compatible = "ethernet-phy-id03a2.9471"; ++ phy-mode = "sgmii"; ++ full-duplex; ++ pause; ++ }; ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ status = "okay"; ++ ++ spi_nand: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ ++ spi-cal-enable; ++ spi-cal-mode = "read-data"; ++ spi-cal-datalen = <7>; ++ spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>; ++ spi-cal-addrlen = <5>; ++ spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>; ++ ++ spi-tx-buswidth = <4>; ++ spi-rx-buswidth = <4>; ++ mediatek,nmbm; ++ mediatek,bmt-max-ratio = <1>; ++ mediatek,bmt-max-reserved-blocks = <64>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "BL2"; ++ reg = <0x00000 0x0100000>; ++ read-only; ++ }; ++ ++ partition@100000 { ++ label = "u-boot-env"; ++ reg = <0x0100000 0x0080000>; ++ }; ++ ++ factory: partition@180000 { ++ label = "Factory"; ++ reg = <0x180000 0x0200000>; ++ read-only; ++ ++ compatible = "nvmem-cells"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ macaddr: macaddr@a { ++ reg = <0xa 0x6>; ++ }; ++ }; ++ ++ partition@380000 { ++ label = "FIP"; ++ reg = <0x380000 0x0200000>; ++ read-only; ++ }; ++ ++ partition@580000 { ++ label = "ubi"; ++ reg = <0x580000 0x4000000>; ++ compatible = "linux,ubi"; ++ }; ++ }; ++ }; ++}; ++ ++&pio { ++ spi0_flash_pins: spi0-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ }; ++}; ++ ++&wifi { ++ mediatek,mtd-eeprom = <&factory 0x0>; ++ ++ status = "okay"; ++}; +diff --git a/target/linux/mediatek/files/drivers/net/phy/en8801sc.c b/target/linux/mediatek/files/drivers/net/phy/en8801sc.c +new file mode 100644 +index 0000000000..d88350ffc4 +--- /dev/null ++++ b/target/linux/mediatek/files/drivers/net/phy/en8801sc.c +@@ -0,0 +1,1152 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* FILE NAME: en8801sc.c ++ * PURPOSE: ++ * EN8801SC phy driver for Linux ++ * NOTES: ++ * ++ */ ++ ++/* INCLUDE FILE DECLARATIONS ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) ++#include ++#include ++#endif ++ ++#include "en8801sc.h" ++ ++MODULE_DESCRIPTION("Airoha EN8801S PHY drivers for MediaTek SoC"); ++MODULE_AUTHOR("Airoha"); ++MODULE_LICENSE("GPL"); ++ ++#define airoha_mdio_lock(bus) mutex_lock(&((bus)->mdio_lock)) ++#define airoha_mdio_unlock(bus) mutex_unlock(&((bus)->mdio_lock)) ++ ++#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) ++#define phydev_mdio_bus(_dev) (_dev->bus) ++#define phydev_phy_addr(_dev) (_dev->addr) ++#define phydev_dev(_dev) (&_dev->dev) ++#define phydev_pbus_addr(dev) ((dev)->addr + 1) ++#else ++#define phydev_mdio_bus(_dev) (_dev->mdio.bus) ++#define phydev_phy_addr(_dev) (_dev->mdio.addr) ++#define phydev_dev(_dev) (&_dev->mdio.dev) ++#define phydev_pbus_addr(dev) ((dev)->mdio.addr + 1) ++#endif ++ ++enum { ++ PHY_STATE_DONE = 0, ++ PHY_STATE_INIT = 1, ++ PHY_STATE_PROCESS = 2, ++ PHY_STATE_FAIL = 3, ++}; ++ ++struct en8801s_priv { ++ bool first_init; ++ u16 count; ++#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) ++ struct gpio_desc *hw_reset; ++#endif ++}; ++ ++/* ++The following led_cfg example is for reference only. ++LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, ++LED6 10/100M/LINK/ACT (GPIO9) <-> BASE_T_LED1, ++LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, ++*/ ++/* User-defined.B */ ++#define AIR_LED_SUPPORT ++#ifdef AIR_LED_SUPPORT ++static const struct AIR_BASE_T_LED_CFG_S led_cfg[4] = { ++/* ++* {LED Enable, GPIO, LED Polarity, LED ON, LED Blink} ++*/ ++ /* BASE-T LED0 */ ++ {LED_ENABLE, 5, AIR_ACTIVE_LOW, ++ BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, ++ /* BASE-T LED1 */ ++ {LED_ENABLE, 9, AIR_ACTIVE_LOW, ++ BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, ++ /* BASE-T LED2 */ ++ {LED_ENABLE, 8, AIR_ACTIVE_LOW, ++ BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, ++ /* BASE-T LED3 */ ++ {LED_DISABLE, 1, AIR_ACTIVE_LOW, ++ BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG}, ++}; ++static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; ++#endif ++ ++/* User-defined.E */ ++ ++/************************************************************************ ++* F U N C T I O N S ++************************************************************************/ ++/*static unsigned int airoha_cl22_read(struct mii_bus *ebus, int phy_addr, ++ unsigned int phy_register, unsigned int *read_data) ++{ ++ *read_data = mdiobus_read(ebus, phy_addr, phy_register); ++ return 0; ++} ++ ++static int airoha_cl22_write(struct mii_bus *ebus, int phy_addr, ++ unsigned int phy_register, unsigned int write_data) ++{ ++ int ret = 0; ++ struct device *dev = &ebus->dev; ++ ++ ret = mdiobus_write(ebus, phy_addr, phy_register, write_data); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++*/ ++static int __airoha_cl45_write(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 val) ++{ ++ int ret = 0; ++ struct device *dev = &bus->dev; ++ ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, ++ MMD_OP_MODE_DATA | devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static int __airoha_cl45_read(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 *read_data) ++{ ++ int ret = 0; ++ struct device *dev = &bus->dev; ++ ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, ++ MMD_OP_MODE_DATA | devad); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return ret; ++ } ++ *read_data = __mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG); ++ ++ return ret; ++} ++ ++static int airoha_cl45_write(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 val) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(bus); ++ ret = __airoha_cl45_write(bus, port, devad, reg, val); ++ airoha_mdio_unlock(bus); ++ ++ return ret; ++} ++ ++static int airoha_cl45_read(struct mii_bus *bus, int port, ++ u32 devad, u32 reg, u16 *read_data) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(bus); ++ ret = __airoha_cl45_read(bus, port, devad, reg, read_data); ++ airoha_mdio_unlock(bus); ++ ++ return ret; ++} ++ ++static int __airoha_pbus_write(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address, unsigned long pbus_data) ++{ ++ int ret = 0; ++ ++ ret = __mdiobus_write(ebus, pbus_id, 0x1F, ++ (unsigned int)(pbus_address >> 6)); ++ if (ret < 0) ++ return ret; ++ ret = __mdiobus_write(ebus, pbus_id, ++ (unsigned int)((pbus_address >> 2) & 0xf), ++ (unsigned int)(pbus_data & 0xFFFF)); ++ if (ret < 0) ++ return ret; ++ ret = __mdiobus_write(ebus, pbus_id, 0x10, ++ (unsigned int)(pbus_data >> 16)); ++ if (ret < 0) ++ return ret; ++ return ret; ++} ++ ++static unsigned long __airoha_pbus_read(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address) ++{ ++ unsigned long pbus_data; ++ unsigned int pbus_data_low, pbus_data_high; ++ int ret = 0; ++ struct device *dev = &ebus->dev; ++ ++ ret = __mdiobus_write(ebus, pbus_id, 0x1F, ++ (unsigned int)(pbus_address >> 6)); ++ if (ret < 0) { ++ dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); ++ return INVALID_DATA; ++ } ++ pbus_data_low = __mdiobus_read(ebus, pbus_id, ++ (unsigned int)((pbus_address >> 2) & 0xf)); ++ pbus_data_high = __mdiobus_read(ebus, pbus_id, 0x10); ++ pbus_data = (pbus_data_high << 16) + pbus_data_low; ++ return pbus_data; ++} ++ ++static int airoha_pbus_write(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address, unsigned long pbus_data) ++{ ++ int ret = 0; ++ ++ airoha_mdio_lock(ebus); ++ ret = __airoha_pbus_write(ebus, pbus_id, pbus_address, pbus_data); ++ airoha_mdio_unlock(ebus); ++ ++ return ret; ++} ++ ++static unsigned long airoha_pbus_read(struct mii_bus *ebus, int pbus_id, ++ unsigned long pbus_address) ++{ ++ unsigned long pbus_data; ++ ++ airoha_mdio_lock(ebus); ++ pbus_data = __airoha_pbus_read(ebus, pbus_id, pbus_address); ++ airoha_mdio_unlock(ebus); ++ ++ return pbus_data; ++} ++ ++/* Airoha Token Ring Write function */ ++static int airoha_tr_reg_write(struct phy_device *phydev, ++ unsigned long tr_address, unsigned long tr_data) ++{ ++ int ret = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *ebus = phydev_mdio_bus(phydev); ++ ++ airoha_mdio_lock(ebus); ++ ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x52b5); /* page select */ ++ ret = __mdiobus_write(ebus, phy_addr, 0x11, ++ (unsigned int)(tr_data & 0xffff)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x12, ++ (unsigned int)(tr_data >> 16)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x10, ++ (unsigned int)(tr_address | TrReg_WR)); ++ ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x0); /* page resetore */ ++ airoha_mdio_unlock(ebus); ++ ++ return ret; ++} ++ ++#ifdef AIR_LED_SUPPORT ++static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, ++ int polar, u16 on_evt, u16 blk_evt) ++{ ++ int ret = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ if (polar == AIR_ACTIVE_HIGH) ++ on_evt |= LED_ON_POL; ++ else ++ on_evt &= ~LED_ON_POL; ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), on_evt | LED_ON_EN); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_BLK_CTRL(entity), blk_evt); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int airoha_led_set_mode(struct phy_device *phydev, u8 mode) ++{ ++ u16 cl45_data; ++ int err = 0; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ err = airoha_cl45_read(mbus, phy_addr, 0x1f, LED_BCR, &cl45_data); ++ if (err < 0) ++ return err; ++ ++ switch (mode) { ++ case AIR_LED_MODE_DISABLE: ++ cl45_data &= ~LED_BCR_EXT_CTRL; ++ cl45_data &= ~LED_BCR_MODE_MASK; ++ cl45_data |= LED_BCR_MODE_DISABLE; ++ break; ++ case AIR_LED_MODE_USER_DEFINE: ++ cl45_data |= LED_BCR_EXT_CTRL; ++ cl45_data |= LED_BCR_CLK_EN; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ err = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BCR, cl45_data); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ ++static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state) ++{ ++ u16 cl45_data; ++ int err; ++ int phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ ++ err = airoha_cl45_read(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), &cl45_data); ++ if (err < 0) ++ return err; ++ if (state == LED_ENABLE) ++ cl45_data |= LED_ON_EN; ++ else ++ cl45_data &= ~LED_ON_EN; ++ ++ err = airoha_cl45_write(mbus, phy_addr, 0x1f, ++ LED_ON_CTRL(entity), cl45_data); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ ++static int en8801s_led_init(struct phy_device *phydev) ++{ ++ ++ unsigned long led_gpio = 0, reg_value = 0; ++ int ret = 0, led_id; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878}; ++ u16 cl45_data = led_dur; ++ struct device *dev = phydev_dev(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BLK_DUR, cl45_data); ++ if (ret < 0) ++ return ret; ++ cl45_data >>= 1; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_ON_DUR, cl45_data); ++ if (ret < 0) ++ return ret; ++ ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set mode, ret %d !\n", ret); ++ return ret; ++ } ++ for (led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) { ++ reg_value = 0; ++ ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set state, ret %d !\n", ret); ++ return ret; ++ } ++ if (led_cfg[led_id].en == LED_ENABLE) { ++ if ((led_cfg[led_id].gpio < 0) ++ || led_cfg[led_id].gpio > 9) { ++ dev_err(dev, "GPIO%d is out of range!! GPIO number is 0~9.\n", ++ led_cfg[led_id].gpio); ++ return -EIO; ++ } ++ led_gpio |= BIT(led_cfg[led_id].gpio); ++ reg_value = airoha_pbus_read(mbus, pbus_addr, ++ gpio_led_rg[led_cfg[led_id].gpio / 4]); ++ LED_SET_GPIO_SEL(led_cfg[led_id].gpio, ++ led_id, reg_value); ++ dev_dbg(dev, "[Airoha] gpio%d, reg_value 0x%lx\n", ++ led_cfg[led_id].gpio, reg_value); ++ ret = airoha_pbus_write(mbus, pbus_addr, ++ gpio_led_rg[led_cfg[led_id].gpio / 4], ++ reg_value); ++ if (ret < 0) ++ return ret; ++ ret = airoha_led_set_usr_def(phydev, led_id, ++ led_cfg[led_id].pol, ++ led_cfg[led_id].on_cfg, ++ led_cfg[led_id].blk_cfg); ++ if (ret != 0) { ++ dev_err(dev, "LED fail to set usr def, ret %d !\n", ++ ret); ++ return ret; ++ } ++ } ++ } ++ reg_value = (airoha_pbus_read(mbus, pbus_addr, 0x1880) & ~led_gpio); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1880, reg_value); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x186c, led_gpio); ++ if (ret < 0) ++ return ret; ++ dev_info(dev, "LED initialize OK !\n"); ++ return 0; ++} ++#endif ++static int en8801s_phy_process(struct phy_device *phydev) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ unsigned long reg_value = 0; ++ int ret = 0; ++ int pbus_addr = phydev_pbus_addr(phydev); ++ ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); ++ reg_value |= BIT(0); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); ++ if (ret < 0) ++ return ret; ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); ++ reg_value &= ~BIT(0); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); ++ if (ret < 0) ++ return ret; ++ return ret; ++} ++ ++static int en8801s_phase1_init(struct phy_device *phydev) ++{ ++ unsigned long pbus_data; ++ int pbusAddress = EN8801S_PBUS_DEFAULT_ID; ++ u16 reg_value; ++ int retry, ret = 0; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ struct device *dev = phydev_dev(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) ++ /* Deassert the reset signal */ ++ if (priv->hw_reset) ++ gpiod_set_value(priv->hw_reset, 0); ++#endif ++ priv->count = 1; ++ msleep(1000); ++ ++ retry = MAX_OUI_CHECK; ++ while (1) { ++ pbus_data = airoha_pbus_read(mbus, pbusAddress, ++ EN8801S_RG_ETHER_PHY_OUI); /* PHY OUI */ ++ if (pbus_data == EN8801S_PBUS_OUI) { ++ dev_info(dev, "PBUS addr 0x%x: Start initialized.\n", ++ pbusAddress); ++ break; ++ } ++ pbusAddress = phydev_pbus_addr(phydev); ++ if (0 == --retry) { ++ dev_err(dev, "Probe fail !\n"); ++ return 0; ++ } ++ } ++ ++ ret = airoha_pbus_write(mbus, pbusAddress, EN8801S_RG_BUCK_CTL, 0x03); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ pbus_data = (airoha_pbus_read(mbus, pbusAddress, EN8801S_RG_LTR_CTL) ++ & 0xfffffffc) | BIT(2); ++ ret = airoha_pbus_write(mbus, pbusAddress, ++ EN8801S_RG_LTR_CTL, pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(500); ++ pbus_data = (pbus_data & ~BIT(2)) | ++ EN8801S_RX_POLARITY_NORMAL | ++ EN8801S_TX_POLARITY_NORMAL; ++ ret = airoha_pbus_write(mbus, pbusAddress, ++ EN8801S_RG_LTR_CTL, pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(500); ++ ++ pbus_data = airoha_pbus_read(mbus, pbusAddress, ++ EN8801S_RG_SMI_ADDR); /* SMI ADDR */ ++ pbus_data = (pbus_data & 0xffff0000) | ++ (unsigned long)(phydev_pbus_addr(phydev) << 8) | ++ (unsigned long)(phydev_phy_addr(phydev)); ++ dev_info(phydev_dev(phydev), "SMI_ADDR=%lx (renew)\n", pbus_data); ++ ret = airoha_pbus_write(mbus, pbusAddress, ++ EN8801S_RG_SMI_ADDR, pbus_data); ++ mdelay(10); ++ ++ retry = MAX_RETRY; ++ while (1) { ++ mdelay(10); ++ reg_value = phy_read(phydev, MII_PHYSID2); ++ if (reg_value == EN8801S_PHY_ID2) ++ break; /* wait GPHY ready */ ++ ++ retry--; ++ if (retry == 0) { ++ dev_err(dev, "Initialize fail !\n"); ++ return 0; ++ } ++ } ++ /* Software Reset PHY */ ++ reg_value = phy_read(phydev, MII_BMCR); ++ reg_value |= BMCR_RESET; ++ ret = phy_write(phydev, MII_BMCR, reg_value); ++ if (ret < 0) ++ return ret; ++ retry = MAX_RETRY; ++ do { ++ mdelay(10); ++ reg_value = phy_read(phydev, MII_BMCR); ++ retry--; ++ if (retry == 0) { ++ dev_err(dev, "Reset fail !\n"); ++ return 0; ++ } ++ } while (reg_value & BMCR_RESET); ++ ++ phydev->dev_flags = PHY_STATE_INIT; ++ ++ dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION); ++ ++ return 0; ++} ++ ++static int en8801s_phase2_init(struct phy_device *phydev) ++{ ++ union gephy_all_REG_LpiReg1Ch GPHY_RG_LPI_1C; ++ union gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324; ++ union gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012; ++ union gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017; ++ unsigned long pbus_data; ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ u16 cl45_value; ++ int retry, ret = 0; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ struct device *dev = phydev_dev(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690); ++ pbus_data |= BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ /* Set FCM control */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505); ++ if (ret < 0) ++ return ret; ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11)); ++ if (ret < 0) ++ return ret; ++ ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5)); ++ if (ret < 0) ++ return ret; ++ ++ /* Set GPHY Perfomance*/ ++ /* Token Ring */ ++ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h, 0x00001E); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h, 0x6FB90A); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h, 0x060671); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h, 0x0E2F00); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h, 0x444444); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h, 0x000000); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h, 0x2EBAEF); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h, 0x00000B); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch, 0x00504D); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh, 0x02314F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh, 0x003028); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h, 0x005010); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h, 0x040001); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h, 0x018670); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h, 0x00024A); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh, 0x000072); ++ if (ret < 0) ++ return ret; ++ ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch, 0x003210); ++ if (ret < 0) ++ return ret; ++ ++ /* CL22 & CL45 */ ++ ret = phy_write(phydev, 0x1f, 0x03); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LPI_1Ch); ++ GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C; ++ ret = phy_write(phydev, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, RgAddr_LPI_1Ch, 0xC92); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, RgAddr_AUXILIARY_1Dh, 0x1); ++ if (ret < 0) ++ return ret; ++ ret = phy_write(phydev, 0x1f, 0x0); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x120, 0x8014); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x122, 0xffff); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x123, 0xffff); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x144, 0x0200); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x14A, 0xEE20); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x189, 0x0110); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19B, 0x0111); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x234, 0x0181); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x238, 0x0120); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x239, 0x0117); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x268, 0x07F4); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x2D1, 0x0733); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x323, 0x0011); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, 0x013F); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x326, 0x0037); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x324, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_324.DATA = cl45_value; ++ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, ++ GPHY_RG_1E_324.DATA); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19E, 0xC2); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x013, 0x0); ++ if (ret < 0) ++ return ret; ++ ++ /* EFUSE */ ++ airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040); ++ retry = MAX_RETRY; ++ while (retry != 0) { ++ mdelay(1); ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); ++ if ((pbus_data & BIT(30)) == 0) ++ break; ++ ++ retry--; ++ } ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */ ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_012.DATA = cl45_value; ++ GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = ++ (u16)(pbus_data & 0x03f); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, ++ GPHY_RG_1E_012.DATA); ++ if (ret < 0) ++ return ret; ++ ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value); ++ if (ret < 0) ++ return ret; ++ GPHY_RG_1E_017.DATA = cl45_value; ++ GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = ++ (u16)((pbus_data >> 8) & 0x03f); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x17, ++ GPHY_RG_1E_017.DATA); ++ if (ret < 0) ++ return ret; ++ ++ airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040); ++ retry = MAX_RETRY; ++ while (retry != 0) { ++ mdelay(1); ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); ++ if ((pbus_data & BIT(30)) == 0) ++ break; ++ ++ retry--; ++ } ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */ ++ GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = ++ (u16)((pbus_data >> 12) & 0x01); ++ ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, ++ GPHY_RG_1E_324.DATA); ++ if (ret < 0) ++ return ret; ++#ifdef AIR_LED_SUPPORT ++ ret = en8801s_led_init(phydev); ++ if (ret != 0) ++ dev_err(dev, "en8801s_led_init fail (ret:%d) !\n", ret); ++#endif ++ ++ ret = airoha_cl45_read(mbus, phy_addr, MDIO_MMD_AN, ++ MDIO_AN_EEE_ADV, &cl45_value); ++ if (ret < 0) ++ return ret; ++ if (cl45_value == 0) { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xA == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | (0xE << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ } ++ } else { ++ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xE == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | (0xA << 22); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ if (ret < 0) ++ return ret; ++ mdelay(10); ++ } ++ } ++ ++ priv->first_init = false; ++ dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n"); ++ return 0; ++} ++ ++static int en8801s_read_status(struct phy_device *phydev) ++{ ++ int ret = 0, preSpeed = phydev->speed; ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ u32 reg_value; ++ struct device *dev = phydev_dev(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ struct en8801s_priv *priv = phydev->priv; ++ ++ ret = genphy_read_status(phydev); ++ if (phydev->link == LINK_DOWN) ++ preSpeed = phydev->speed = 0; ++ ++ if (phydev->dev_flags == PHY_STATE_PROCESS) { ++ en8801s_phy_process(phydev); ++ phydev->dev_flags = PHY_STATE_DONE; ++ } ++ ++ if (phydev->dev_flags == PHY_STATE_INIT) { ++ dev_dbg(dev, "phydev->link %d, count %d\n", ++ phydev->link, priv->count); ++ if ((phydev->link) || (priv->count == 5)) { ++ ret = en8801s_phase2_init(phydev); ++ if (ret != 0) { ++ dev_info(dev, "en8801_phase2_init failed\n"); ++ phydev->dev_flags = PHY_STATE_FAIL; ++ return 0; ++ } ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } ++ priv->count++; ++ } ++ ++ if ((preSpeed != phydev->speed) && (phydev->link == LINK_UP)) { ++ preSpeed = phydev->speed; ++ ++ if (preSpeed == SPEED_10) { ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); ++ reg_value |= BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, ++ reg_value); ++ if (ret < 0) ++ return ret; ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } else { ++ reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); ++ reg_value &= ~BIT(31); ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, ++ reg_value); ++ if (ret < 0) ++ return ret; ++ phydev->dev_flags = PHY_STATE_PROCESS; ++ } ++ ++ airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c000c00); ++ if (preSpeed == SPEED_1000) { ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD801); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x0003); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c000c00); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x004b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } else if (preSpeed == SPEED_100) { ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD401); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c11); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x0027); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } else if (preSpeed == SPEED_10) { ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x10, ++ 0xD001); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0, ++ 0x9140); ++ if (ret < 0) ++ return ret; ++ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, ++ 0x000b); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, ++ 0x0c11); ++ if (ret < 0) ++ return ret; ++ mdelay(2); /* delay 2 ms */ ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, ++ 0x0027); ++ if (ret < 0) ++ return ret; ++ ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, ++ 0x0007); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ return ret; ++} ++ ++static int en8801s_probe(struct phy_device *phydev) ++{ ++ struct en8801s_priv *priv; ++ unsigned long phy_addr = phydev_phy_addr(phydev); ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ struct device *dev = &mbus->dev; ++#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) ++ struct gpio_desc *en8801s_reset; ++ int err = 0; ++#else ++ struct mdio_device *mdiodev = &phydev->mdio; ++#endif ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->count = 0; ++ priv->first_init = true; ++ ++#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) ++ /* Assert the optional reset signal */ ++ en8801s_reset = gpiod_get_optional(&phydev->dev, ++ "reset", GPIOD_OUT_HIGH); ++ err = PTR_ERR_OR_ZERO(en8801s_reset); ++ if (err) { ++ dev_dbg(phydev_dev(phydev), ++ "PHY %lx have no reset pin in device tree.\n", ++ phy_addr); ++ } else { ++ dev_dbg(phydev_dev(phydev), ++ "Assert PHY %lx HWRST until config_init\n", ++ phy_addr); ++ priv->hw_reset = en8801s_reset; ++ } ++ ++#else ++ if (mdiodev->reset_gpio) { ++ dev_dbg(phydev_dev(phydev), ++ "Assert PHY %lx HWRST until phy_init_hw\n", ++ phy_addr); ++ phy_device_reset(phydev, 1); ++ } ++#endif ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE) ++static int airoha_mmd_read(struct phy_device *phydev, ++ int devad, u16 reg) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int ret = 0; ++ u16 cl45_value; ++ ++ ret = __airoha_cl45_read(mbus, phy_addr, devad, reg, &cl45_value); ++ if (ret < 0) ++ return ret; ++ ++ return cl45_value; ++} ++ ++static int airoha_mmd_write(struct phy_device *phydev, ++ int devad, u16 reg, u16 val) ++{ ++ struct mii_bus *mbus = phydev_mdio_bus(phydev); ++ int phy_addr = phydev_phy_addr(phydev); ++ int pbus_addr = phydev_pbus_addr(phydev); ++ unsigned long pbus_data; ++ int ret = 0; ++ ++ if (MDIO_MMD_AN == devad && MDIO_AN_EEE_ADV == reg) { ++ if (val == 0) { ++ pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xA == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xC << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xE << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ } ++ } else { ++ pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); ++ if (0xE == ((pbus_data & 0x07c00000) >> 22)) { ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xC << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ pbus_data = (pbus_data & 0xf83fffff) | ++ (0xA << 22); ++ __airoha_pbus_write(mbus, pbus_addr, 0x1960, ++ pbus_data); ++ mdelay(10); ++ } ++ } ++ } ++ ++ ret = __airoha_cl45_write(mbus, phy_addr, devad, reg, val); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++#endif ++ ++static struct phy_driver Airoha_driver[] = { ++ { ++ .phy_id = EN8801SC_PHY_ID, ++ .name = "Airoha EN8801SC", ++ .phy_id_mask = 0x0ffffff0, ++ .features = PHY_GBIT_FEATURES, ++ .probe = en8801s_probe, ++ .config_init = en8801s_phase1_init, ++ .config_aneg = genphy_config_aneg, ++ .read_status = en8801s_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE) ++ .read_mmd = airoha_mmd_read, ++ .write_mmd = airoha_mmd_write, ++#endif ++ } ++}; ++ ++module_phy_driver(Airoha_driver); ++ ++static struct mdio_device_id __maybe_unused Airoha_tbl[] = { ++ { EN8801SC_PHY_ID, 0x0ffffff0 }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, Airoha_tbl); +diff --git a/target/linux/mediatek/files/drivers/net/phy/en8801sc.h b/target/linux/mediatek/files/drivers/net/phy/en8801sc.h +new file mode 100644 +index 0000000000..0a077c34ab +--- /dev/null ++++ b/target/linux/mediatek/files/drivers/net/phy/en8801sc.h +@@ -0,0 +1,255 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* FILE NAME: en8801sc.h ++ * PURPOSE: ++ * Define EN8801SC driver function ++ * ++ * NOTES: ++ * ++ */ ++ ++#ifndef __EN8801SC_H ++#define __EN8801SC_H ++ ++/* NAMING DECLARATIONS ++ */ ++#define EN8801S_DRIVER_VERSION "1.1.7_Generic" ++#define EN8801S_PBUS_DEFAULT_ID 0x1e ++#define EN8801S_RG_ETHER_PHY_OUI 0x19a4 ++#define EN8801S_RG_SMI_ADDR 0x19a8 ++#define EN8801S_RG_BUCK_CTL 0x1a20 ++#define EN8801S_RG_LTR_CTL 0x0cf8 ++ ++#define EN8801S_PBUS_OUI 0x17a5 ++#define EN8801S_PHY_ID1 0x03a2 ++#define EN8801S_PHY_ID2 0x9461 ++#define EN8801SC_PHY_ID 0x03a29471 ++ ++#define LED_ON_CTRL(i) (0x024 + ((i)*2)) ++#define LED_ON_EN (1 << 15) ++#define LED_ON_POL (1 << 14) ++#define LED_ON_EVT_MASK (0x7f) ++/* LED ON Event Option.B */ ++#define LED_ON_EVT_FORCE (1 << 6) ++#define LED_ON_EVT_LINK_DOWN (1 << 3) ++#define LED_ON_EVT_LINK_10M (1 << 2) ++#define LED_ON_EVT_LINK_100M (1 << 1) ++#define LED_ON_EVT_LINK_1000M (1 << 0) ++/* LED ON Event Option.E */ ++ ++#define LED_BLK_CTRL(i) (0x025 + ((i)*2)) ++#define LED_BLK_EVT_MASK (0x3ff) ++/* LED Blinking Event Option.B*/ ++#define LED_BLK_EVT_FORCE (1 << 9) ++#define LED_BLK_EVT_10M_RX_ACT (1 << 5) ++#define LED_BLK_EVT_10M_TX_ACT (1 << 4) ++#define LED_BLK_EVT_100M_RX_ACT (1 << 3) ++#define LED_BLK_EVT_100M_TX_ACT (1 << 2) ++#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) ++#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) ++/* LED Blinking Event Option.E*/ ++#define LED_ENABLE 1 ++#define LED_DISABLE 0 ++ ++#define LINK_UP 1 ++#define LINK_DOWN 0 ++ ++/* ++SFP Sample for verification ++Tx Reverse, Rx Reverse ++*/ ++#define EN8801S_TX_POLARITY_NORMAL 0x0 ++#define EN8801S_TX_POLARITY_REVERSE 0x1 ++ ++#define EN8801S_RX_POLARITY_NORMAL (0x1 << 1) ++#define EN8801S_RX_POLARITY_REVERSE (0x0 << 1) ++ ++/* ++The following led_cfg example is for reference only. ++LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, ++LED6 10/100M/LINK/ACT(GPIO9) <-> BASE_T_LED1, ++LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, ++*/ ++/* User-defined.B */ ++#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_1000M) ++#define BASE_T_LED0_BLK_CFG \ ++ (LED_BLK_EVT_1000M_TX_ACT | \ ++ LED_BLK_EVT_1000M_RX_ACT) ++#define BASE_T_LED1_ON_CFG \ ++ (LED_ON_EVT_LINK_100M | \ ++ LED_ON_EVT_LINK_10M) ++#define BASE_T_LED1_BLK_CFG \ ++ (LED_BLK_EVT_100M_TX_ACT | \ ++ LED_BLK_EVT_100M_RX_ACT | \ ++ LED_BLK_EVT_10M_TX_ACT | \ ++ LED_BLK_EVT_10M_RX_ACT) ++#define BASE_T_LED2_ON_CFG \ ++ (LED_ON_EVT_LINK_100M) ++#define BASE_T_LED2_BLK_CFG \ ++ (LED_BLK_EVT_100M_TX_ACT | \ ++ LED_BLK_EVT_100M_RX_ACT) ++#define BASE_T_LED3_ON_CFG (0x0) ++#define BASE_T_LED3_BLK_CFG (0x0) ++/* User-defined.E */ ++ ++#define EN8801S_LED_COUNT 4 ++ ++#define MAX_RETRY 5 ++#define MAX_OUI_CHECK 2 ++/* CL45 MDIO control */ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MII_MMD_ADDR_DATA_REG 0x0e ++#define MMD_OP_MODE_DATA BIT(14) ++ ++#define MAX_TRG_COUNTER 5 ++ ++/* CL22 Reg Support Page Select */ ++#define RgAddr_Reg1Fh 0x1f ++#define CL22_Page_Reg 0x0000 ++#define CL22_Page_ExtReg 0x0001 ++#define CL22_Page_MiscReg 0x0002 ++#define CL22_Page_LpiReg 0x0003 ++#define CL22_Page_tReg 0x02A3 ++#define CL22_Page_TrReg 0x52B5 ++ ++/* CL45 Reg Support DEVID */ ++#define DEVID_03 0x03 ++#define DEVID_07 0x07 ++#define DEVID_1E 0x1E ++#define DEVID_1F 0x1F ++ ++/* TokenRing Reg Access */ ++#define TrReg_PKT_XMT_STA 0x8000 ++#define TrReg_WR 0x8000 ++#define TrReg_RD 0xA000 ++ ++#define RgAddr_LPI_1Ch 0x1c ++#define RgAddr_AUXILIARY_1Dh 0x1d ++#define RgAddr_PMA_00h 0x0f80 ++#define RgAddr_PMA_01h 0x0f82 ++#define RgAddr_PMA_17h 0x0fae ++#define RgAddr_PMA_18h 0x0fb0 ++#define RgAddr_DSPF_03h 0x1686 ++#define RgAddr_DSPF_06h 0x168c ++#define RgAddr_DSPF_08h 0x1690 ++#define RgAddr_DSPF_0Ch 0x1698 ++#define RgAddr_DSPF_0Dh 0x169a ++#define RgAddr_DSPF_0Fh 0x169e ++#define RgAddr_DSPF_10h 0x16a0 ++#define RgAddr_DSPF_11h 0x16a2 ++#define RgAddr_DSPF_13h 0x16a6 ++#define RgAddr_DSPF_14h 0x16a8 ++#define RgAddr_DSPF_1Bh 0x16b6 ++#define RgAddr_DSPF_1Ch 0x16b8 ++#define RgAddr_TR_26h 0x0ecc ++#define RgAddr_R1000DEC_15h 0x03aa ++#define RgAddr_R1000DEC_17h 0x03ae ++ ++#define LED_BCR (0x021) ++#define LED_BCR_EXT_CTRL (1 << 15) ++#define LED_BCR_CLK_EN (1 << 3) ++#define LED_BCR_TIME_TEST (1 << 2) ++#define LED_BCR_MODE_MASK (3) ++#define LED_BCR_MODE_DISABLE (0) ++ ++#define LED_ON_DUR (0x022) ++#define LED_ON_DUR_MASK (0xffff) ++ ++#define LED_BLK_DUR (0x023) ++#define LED_BLK_DUR_MASK (0xffff) ++ ++#define LED_GPIO_SEL_MASK 0x7FFFFFF ++ ++#define UNIT_LED_BLINK_DURATION 1024 ++ ++/* Invalid data */ ++#define INVALID_DATA 0xffffffff ++ ++#define LED_SET_EVT(reg, cod, result, bit) do \ ++ { \ ++ if (reg & cod) { \ ++ result |= bit; \ ++ } \ ++ } while (0) ++ ++#define LED_SET_GPIO_SEL(gpio, led, val) \ ++ (val |= (led << (8 * (gpio % 4)))) \ ++ ++ ++/* DATA TYPE DECLARATIONS ++ */ ++struct AIR_BASE_T_LED_CFG_S { ++ u16 en; ++ u16 gpio; ++ u16 pol; ++ u16 on_cfg; ++ u16 blk_cfg; ++}; ++ ++union gephy_all_REG_LpiReg1Ch { ++ struct { ++ /* b[15:00] */ ++ u16 smi_deton_wt : 3; ++ u16 smi_det_mdi_inv : 1; ++ u16 smi_detoff_wt : 3; ++ u16 smi_sigdet_debouncing_en : 1; ++ u16 smi_deton_th : 6; ++ u16 rsv_14 : 2; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg324h { ++ struct { ++ /* b[15:00] */ ++ u16 rg_smi_detcnt_max : 6; ++ u16 rsv_6 : 2; ++ u16 rg_smi_det_max_en : 1; ++ u16 smi_det_deglitch_off : 1; ++ u16 rsv_10 : 6; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg012h { ++ struct { ++ /* b[15:00] */ ++ u16 da_tx_i2mpb_a_tbt : 6; ++ u16 rsv_6 : 4; ++ u16 da_tx_i2mpb_a_gbe : 6; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++union gephy_all_REG_dev1Eh_reg017h { ++ struct { ++ /* b[15:00] */ ++ u16 da_tx_i2mpb_b_tbt : 6; ++ u16 rsv_6 : 2; ++ u16 da_tx_i2mpb_b_gbe : 6; ++ u16 rsv_14 : 2; ++ } DataBitField; ++ u16 DATA; ++}; ++ ++enum { ++ AIR_LED_BLK_DUR_32M, ++ AIR_LED_BLK_DUR_64M, ++ AIR_LED_BLK_DUR_128M, ++ AIR_LED_BLK_DUR_256M, ++ AIR_LED_BLK_DUR_512M, ++ AIR_LED_BLK_DUR_1024M, ++ AIR_LED_BLK_DUR_LAST ++}; ++ ++enum { ++ AIR_ACTIVE_LOW, ++ AIR_ACTIVE_HIGH, ++}; ++ ++enum { ++ AIR_LED_MODE_DISABLE, ++ AIR_LED_MODE_USER_DEFINE, ++ AIR_LED_MODE_LAST ++}; ++ ++#endif /* End of __EN8801SC_H */ +diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds b/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds +index c81bd2cd97..049779ed6c 100644 +--- a/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds ++++ b/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds +@@ -9,6 +9,10 @@ case $board in + cudy,wr3000-v1) + ucidef_set_led_netdev "wan" "wan" "blue:wan" "wan" + ;; ++edgecore,eap111) ++ ucidef_set_led_netdev "wan" "wan" "orange:wan" "eth1" ++ ucidef_set_led_netdev "wlan5g" "WLAN5G" "blue:wlan5g" "phy1-ap0" ++ ;; + mercusys,mr90x-v1) + ucidef_set_led_netdev "lan0" "lan0" "green:lan0" "lan0" "link tx rx" + ucidef_set_led_netdev "lan1" "lan2" "green:lan1" "lan1" "link tx rx" +diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +index c05c5d25e4..cfc615c943 100644 +--- a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network ++++ b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +@@ -20,6 +20,9 @@ mediatek_setup_interfaces() + cudy,wr3000-v1) + ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan" + ;; ++ edgecore,eap111) ++ ucidef_set_interfaces_lan_wan eth0 eth1 ++ ;; + glinet,gl-mt3000) + ucidef_set_interfaces_lan_wan eth1 eth0 + ;; +diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 +index 4cae8c50ac..5570cf8db6 100644 +--- a/target/linux/mediatek/filogic/config-5.15 ++++ b/target/linux/mediatek/filogic/config-5.15 +@@ -1,5 +1,6 @@ + CONFIG_64BIT=y + # CONFIG_AHCI_MTK is not set ++CONFIG_AIROHA_EN8801SC_PHY=y + CONFIG_AQUANTIA_PHY=y + CONFIG_ARCH_DMA_ADDR_T_64BIT=y + CONFIG_ARCH_KEEP_MEMBLOCK=y +diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk +index fd83b9d441..10cdc28578 100644 +--- a/target/linux/mediatek/image/filogic.mk ++++ b/target/linux/mediatek/image/filogic.mk +@@ -160,6 +160,22 @@ define Device/cudy_wr3000-v1 + endef + TARGET_DEVICES += cudy_wr3000-v1 + ++define Device/edgecore_eap111 ++ DEVICE_VENDOR := Edgecore ++ DEVICE_MODEL := eap111 ++ DEVICE_DTS := mt7981a-edgecore-eap111 ++ DEVICE_DTS_DIR := ../dts ++ SUPPORTED_DEVICES += edgecore,eap111 ++ DEVICE_PACKAGES := kmod-mt7981-firmware mt7981-wo-firmware ++ UBINIZE_OPTS := -E 5 ++ BLOCKSIZE := 128k ++ PAGESIZE := 2048 ++ IMAGE_SIZE := 246272k ++ KERNEL_IN_UBI := 1 ++ IMAGE/sysupgrade.bin := sysupgrade-tar ++endef ++TARGET_DEVICES += edgecore_eap111 ++ + define Device/glinet_gl-mt3000 + DEVICE_VENDOR := GL.iNet + DEVICE_MODEL := GL-MT3000 +diff --git a/target/linux/mediatek/patches-5.15/999-en8801sc.patch b/target/linux/mediatek/patches-5.15/999-en8801sc.patch +new file mode 100644 +index 0000000000..fdfa3ded72 +--- /dev/null ++++ b/target/linux/mediatek/patches-5.15/999-en8801sc.patch +@@ -0,0 +1,28 @@ ++Index: linux-5.15.120/drivers/net/phy/Kconfig ++=================================================================== ++--- linux-5.15.120.orig/drivers/net/phy/Kconfig +++++ linux-5.15.120/drivers/net/phy/Kconfig ++@@ -242,6 +242,11 @@ config DAVICOM_PHY ++ help ++ Currently supports dm9161e and dm9131 ++ +++config AIROHA_EN8801SC_PHY +++ tristate "Drivers for Airoha EN8801S Gigabit PHYs for MediaTek SoC." +++ help +++ Currently supports the Airoha EN8801S PHY for MediaTek SoC. +++ ++ config ICPLUS_PHY ++ tristate "ICPlus PHYs" ++ help ++Index: linux-5.15.120/drivers/net/phy/Makefile ++=================================================================== ++--- linux-5.15.120.orig/drivers/net/phy/Makefile +++++ linux-5.15.120/drivers/net/phy/Makefile ++@@ -71,6 +71,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o ++ obj-$(CONFIG_DP83867_PHY) += dp83867.o ++ obj-$(CONFIG_DP83869_PHY) += dp83869.o ++ obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o +++obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o ++ obj-$(CONFIG_FIXED_PHY) += fixed_phy.o ++ obj-$(CONFIG_ICPLUS_PHY) += icplus.o ++ obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o +-- +2.34.1 +