-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: freifunk-gluon/gluon#2904 Signed-off-by: David Bauer <[email protected]>
- Loading branch information
1 parent
39b61ee
commit 916af73
Showing
1 changed file
with
104 additions
and
0 deletions.
There are no files selected for viewing
104 changes: 104 additions & 0 deletions
104
target/linux/ath79/patches-6.6/101-reset-ath79-reset-ETH-switch-for-AR9344.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
From: David Bauer <[email protected]> | ||
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 <[email protected]> | ||
|
||
--- a/drivers/reset/reset-ath79.c | ||
+++ b/drivers/reset/reset-ath79.c | ||
@@ -12,8 +12,11 @@ | ||
#include <linux/platform_device.h> | ||
#include <linux/reset-controller.h> | ||
#include <linux/reboot.h> | ||
+#include <linux/delay.h> | ||
+#include <linux/of.h> | ||
|
||
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); |