mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-10 15:03:07 +00:00
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 <mail@david-bauer.net>
(cherry picked from commit 916af73fc3
)
This commit is contained in:
parent
50dcebeb8a
commit
0c52c9d6fc
@ -0,0 +1,104 @@
|
|||||||
|
From: David Bauer <mail@david-bauer.net>
|
||||||
|
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 <mail@david-bauer.net>
|
||||||
|
|
||||||
|
--- 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);
|
Loading…
Reference in New Issue
Block a user