Message ID | 1828686.9elolEQQZP@tool |
---|---|
State | Superseded, archived |
Headers | show |
Series | [1/2] mvebu: backport linkstation-poweroff upstream driver | expand |
Hi, > -----Original Message----- > From: openwrt-devel [mailto:openwrt-devel-bounces@lists.openwrt.org] > On Behalf Of Daniel González Cabanelas > Sent: Donnerstag, 27. August 2020 22:21 > To: openwrt-devel@lists.openwrt.org > Subject: [PATCH 1/2] mvebu: backport linkstation-poweroff upstream driver > > Backport the Linkstation poweroff driver from the kernel upstream (commit > a7f79f99541ef) > > This driver is required by the Buffalo LinkStation LS421DE for a correct power > off operation. It also allows to use the WoL feature. > > Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com> > --- > package/kernel/linux/modules/other.mk | 21 +++ > .../030-linkstation-poweroff.patch | 177 ++++++++++++++++++ > 2 files changed, 198 insertions(+) > create mode 100644 target/linux/mvebu/patches-5.4/030-linkstation- > poweroff.patch > > diff --git a/package/kernel/linux/modules/other.mk > b/package/kernel/linux/modules/other.mk > index 6eb9404837..683d539be4 100644 > --- a/package/kernel/linux/modules/other.mk > +++ b/package/kernel/linux/modules/other.mk > @@ -329,6 +329,27 @@ endef > > $(eval $(call KernelPackage,gpio-amd-fch)) > > +define KernelPackage/linkstation-poweroff > + SUBMENU:=$(OTHER_MENU) > + DEPENDS:=@TARGET_mvebu > + TITLE:=Buffalo LinkStation power off driver > + KCONFIG:= \ > + CONFIG_POWER_RESET=y \ > + CONFIG_POWER_RESET_LINKSTATION \ > + CONFIG_POWER_RESET_QNAP=n Since this is specific to mvebu and even refers to symbols only defined in the target, I'd have expected it in target/linux/mvebu/modules.mk? Best Adrian > + > + FILES:=$(LINUX_DIR)/drivers/power/reset/linkstation-poweroff.ko > + AUTOLOAD:=$(call AutoLoad,31,linkstation-poweroff,1) > +endef > + > +define KernelPackage/linkstation-poweroff/description > + This driver supports turning off some Buffalo LinkStations by > + setting an output pin at the ethernet PHY to the correct state. > + It also makes the device compatible with the WoL function. > + Say Y here if you have a Buffalo LinkStation LS421D/E. > +endef > + > +$(eval $(call KernelPackage,linkstation-poweroff)) > > define KernelPackage/ppdev > SUBMENU:=$(OTHER_MENU) > diff --git a/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch > b/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch > new file mode 100644 > index 0000000000..983b1de918 > --- /dev/null > +++ b/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch > @@ -0,0 +1,177 @@ > +--- a/drivers/power/reset/Kconfig > ++++ b/drivers/power/reset/Kconfig > +@@ -99,6 +99,17 @@ > + help > + Reboot support for Hisilicon boards. > + > ++config POWER_RESET_LINKSTATION > ++ tristate "Buffalo LinkStation power-off driver" > ++ depends on ARCH_MVEBU || COMPILE_TEST > ++ depends on OF_MDIO && PHYLIB > ++ help > ++ This driver supports turning off some Buffalo LinkStations by > ++ setting an output pin at the ethernet PHY to the correct state. > ++ It also makes the device compatible with the WoL function. > ++ > ++ Say Y here if you have a Buffalo LinkStation LS421D/E. > ++ > + config POWER_RESET_MSM > + bool "Qualcomm MSM power-off driver" > + depends on ARCH_QCOM > +--- a/drivers/power/reset/Makefile > ++++ b/drivers/power/reset/Makefile > +@@ -10,6 +10,7 @@ > + obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o > + obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o > + obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o > ++obj-${CONFIG_POWER_RESET_LINKSTATION} += linkstation-poweroff.o > + obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o > + obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o > + obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o > +--- a/dev/null > ++++ b/drivers/power/reset/linkstation-poweroff.c > +@@ -0,0 +1,144 @@ > ++// SPDX-License-Identifier: GPL-2.0 > ++/* > ++ * LinkStation power off restart driver > ++ * Copyright (C) 2020 Daniel González Cabanelas <dgcbueu@gmail.com> > ++*/ > ++ > ++#include <linux/module.h> > ++#include <linux/notifier.h> > ++#include <linux/of.h> > ++#include <linux/of_mdio.h> > ++#include <linux/of_platform.h> > ++#include <linux/reboot.h> > ++#include <linux/phy.h> > ++ > ++/* Defines from the eth phy Marvell driver */ > ++#define MII_MARVELL_COPPER_PAGE 0 > ++#define MII_MARVELL_LED_PAGE 3 > ++#define MII_MARVELL_WOL_PAGE 17 > ++#define MII_MARVELL_PHY_PAGE 22 > ++ > ++#define MII_PHY_LED_CTRL 16 > ++#define MII_88E1318S_PHY_LED_TCR 18 > ++#define MII_88E1318S_PHY_WOL_CTRL 16 > ++#define MII_M1011_IEVENT 19 > ++ > ++#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) > ++#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) > ++#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) > ++#define LED2_FORCE_ON (0x8 << 8) > ++#define LEDMASK > GENMASK(11,8) > ++ > ++static struct phy_device *phydev; > ++ > ++static void mvphy_reg_intn(u16 data) > ++{ > ++ int rc = 0, saved_page; > ++ > ++ saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE); > ++ if (saved_page < 0) > ++ goto err; > ++ > ++ /* Force manual LED2 control to let INTn work */ > ++ __phy_modify(phydev, MII_PHY_LED_CTRL, LEDMASK, > LED2_FORCE_ON); > ++ > ++ /* Set the LED[2]/INTn pin to the required state */ > ++ __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, > ++ MII_88E1318S_PHY_LED_TCR_FORCE_INT, > ++ MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | data); > ++ > ++ if (!data) { > ++ /* Clear interrupts to ensure INTn won't be holded in high > state */ > ++ __phy_write(phydev, MII_MARVELL_PHY_PAGE, > MII_MARVELL_COPPER_PAGE); > ++ __phy_read(phydev, MII_M1011_IEVENT); > ++ > ++ /* If WOL was enabled and a magic packet was received > before powering > ++ * off, we won't be able to wake up by sending another magic > packet. > ++ * Clear WOL status. > ++ */ > ++ __phy_write(phydev, MII_MARVELL_PHY_PAGE, > MII_MARVELL_WOL_PAGE); > ++ __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, > ++ > MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); > ++ } > ++err: > ++ rc = phy_restore_page(phydev, saved_page, rc); > ++ if (rc < 0) > ++ dev_err(&phydev->mdio.dev, "Write register failed, %d\n", > rc); > ++ > ++ if (!data) { > ++ /* Slow down the PHY to save energy */ > ++ rc= phy_speed_down(phydev, false); > ++ if (rc < 0) > ++ dev_err(&phydev->mdio.dev, "PHY speed down > failed, %d\n", rc); > ++ } > ++} > ++ > ++static int linkstation_reboot_notifier(struct notifier_block *nb, > ++ unsigned long action, void *unused) { > ++ if (action == SYS_RESTART) > ++ mvphy_reg_intn(MII_88E1318S_PHY_LED_TCR_FORCE_INT); > ++ > ++ return NOTIFY_DONE; > ++} > ++ > ++static struct notifier_block linkstation_reboot_nb = { > ++ .notifier_call = linkstation_reboot_notifier, }; > ++ > ++static void linkstation_poweroff(void) { > ++ unregister_reboot_notifier(&linkstation_reboot_nb); > ++ mvphy_reg_intn(0); > ++ > ++ kernel_restart("Power off"); > ++} > ++ > ++static const struct of_device_id ls_poweroff_of_match[] = { > ++ { .compatible = "buffalo,ls421d" }, > ++ { .compatible = "buffalo,ls421de" }, > ++ { }, > ++}; > ++ > ++static int __init linkstation_poweroff_init(void) { > ++ struct mii_bus *bus; > ++ struct device_node *dn; > ++ > ++ dn = of_find_matching_node(NULL, ls_poweroff_of_match); > ++ if (!dn) > ++ return -ENODEV; > ++ of_node_put(dn); > ++ > ++ dn = of_find_node_by_name(NULL, "mdio"); > ++ if (!dn) > ++ return -ENODEV; > ++ > ++ bus = of_mdio_find_bus(dn); > ++ of_node_put(dn); > ++ if (!bus) > ++ return -EPROBE_DEFER; > ++ > ++ phydev = phy_find_first(bus); > ++ if (!phydev) > ++ return -EPROBE_DEFER; > ++ > ++ register_reboot_notifier(&linkstation_reboot_nb); > ++ pm_power_off = linkstation_poweroff; > ++ > ++ pr_info("LinkStation power off driver registered\n"); > ++ return 0; > ++} > ++ > ++static void __exit linkstation_poweroff_exit(void) { > ++ pm_power_off = NULL; > ++ unregister_reboot_notifier(&linkstation_reboot_nb); > ++} > ++ > ++module_init(linkstation_poweroff_init); > ++module_exit(linkstation_poweroff_exit); > ++ > ++MODULE_AUTHOR("Daniel González Cabanelas <dgcbueu@gmail.com>"); > ++MODULE_DESCRIPTION("LinkStation power off driver"); > ++MODULE_LICENSE("GPL v2"); > -- > 2.28.0 > > > > > > _______________________________________________ > openwrt-devel mailing list > openwrt-devel@lists.openwrt.org > https://lists.openwrt.org/mailman/listinfo/openwrt-devel
diff --git a/package/kernel/linux/modules/other.mk b/package/kernel/linux/modules/other.mk index 6eb9404837..683d539be4 100644 --- a/package/kernel/linux/modules/other.mk +++ b/package/kernel/linux/modules/other.mk @@ -329,6 +329,27 @@ endef $(eval $(call KernelPackage,gpio-amd-fch)) +define KernelPackage/linkstation-poweroff + SUBMENU:=$(OTHER_MENU) + DEPENDS:=@TARGET_mvebu + TITLE:=Buffalo LinkStation power off driver + KCONFIG:= \ + CONFIG_POWER_RESET=y \ + CONFIG_POWER_RESET_LINKSTATION \ + CONFIG_POWER_RESET_QNAP=n + + FILES:=$(LINUX_DIR)/drivers/power/reset/linkstation-poweroff.ko + AUTOLOAD:=$(call AutoLoad,31,linkstation-poweroff,1) +endef + +define KernelPackage/linkstation-poweroff/description + This driver supports turning off some Buffalo LinkStations by + setting an output pin at the ethernet PHY to the correct state. + It also makes the device compatible with the WoL function. + Say Y here if you have a Buffalo LinkStation LS421D/E. +endef + +$(eval $(call KernelPackage,linkstation-poweroff)) define KernelPackage/ppdev SUBMENU:=$(OTHER_MENU) diff --git a/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch b/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch new file mode 100644 index 0000000000..983b1de918 --- /dev/null +++ b/target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch @@ -0,0 +1,177 @@ +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -99,6 +99,17 @@ + help + Reboot support for Hisilicon boards. + ++config POWER_RESET_LINKSTATION ++ tristate "Buffalo LinkStation power-off driver" ++ depends on ARCH_MVEBU || COMPILE_TEST ++ depends on OF_MDIO && PHYLIB ++ help ++ This driver supports turning off some Buffalo LinkStations by ++ setting an output pin at the ethernet PHY to the correct state. ++ It also makes the device compatible with the WoL function. ++ ++ Say Y here if you have a Buffalo LinkStation LS421D/E. ++ + config POWER_RESET_MSM + bool "Qualcomm MSM power-off driver" + depends on ARCH_QCOM +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -10,6 +10,7 @@ + obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o + obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o + obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o ++obj-${CONFIG_POWER_RESET_LINKSTATION} += linkstation-poweroff.o + obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o + obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o + obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o +--- a/dev/null ++++ b/drivers/power/reset/linkstation-poweroff.c +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LinkStation power off restart driver ++ * Copyright (C) 2020 Daniel González Cabanelas <dgcbueu@gmail.com> ++ */ ++ ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of.h> ++#include <linux/of_mdio.h> ++#include <linux/of_platform.h> ++#include <linux/reboot.h> ++#include <linux/phy.h> ++ ++/* Defines from the eth phy Marvell driver */ ++#define MII_MARVELL_COPPER_PAGE 0 ++#define MII_MARVELL_LED_PAGE 3 ++#define MII_MARVELL_WOL_PAGE 17 ++#define MII_MARVELL_PHY_PAGE 22 ++ ++#define MII_PHY_LED_CTRL 16 ++#define MII_88E1318S_PHY_LED_TCR 18 ++#define MII_88E1318S_PHY_WOL_CTRL 16 ++#define MII_M1011_IEVENT 19 ++ ++#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) ++#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) ++#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) ++#define LED2_FORCE_ON (0x8 << 8) ++#define LEDMASK GENMASK(11,8) ++ ++static struct phy_device *phydev; ++ ++static void mvphy_reg_intn(u16 data) ++{ ++ int rc = 0, saved_page; ++ ++ saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE); ++ if (saved_page < 0) ++ goto err; ++ ++ /* Force manual LED2 control to let INTn work */ ++ __phy_modify(phydev, MII_PHY_LED_CTRL, LEDMASK, LED2_FORCE_ON); ++ ++ /* Set the LED[2]/INTn pin to the required state */ ++ __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, ++ MII_88E1318S_PHY_LED_TCR_FORCE_INT, ++ MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | data); ++ ++ if (!data) { ++ /* Clear interrupts to ensure INTn won't be holded in high state */ ++ __phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_COPPER_PAGE); ++ __phy_read(phydev, MII_M1011_IEVENT); ++ ++ /* If WOL was enabled and a magic packet was received before powering ++ * off, we won't be able to wake up by sending another magic packet. ++ * Clear WOL status. ++ */ ++ __phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_WOL_PAGE); ++ __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, ++ MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); ++ } ++err: ++ rc = phy_restore_page(phydev, saved_page, rc); ++ if (rc < 0) ++ dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc); ++ ++ if (!data) { ++ /* Slow down the PHY to save energy */ ++ rc= phy_speed_down(phydev, false); ++ if (rc < 0) ++ dev_err(&phydev->mdio.dev, "PHY speed down failed, %d\n", rc); ++ } ++} ++ ++static int linkstation_reboot_notifier(struct notifier_block *nb, ++ unsigned long action, void *unused) ++{ ++ if (action == SYS_RESTART) ++ mvphy_reg_intn(MII_88E1318S_PHY_LED_TCR_FORCE_INT); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block linkstation_reboot_nb = { ++ .notifier_call = linkstation_reboot_notifier, ++}; ++ ++static void linkstation_poweroff(void) ++{ ++ unregister_reboot_notifier(&linkstation_reboot_nb); ++ mvphy_reg_intn(0); ++ ++ kernel_restart("Power off"); ++} ++ ++static const struct of_device_id ls_poweroff_of_match[] = { ++ { .compatible = "buffalo,ls421d" }, ++ { .compatible = "buffalo,ls421de" }, ++ { }, ++}; ++ ++static int __init linkstation_poweroff_init(void) ++{ ++ struct mii_bus *bus; ++ struct device_node *dn; ++ ++ dn = of_find_matching_node(NULL, ls_poweroff_of_match); ++ if (!dn) ++ return -ENODEV; ++ of_node_put(dn); ++ ++ dn = of_find_node_by_name(NULL, "mdio"); ++ if (!dn) ++ return -ENODEV; ++ ++ bus = of_mdio_find_bus(dn); ++ of_node_put(dn); ++ if (!bus) ++ return -EPROBE_DEFER; ++ ++ phydev = phy_find_first(bus); ++ if (!phydev) ++ return -EPROBE_DEFER; ++ ++ register_reboot_notifier(&linkstation_reboot_nb); ++ pm_power_off = linkstation_poweroff; ++ ++ pr_info("LinkStation power off driver registered\n"); ++ return 0; ++} ++ ++static void __exit linkstation_poweroff_exit(void) ++{ ++ pm_power_off = NULL; ++ unregister_reboot_notifier(&linkstation_reboot_nb); ++} ++ ++module_init(linkstation_poweroff_init); ++module_exit(linkstation_poweroff_exit); ++ ++MODULE_AUTHOR("Daniel González Cabanelas <dgcbueu@gmail.com>"); ++MODULE_DESCRIPTION("LinkStation power off driver"); ++MODULE_LICENSE("GPL v2");
Backport the Linkstation poweroff driver from the kernel upstream (commit a7f79f99541ef) This driver is required by the Buffalo LinkStation LS421DE for a correct power off operation. It also allows to use the WoL feature. Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com> --- package/kernel/linux/modules/other.mk | 21 +++ .../030-linkstation-poweroff.patch | 177 ++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 target/linux/mvebu/patches-5.4/030-linkstation-poweroff.patch