blob: eb37db77b4766453a4669272690696658a76e397 [file] [log] [blame]
From 883cca0b39bbf55862e3944bbcf6a079863e19e2 Mon Sep 17 00:00:00 2001
From: Zhuo Wang <zhuo.wang@amlogic.com>
Date: Wed, 23 Nov 2022 15:12:18 +0800
Subject: [PATCH 83/95] eth: mac wol function [1/2]
PD#SWPL-98490
Problem:
porting wol function
Solution:
porting wol function
Verify:
AR321-T965D4-REF#049
Change-Id: Iea34df3e69d2dc46488a7008eab3788ab5b58094
Signed-off-by: Zhuo Wang <zhuo.wang@amlogic.com>
---
.../ethernet/stmicro/stmmac/dwmac-meson8b.c | 187 ++++++++++++++++++
.../ethernet/stmicro/stmmac/stmmac_platform.h | 4 +-
2 files changed, 190 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
index 5b67f312e816..fecd47046a76 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -20,6 +20,12 @@
#include <linux/stmmac.h>
#include "stmmac_platform.h"
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+#include <linux/amlogic/scpi_protocol.h>
+#include <linux/input.h>
+#include <linux/amlogic/pm.h>
+#include <linux/amlogic/aml_phy_debug.h>
+#endif
#define PRG_ETH0 0x0
@@ -83,6 +89,10 @@ struct meson8b_dwmac;
struct meson8b_dwmac_data {
int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
bool has_prg_eth1_rgmii_rx_delay;
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ int (*suspend)(struct meson8b_dwmac *dwmac);
+ void (*resume)(struct meson8b_dwmac *dwmac);
+#endif
};
struct meson8b_dwmac {
@@ -95,6 +105,9 @@ struct meson8b_dwmac {
u32 tx_delay_ns;
u32 rx_delay_ps;
struct clk *timing_adj_clk;
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ struct input_dev *input_dev;
+#endif
};
struct meson8b_dwmac_clk_configs {
@@ -386,6 +399,19 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
}
#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+void set_wol_notify_bl31(u32 enable_bl31)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(0x8200009D, enable_bl31,
+ 0, 0, 0, 0, 0, 0, &res);
+}
+
+static void set_wol_notify_bl30(u32 enable_bl30)
+{
+ scpi_set_ethernet_wol(enable_bl30);
+}
+
static int aml_custom_setting(struct platform_device *pdev, struct meson8b_dwmac *dwmac)
{
struct device_node *np = pdev->dev.of_node;
@@ -407,6 +433,9 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
struct meson8b_dwmac *dwmac;
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ struct input_dev *input_dev;
+#endif
int ret;
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -503,6 +532,36 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
goto err_remove_config_dt;
#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
aml_custom_setting(pdev, dwmac);
+
+ /*input device to send virtual pwr key for android*/
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ pr_err("[abner test]input_allocate_device failed: %d\n", ret);
+ return -EINVAL;
+ }
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(KEY_POWER, input_dev->keybit);
+ set_bit(133, input_dev->keybit);
+
+ input_dev->name = "input_ethrcu";
+ input_dev->phys = "input_ethrcu/input0";
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_ISA;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->rep[REP_DELAY] = 0xffffffff;
+ input_dev->rep[REP_PERIOD] = 0xffffffff;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = 0x1ff;
+ ret = input_register_device(input_dev);
+ if (ret < 0) {
+ pr_err("[abner test]input_register_device failed: %d\n", ret);
+ input_free_device(input_dev);
+ return -EINVAL;
+ }
+ dwmac->input_dev = input_dev;
+
#endif
return 0;
@@ -512,6 +571,122 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
return ret;
}
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+static int dwmac_suspend(struct meson8b_dwmac *dwmac)
+{
+ pr_info("disable analog\n");
+ writel(0x00000000, phy_analog_config_addr + 0x0);
+ writel(0x003e0000, phy_analog_config_addr + 0x4);
+ writel(0x12844008, phy_analog_config_addr + 0x8);
+ writel(0x0800a40c, phy_analog_config_addr + 0xc);
+ writel(0x00000000, phy_analog_config_addr + 0x10);
+ writel(0x031d161c, phy_analog_config_addr + 0x14);
+ writel(0x00001683, phy_analog_config_addr + 0x18);
+ writel(0x09c0040a, phy_analog_config_addr + 0x44);
+ return 0;
+}
+
+static void dwmac_resume(struct meson8b_dwmac *dwmac)
+{
+ pr_info("recover analog\n");
+ writel(0x19c0040a, phy_analog_config_addr + 0x44);
+ writel(0x0, phy_analog_config_addr + 0x4);
+}
+
+int backup_adv;
+static int meson8b_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ struct meson8b_dwmac *dwmac = priv->plat->bsp_priv;
+ struct phy_device *phydev = ndev->phydev;
+
+ int ret;
+
+ /*open wol*/
+ if (wol_switch_from_user) {
+ set_wol_notify_bl31(true);
+ set_wol_notify_bl30(true);
+ device_init_wakeup(dev, true);
+ priv->wolopts = 0x1 << 5;
+ ndev->wol_enabled = true;
+ /*phy is 100M, change to 10M*/
+ pr_info("link 100M -> 10M\n");
+ backup_adv = phy_read(phydev, MII_ADVERTISE);
+ phy_write(phydev, MII_ADVERTISE, 0x61);
+ mii_lpa_to_linkmode_lpa_t(phydev->advertising, 0x61);
+ genphy_restart_aneg(phydev);
+ msleep(3000);
+
+ ret = stmmac_suspend(dev);
+ } else {
+ set_wol_notify_bl31(false);
+ set_wol_notify_bl30(false);
+ device_init_wakeup(dev, false);
+ ndev->wol_enabled = false;
+
+ ret = stmmac_suspend(dev);
+ if (dwmac->data->suspend)
+ ret = dwmac->data->suspend(dwmac);
+ }
+
+ return ret;
+}
+
+static int meson8b_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ struct meson8b_dwmac *dwmac = priv->plat->bsp_priv;
+ int ret;
+ struct phy_device *phydev = ndev->phydev;
+
+ if (wol_switch_from_user) {
+ ret = stmmac_resume(dev);
+
+ if (get_resume_method() == ETH_PHY_WAKEUP) {
+ pr_info("evan---wol rx--KEY_POWER\n");
+ input_event(dwmac->input_dev,
+ EV_KEY, KEY_POWER, 1);
+ input_sync(dwmac->input_dev);
+ input_event(dwmac->input_dev,
+ EV_KEY, KEY_POWER, 0);
+ input_sync(dwmac->input_dev);
+ }
+
+ phy_write(phydev, MII_ADVERTISE, backup_adv);
+ mii_lpa_to_linkmode_lpa_t(phydev->advertising, backup_adv);
+ genphy_restart_aneg(phydev);
+ } else {
+ if (dwmac->data->resume)
+ dwmac->data->resume(dwmac);
+ ret = stmmac_resume(dev);
+ }
+ return ret;
+}
+
+static int meson8b_dwmac_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int err;
+
+ struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
+
+ input_unregister_device(dwmac->input_dev);
+
+ err = stmmac_dvr_remove(&pdev->dev);
+ if (err < 0)
+ dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
+
+ stmmac_remove_config_dt(pdev, priv->plat);
+
+ return err;
+}
+
+static SIMPLE_DEV_PM_OPS(meson8b_pm_ops,
+ meson8b_suspend, meson8b_resume);
+#endif
static const struct meson8b_dwmac_data meson8b_dwmac_data = {
.set_phy_mode = meson8b_set_phy_mode,
.has_prg_eth1_rgmii_rx_delay = false,
@@ -520,6 +695,10 @@ static const struct meson8b_dwmac_data meson8b_dwmac_data = {
static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
.set_phy_mode = meson_axg_set_phy_mode,
.has_prg_eth1_rgmii_rx_delay = false,
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ .suspend = dwmac_suspend,
+ .resume = dwmac_resume,
+#endif
};
static const struct meson8b_dwmac_data meson_g12a_dwmac_data = {
@@ -554,10 +733,18 @@ MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
static struct platform_driver meson8b_dwmac_driver = {
.probe = meson8b_dwmac_probe,
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ .remove = meson8b_dwmac_remove,
+#else
.remove = stmmac_pltfr_remove,
+#endif
.driver = {
.name = "meson8b-dwmac",
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+ .pm = &meson8b_pm_ops,
+#else
.pm = &stmmac_pltfr_pm_ops,
+#endif
.of_match_table = meson8b_dwmac_match,
},
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 3fff3f59d73d..e29408eda06c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -21,7 +21,9 @@ int stmmac_get_platform_resources(struct platform_device *pdev,
int stmmac_pltfr_remove(struct platform_device *pdev);
extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
-
+#if IS_ENABLED(CONFIG_AMLOGIC_ETH_PRIVE)
+extern void __iomem *phy_analog_config_addr;
+#endif
static inline void *get_stmmac_bsp_priv(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
--
2.25.1