mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-30 01:52:51 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1753 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1753 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From aa7fc7b7a6efca7bf026648e6f645507d1a16408 Mon Sep 17 00:00:00 2001
 | |
| From: John Crispin <john@phrozen.org>
 | |
| Date: Tue, 5 Sep 2023 08:58:23 +0200
 | |
| Subject: [PATCH] mediatek: add edgecore eap111 support
 | |
| 
 | |
| Signed-off-by: John Crispin <john@phrozen.org>
 | |
| ---
 | |
|  .../uboot-envtools/files/mediatek_filogic     |    1 +
 | |
|  .../mediatek/dts/mt7981a-edgecore-eap111.dts  |  189 +++
 | |
|  .../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 +
 | |
|  9 files changed, 1649 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/package/boot/uboot-envtools/files/mediatek_filogic b/package/boot/uboot-envtools/files/mediatek_filogic
 | |
| index f13beed526..1e596f3063 100644
 | |
| --- a/package/boot/uboot-envtools/files/mediatek_filogic
 | |
| +++ b/package/boot/uboot-envtools/files/mediatek_filogic
 | |
| @@ -44,6 +44,7 @@ mercusys,mr90x-v1)
 | |
|  	local envdev=/dev/mtd$(find_mtd_index "u-boot-env")
 | |
|  	ubootenv_add_uci_config "$envdev" "0x0" "0x20000" "0x20000" "1"
 | |
|  	;;
 | |
| +edgecore,eap111|\
 | |
|  netgear,wax220)
 | |
|  	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
 | |
|  	;;
 | |
| 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..e22c099b34
 | |
| --- /dev/null
 | |
| +++ b/target/linux/mediatek/dts/mt7981a-edgecore-eap111.dts
 | |
| @@ -0,0 +1,189 @@
 | |
| +/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 = <KEY_RESTART>;
 | |
| +			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>;
 | |
| +		managed = "in-band-status";
 | |
| +	};
 | |
| +
 | |
| +	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-ieee802.3-c22";
 | |
| +		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 <linux/kernel.h>
 | |
| +#include <linux/string.h>
 | |
| +#include <linux/errno.h>
 | |
| +#include <linux/unistd.h>
 | |
| +#include <linux/interrupt.h>
 | |
| +#include <linux/init.h>
 | |
| +#include <linux/delay.h>
 | |
| +#include <linux/netdevice.h>
 | |
| +#include <linux/etherdevice.h>
 | |
| +#include <linux/skbuff.h>
 | |
| +#include <linux/spinlock.h>
 | |
| +#include <linux/mm.h>
 | |
| +#include <linux/module.h>
 | |
| +#include <linux/mii.h>
 | |
| +#include <linux/ethtool.h>
 | |
| +#include <linux/phy.h>
 | |
| +#include <linux/delay.h>
 | |
| +
 | |
| +#include <linux/uaccess.h>
 | |
| +#include <linux/version.h>
 | |
| +#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
 | |
| +#include <linux/of_gpio.h>
 | |
| +#include <linux/gpio/consumer.h>
 | |
| +#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 ea126bc46f..c2744661a8 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 e5872e7fe4..78364e6787 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
 | |
| @@ -24,6 +24,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 2ffc466b7c..8aca4f15d2 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 846fbcbf2c..620528670e 100644
 | |
| --- a/target/linux/mediatek/image/filogic.mk
 | |
| +++ b/target/linux/mediatek/image/filogic.mk
 | |
| @@ -191,6 +191,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 | append-metadata
 | |
| +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
 | |
| 
 | 
