-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
reset: ath79: fix reset sequence for AR9344
According to datasheet, on AR9344 the switch and switch analog need to be reset first before initiating a full reset. This fixes sporadic reboot issues. Instead of rebooting, the device will just hang. Without this patch, I had failed resets after 5, 20 and 250 tries. With this patch I have more than 2200 successful resets. Other chips like AR7100 do not have this specific requirement in the datasheet and also the meaning for bits 8 and 12 is slightly different, so only perform this sequence on AR9344. Signed-off-by: Nico Boehr <[email protected]>
- Loading branch information
Showing
1 changed file
with
92 additions
and
0 deletions.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
patches/openwrt/0006-reset-ath79-fix-reset-sequence-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,92 @@ | ||
From: Nico <[email protected]> | ||
Date: Mon, 16 Dec 2024 22:19:01 +0000 | ||
Subject: reset: ath79: fix reset sequence for AR9344 | ||
|
||
According to datasheet, on AR9344 the switch and switch analog need to | ||
be reset first before initiating a full reset. | ||
|
||
This fixes sporadic reboot issues. Instead of rebooting, the device will | ||
just hang. Without this patch, I had failed resets after 5, 20 and 250 | ||
tries. With this patch I have more than 2200 successful resets. | ||
|
||
Other chips like AR7100 do not have this specific requirement in the | ||
datasheet and also the meaning for bits 8 and 12 is slightly different, | ||
so only perform this sequence on AR9344. | ||
|
||
diff --git a/target/linux/ath79/patches-6.6/940-ath79-fix-reset-sequence.patch b/target/linux/ath79/patches-6.6/940-ath79-fix-reset-sequence.patch | ||
new file mode 100644 | ||
index 0000000000000000000000000000000000000000..dccb8449e9cc03701495afcbc4196540d0b1c15d | ||
--- /dev/null | ||
+++ b/target/linux/ath79/patches-6.6/940-ath79-fix-reset-sequence.patch | ||
@@ -0,0 +1,71 @@ | ||
+--- a/drivers/reset/reset-ath79.c | ||
++++ b/drivers/reset/reset-ath79.c | ||
+@@ -12,6 +12,8 @@ | ||
+ #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 reset_controller_dev rcdev; | ||
+@@ -21,16 +23,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 +38,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 +89,20 @@ 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); | ||
++ /* special reset sequence required for AR9344 - see datasheet p 111 */ | ||
++ if (of_machine_is_compatible("qca,ar9344")) { | ||
++ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_RESET, true); | ||
++ mdelay(2); | ||
++ __ath79_reset_update_unlocked(ath79_reset, ETH_SWITCH_ARESET, true); | ||
++ mdelay(2); | ||
++ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true); | ||
++ mdelay(10); | ||
++ } else | ||
++ __ath79_reset_update_unlocked(ath79_reset, FULL_CHIP_RESET, true); | ||
++ spin_unlock_irqrestore(&ath79_reset->lock, flags); | ||
+ | ||
+ return NOTIFY_DONE; | ||
+ } |