[][kernel][common][eth][Update Airoha EN8801SC 1G PHY driver to v1.1.8 Generic]
[Description]
Change Airoha EN8801SC 1G PHY driver to v1.1.8 Generic.
Change Log:
[2024/01/19] V1.1.8_Generic
* EN8801S E4 supported.
If your board that GMAC2 connects with Airoha EN8801SC, please change
the eth node as following.
=====================================================================
ð {
...
gmac1: mac@1 {
compatible = "mediatek,eth-mac";
reg = <1>;
phy-mode = "sgmii";
phy-handle = <&phy24>;
};
mdio: mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
phy24: phy@24 {
compatible = "ethernet-phy-id03a2.9471";
reg = <24>;
phy-mode = "sgmii";
full-duplex;
pause;
};
...
};
};
=====================================================================
In addition, if EN8801SC connects with a RESET GPIO, please check the
GPIO number, and then add reset-gpio related definition to above phy
node.
=====================================================================
reset-gpios = <&gpio 6 1>;
reset-assert-us = <10000>;
reset-deassert-us = <10000>;
=====================================================================
If without this patch, kernel cannot load up-to-date PHY driver
for the Airoha EN8801SC.
[Release-log]
N/A
Change-Id: Ie39ad204685b76b8262ee54f522235a37e4923c7
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8610305
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c
index f8c5ad6..2cbea72 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.c
@@ -65,6 +65,7 @@
struct en8801s_priv {
bool first_init;
u16 count;
+ u16 pro_version;
#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE)
struct gpio_desc *hw_reset;
#endif
@@ -104,6 +105,7 @@
/************************************************************************
* F U N C T I O N S
************************************************************************/
+static int en8801s_phase2_init(struct phy_device *phydev);
static unsigned int airoha_cl22_read(struct mii_bus *ebus, int phy_addr,
unsigned int phy_register, unsigned int *read_data)
{
@@ -472,7 +474,8 @@
static int en8801s_phase1_init(struct phy_device *phydev)
{
unsigned long pbus_data;
- int pbusAddress = EN8801S_PBUS_DEFAULT_ID;
+ int pbus_addr = EN8801S_PBUS_DEFAULT_ADDR;
+ int phy_addr = EN8801S_PHY_DEFAULT_ADDR;
u16 reg_value;
int retry, ret = 0;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
@@ -489,27 +492,30 @@
retry = MAX_OUI_CHECK;
while (1) {
- pbus_data = airoha_pbus_read(mbus, pbusAddress,
+ pbus_data = airoha_pbus_read(mbus, pbus_addr,
EN8801S_RG_ETHER_PHY_OUI); /* PHY OUI */
if (pbus_data == EN8801S_PBUS_OUI) {
dev_info(dev, "PBUS addr 0x%x: Start initialized.\n",
- pbusAddress);
+ pbus_addr);
break;
}
- pbusAddress = phydev_pbus_addr(phydev);
+ pbus_addr = 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);
+ ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_BUCK_CTL, 0x03);
if (ret < 0)
return ret;
+ pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_PROD_VER);
+ priv->pro_version = pbus_data & 0xf;
+ dev_info(dev, "EN8801S Procduct Version :E%d\n", priv->pro_version);
mdelay(10);
- pbus_data = (airoha_pbus_read(mbus, pbusAddress, EN8801S_RG_LTR_CTL)
+ pbus_data = (airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL)
& 0xfffffffc) | BIT(2);
- ret = airoha_pbus_write(mbus, pbusAddress,
+ ret = airoha_pbus_write(mbus, pbus_addr,
EN8801S_RG_LTR_CTL, pbus_data);
if (ret < 0)
return ret;
@@ -517,19 +523,35 @@
pbus_data = (pbus_data & ~BIT(2)) |
EN8801S_RX_POLARITY_NORMAL |
EN8801S_TX_POLARITY_NORMAL;
- ret = airoha_pbus_write(mbus, pbusAddress,
+ ret = airoha_pbus_write(mbus, pbus_addr,
EN8801S_RG_LTR_CTL, pbus_data);
if (ret < 0)
return ret;
mdelay(500);
-
- pbus_data = airoha_pbus_read(mbus, pbusAddress,
+ if (priv->pro_version == 4) {
+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900);
+ dev_dbg(dev, "Before 0x1900 0x%x\n", pbus_data);
+ ret = airoha_pbus_write(mbus, pbus_addr, 0x1900, 0x101009f);
+ if (ret < 0)
+ return ret;
+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900);
+ dev_dbg(dev, "After 0x1900 0x%x\n", pbus_data);
+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8);
+ dev_dbg(dev, "Before 19a8 0x%x\n", pbus_data);
+ ret = airoha_pbus_write(mbus, pbus_addr,
+ 0x19a8, pbus_data & ~BIT(16));
+ if (ret < 0)
+ return ret;
+ pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8);
+ dev_dbg(dev, "After 19a8 0x%x\n", pbus_data);
+ }
+ pbus_data = airoha_pbus_read(mbus, pbus_addr,
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,
+ ret = airoha_pbus_write(mbus, pbus_addr,
EN8801S_RG_SMI_ADDR, pbus_data);
mdelay(10);
@@ -566,6 +588,15 @@
phydev->dev_flags = PHY_STATE_INIT;
dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
+ if (priv->pro_version == 4) {
+ 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;
+ }
return 0;
}
@@ -889,13 +920,15 @@
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;
+ if (priv->pro_version != 4) {
+ 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;
}
- phydev->dev_flags = PHY_STATE_PROCESS;
}
priv->count++;
}
@@ -924,6 +957,7 @@
airoha_pbus_write(mbus, pbus_addr, 0x0600,
0x0c000c00);
if (preSpeed == SPEED_1000) {
+ dev_dbg(dev, "SPEED_1000\n");
ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
0xD801);
if (ret < 0)
@@ -951,6 +985,7 @@
if (ret < 0)
return ret;
} else if (preSpeed == SPEED_100) {
+ dev_dbg(dev, "SPEED_100\n");
ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
0xD401);
if (ret < 0)
@@ -978,6 +1013,7 @@
if (ret < 0)
return ret;
} else if (preSpeed == SPEED_10) {
+ dev_dbg(dev, "SPEED_10\n");
ret = airoha_pbus_write(mbus, pbus_addr, 0x10,
0xD001);
if (ret < 0)
@@ -1022,7 +1058,7 @@
struct mdio_device *mdiodev = &phydev->mdio;
#endif
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1115,7 +1151,6 @@
}
}
}
-
ret = __airoha_cl45_write(mbus, phy_addr, devad, reg, val);
if (ret < 0)
return ret;
diff --git a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h
index 0a077c3..d1e268c 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h
+++ b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/phy/en8801sc.h
@@ -12,12 +12,14 @@
/* NAMING DECLARATIONS
*/
-#define EN8801S_DRIVER_VERSION "1.1.7_Generic"
-#define EN8801S_PBUS_DEFAULT_ID 0x1e
+#define EN8801S_DRIVER_VERSION "1.1.8_Generic"
+#define EN8801S_PBUS_DEFAULT_ADDR 0x1e
+#define EN8801S_PHY_DEFAULT_ADDR 0x1d
#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_RG_PROD_VER 0x18e0
#define EN8801S_PBUS_OUI 0x17a5
#define EN8801S_PHY_ID1 0x03a2
@@ -164,17 +166,10 @@
/* 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)))) \
-
+#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
/* DATA TYPE DECLARATIONS
*/
struct AIR_BASE_T_LED_CFG_S {