From 63ddbc67679cdd0ca796f652e84906101df12335 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 3 Jan 2025 21:46:13 +0100 Subject: [PATCH] ath79: reset ETH switch for AR9344 According to datasheet, on AR9344 the switch and switch analog need to be reset first before initiating a full reset. Resetting these systems fixes spurious reset hangs on Atheros AR9344 SoCs. Link: https://github.com/freifunk-gluon/gluon/issues/2904 Signed-off-by: David Bauer --- ...et-ath79-reset-ETH-switch-for-AR9344.patch | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 target/linux/ath79/patches-6.6/101-reset-ath79-reset-ETH-switch-for-AR9344.patch diff --git a/target/linux/ath79/patches-6.6/101-reset-ath79-reset-ETH-switch-for-AR9344.patch b/target/linux/ath79/patches-6.6/101-reset-ath79-reset-ETH-switch-for-AR9344.patch new file mode 100644 index 0000000000..dcac5be58b --- /dev/null +++ b/target/linux/ath79/patches-6.6/101-reset-ath79-reset-ETH-switch-for-AR9344.patch @@ -0,0 +1,104 @@ +From: David Bauer +Date: Tue, 2 Jan 2025 19:22:40 +0100 +Subject: [PATCH] reset: ath79: reset ETH switch for AR9344 + +According to datasheet, on AR9344 the switch and switch analog need to +be reset first before initiating a full reset. + +Resetting these systems fixes spurious reset hangs on Atheros AR9344 +SoCs. + +Link: https://github.com/freifunk-gluon/gluon/issues/2904 + +Signed-off-by: David Bauer + +--- a/drivers/reset/reset-ath79.c ++++ b/drivers/reset/reset-ath79.c +@@ -12,8 +12,11 @@ + #include + #include + #include ++#include ++#include + + struct ath79_reset { ++ struct platform_device *pdev; + struct reset_controller_dev rcdev; + struct notifier_block restart_nb; + void __iomem *base; +@@ -21,16 +24,13 @@ struct ath79_reset { + }; + + #define FULL_CHIP_RESET 24 ++#define ETH_SWITCH_RESET 8 ++#define ETH_SWITCH_ARESET 12 + +-static int ath79_reset_update(struct reset_controller_dev *rcdev, ++static void __ath79_reset_update_unlocked(struct ath79_reset *ath79_reset, + unsigned long id, bool assert) + { +- struct ath79_reset *ath79_reset = +- container_of(rcdev, struct ath79_reset, rcdev); +- unsigned long flags; + u32 val; +- +- spin_lock_irqsave(&ath79_reset->lock, flags); + val = readl(ath79_reset->base); + if (assert) + val |= BIT(id); +@@ -39,6 +39,17 @@ static int ath79_reset_update(struct res + writel(val, ath79_reset->base); + /* Flush cache */ + readl(ath79_reset->base); ++} ++ ++static int ath79_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct ath79_reset *ath79_reset = ++ container_of(rcdev, struct ath79_reset, rcdev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ath79_reset->lock, flags); ++ __ath79_reset_update_unlocked(ath79_reset, id, assert); + spin_unlock_irqrestore(&ath79_reset->lock, flags); + + return 0; +@@ -79,8 +90,27 @@ static int ath79_reset_restart_handler(s + { + struct ath79_reset *ath79_reset = + container_of(nb, struct ath79_reset, restart_nb); ++ unsigned long flags; + +- ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET); ++ spin_lock_irqsave(&ath79_reset->lock, flags); ++ ++ if (of_device_is_compatible(ath79_reset->pdev->dev.of_node, "qca,ar9340-reset")) { ++ /** ++ * AR9344 has been observed to hang on reboot in rare cases. ++ * ++ * Datasheet states to reset the ETH switch systems before asserting ++ * full chip reset. See page 111 of the AR9344 datasheet. ++ */ ++ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_RESET, true); ++ mdelay(10); ++ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_ARESET, true); ++ mdelay(10); ++ } ++ ++ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true); ++ mdelay(10); ++ ++ spin_unlock_irqrestore(&ath79_reset->lock, flags); + + return NOTIFY_DONE; + } +@@ -95,6 +125,8 @@ static int ath79_reset_probe(struct plat + if (!ath79_reset) + return -ENOMEM; + ++ ath79_reset->pdev = pdev; ++ + ath79_reset->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ath79_reset->base)) + return PTR_ERR(ath79_reset->base); -- 2.30.2