cyberchallenge-modem/buildroot/board/tiesse/tgr/kernel-patches/1006-imx8mm-shut.patch

323 lines
8.3 KiB
Diff
Raw Permalink Normal View History

Index: drivers/net/phy/phy.c
===================================================================
--- drivers/net/phy/phy.c
+++ linux-imx/drivers/net/phy/phy.c
@@ -55,6 +55,7 @@ static const char *phy_state_to_str(enum
PHY_STATE_STR(NOLINK)
PHY_STATE_STR(FORCING)
PHY_STATE_STR(CHANGELINK)
+ PHY_STATE_STR(POWERED_DOWN)
PHY_STATE_STR(HALTED)
PHY_STATE_STR(RESUMING)
}
@@ -241,6 +242,33 @@ static void phy_sanitize_settings(struct
}
}
+static int phy_shut(struct phy_device *phydev)
+{
+ mutex_lock(&phydev->lock);
+ phydev->power = PHY_POWER_DOWN;
+ if (PHY_HALTED == phydev->state) {
+ mutex_unlock(&phydev->lock);
+ return 0;
+ }
+ phydev->state = PHY_POWERED_DOWN;
+ mutex_unlock(&phydev->lock);
+ return 0;
+}
+
+static int phy_unshut(struct phy_device *phydev)
+{
+ mutex_lock(&phydev->lock);
+ phydev->power = PHY_POWER_UP;
+ if (PHY_HALTED == phydev->state) {
+ mutex_unlock(&phydev->lock);
+ return 0;
+ }
+ phy_power_up(phydev);
+ phydev->state = PHY_CHANGELINK;
+ mutex_unlock(&phydev->lock);
+ return 0;
+}
+
/**
* phy_ethtool_sset - generic ethtool sset function, handles all the details
* @phydev: target phy_device struct
@@ -257,10 +285,28 @@ static void phy_sanitize_settings(struct
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
u32 speed = ethtool_cmd_speed(cmd);
+ int ret;
if (cmd->phy_address != phydev->mdio.addr)
return -EINVAL;
+ if (PHY_POWERED_DOWN == phydev->state) {
+ if (cmd->power == PHY_POWER_UP) {
+ ret = phy_unshut(phydev);
+ if (ret < 0)
+ return -EIO;
+ phy_trigger_machine(phydev, true);
+ }
+ return 0;
+ }
+ else if (cmd->power == PHY_POWER_DOWN) {
+ ret = phy_shut(phydev);
+ if (ret < 0)
+ return -EIO;
+ phy_trigger_machine(phydev, true);
+ return 0;
+ }
+
/* We make sure that we don't pass unsupported values in to the PHY */
cmd->advertising &= phydev->supported;
@@ -308,10 +354,28 @@ int phy_ethtool_ksettings_set(struct phy
u8 duplex = cmd->base.duplex;
u32 speed = cmd->base.speed;
u32 advertising;
+ int ret;
if (cmd->base.phy_address != phydev->mdio.addr)
return -EINVAL;
+ if (PHY_POWERED_DOWN == phydev->state) {
+ if (cmd->base.power == PHY_POWER_UP) {
+ ret = phy_unshut(phydev);
+ if (ret < 0)
+ return -EIO;
+ phy_trigger_machine(phydev, true);
+ }
+ return 0;
+ }
+ else if (cmd->base.power == PHY_POWER_DOWN) {
+ ret = phy_shut(phydev);
+ if (ret < 0)
+ return -EIO;
+ phy_trigger_machine(phydev, true);
+ return 0;
+ }
+
ethtool_convert_link_mode_to_legacy_u32(&advertising,
cmd->link_modes.advertising);
@@ -379,6 +443,7 @@ void phy_ethtool_ksettings_get(struct ph
cmd->base.autoneg = phydev->autoneg;
cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl;
cmd->base.eth_tp_mdix = phydev->mdix;
+ cmd->base.power = phydev->power;
}
EXPORT_SYMBOL(phy_ethtool_ksettings_get);
@@ -881,7 +946,7 @@ void phy_state_machine(struct work_struc
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
container_of(dwork, struct phy_device, state_queue);
- bool needs_aneg = false, do_suspend = false;
+ bool needs_aneg = false, do_suspend = false, do_power_down = false;
enum phy_state old_state;
int err = 0;
int old_link;
@@ -1014,6 +1079,14 @@ void phy_state_machine(struct work_struc
do_suspend = true;
}
break;
+ case PHY_POWERED_DOWN:
+ phy_read_status(phydev);
+ if (phydev->link) {
+ phydev->link = 0;
+ phy_link_down(phydev, true);
+ do_power_down = true;
+ }
+ break;
case PHY_RESUMING:
if (AUTONEG_ENABLE == phydev->autoneg) {
err = phy_aneg_done(phydev);
@@ -1059,8 +1132,14 @@ void phy_state_machine(struct work_struc
if (needs_aneg)
err = phy_start_aneg_priv(phydev, false);
- else if (do_suspend)
- phy_suspend(phydev);
+ else {
+ if (do_suspend)
+ phy_suspend(phydev);
+ if (do_power_down) {
+ phy_power_down(phydev);
+ phy_read_status(phydev);
+ }
+ }
if (err < 0)
phy_error(phydev);
Index: drivers/net/phy/phy_device.c
===================================================================
--- drivers/net/phy/phy_device.c
+++ linux-imx/drivers/net/phy/phy_device.c
@@ -1230,6 +1230,31 @@ out:
}
EXPORT_SYMBOL(phy_loopback);
+int phy_power_down(struct phy_device *phydev)
+{
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+ int ret = 0;
+
+ if (phydev->drv && phydrv->suspend)
+ ret = phydrv->suspend(phydev);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(phy_power_down);
+
+int phy_power_up(struct phy_device *phydev)
+{
+ struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
+ int ret = 0;
+
+ if (phydev->drv && phydrv->resume)
+ ret = phydrv->resume(phydev);
+
+ return ret;
+}
+EXPORT_SYMBOL(phy_power_up);
+
/* Generic PHY support and helper functions */
/**
@@ -1501,6 +1526,7 @@ EXPORT_SYMBOL(genphy_update_link);
*/
int genphy_read_status(struct phy_device *phydev)
{
+ int bmcr;
int adv;
int err;
int lpa;
@@ -1513,6 +1539,10 @@ int genphy_read_status(struct phy_device
if (err)
return err;
+ bmcr = phy_read(phydev, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
phydev->lp_advertising = 0;
if (AUTONEG_ENABLE == phydev->autoneg) {
@@ -1567,11 +1597,6 @@ int genphy_read_status(struct phy_device
phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
}
} else {
- int bmcr = phy_read(phydev, MII_BMCR);
-
- if (bmcr < 0)
- return bmcr;
-
if (bmcr & BMCR_FULLDPLX)
phydev->duplex = DUPLEX_FULL;
else
@@ -1588,6 +1613,11 @@ int genphy_read_status(struct phy_device
phydev->asym_pause = 0;
}
+ if (bmcr & BMCR_PDOWN)
+ phydev->power = PHY_POWER_DOWN;
+ else
+ phydev->power = PHY_POWER_UP;
+
return 0;
}
EXPORT_SYMBOL(genphy_read_status);
Index: include/linux/phy.h
===================================================================
--- include/linux/phy.h
+++ linux-imx/include/linux/phy.h
@@ -348,6 +348,7 @@ enum phy_state {
PHY_NOLINK,
PHY_FORCING,
PHY_CHANGELINK,
+ PHY_POWERED_DOWN,
PHY_HALTED,
PHY_RESUMING
};
@@ -447,6 +448,8 @@ struct phy_device {
int link_timeout;
+ int power;
+
#ifdef CONFIG_LED_TRIGGER_PHY
struct phy_led_trigger *phy_led_triggers;
unsigned int phy_num_led_triggers;
@@ -819,6 +822,8 @@ int phy_suspend(struct phy_device *phyde
int phy_resume(struct phy_device *phydev);
int __phy_resume(struct phy_device *phydev);
int phy_loopback(struct phy_device *phydev, bool enable);
+int phy_power_up(struct phy_device *phydev);
+int phy_power_down(struct phy_device *phydev);
struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
phy_interface_t interface);
struct phy_device *phy_find_first(struct mii_bus *bus);
Index: include/uapi/linux/ethtool.h
===================================================================
--- include/uapi/linux/ethtool.h
+++ linux-imx/include/uapi/linux/ethtool.h
@@ -114,7 +114,10 @@ struct ethtool_cmd {
__u8 eth_tp_mdix;
__u8 eth_tp_mdix_ctrl;
__u32 lp_advertising;
- __u32 reserved[2];
+ __u8 power;
+ __u8 reserved2;
+ __u16 reserved3;
+ __u32 reserved[1];
};
static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
@@ -1664,6 +1667,11 @@ static inline int ethtool_validate_duple
#define ETH_MODULE_SFF_8436 0x4
#define ETH_MODULE_SFF_8436_LEN 256
+/* TIESSE Power, up or down. */
+#define PHY_POWER_IGNORE 0x0
+#define PHY_POWER_DOWN 0x1
+#define PHY_POWER_UP 0x2
+
/* Reset flags */
/* The reset() operation must clear the flags for the components which
* were actually reset. On successful return, the flags indicate the
@@ -1808,7 +1816,8 @@ struct ethtool_link_settings {
__u8 eth_tp_mdix_ctrl;
__s8 link_mode_masks_nwords;
__u8 transceiver;
- __u8 reserved1[3];
+ __u8 power;
+ __u8 reserved1[2];
__u32 reserved[7];
__u32 link_mode_masks[0];
/* layout of link_mode_masks fields:
Index: net/core/ethtool.c
===================================================================
--- net/core/ethtool.c
+++ linux-imx/net/core/ethtool.c
@@ -480,6 +480,8 @@ convert_legacy_settings_to_link_ksetting
= legacy_settings->eth_tp_mdix;
link_ksettings->base.eth_tp_mdix_ctrl
= legacy_settings->eth_tp_mdix_ctrl;
+ link_ksettings->base.power
+ = legacy_settings->power;
return retval;
}
@@ -526,6 +528,8 @@ convert_link_ksettings_to_legacy_setting
= link_ksettings->base.eth_tp_mdix_ctrl;
legacy_settings->transceiver
= link_ksettings->base.transceiver;
+ legacy_settings->power
+ = link_ksettings->base.power;
return retval;
}