aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.9/950-0023-watchdog-bcm2835-Support-setting-reboot-partition.patch
blob: 392ce70232d1c336fee2b1fcd4919047c4e0e5b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
From 0e690096e05c3b4e806381ff38124dbdae3ba877 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 7 Oct 2016 16:50:59 +0200
Subject: [PATCH] watchdog: bcm2835: Support setting reboot partition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The Raspberry Pi firmware looks at the RSTS register to know which
partition to boot from. The reboot syscall command
LINUX_REBOOT_CMD_RESTART2 supports passing in a string argument.

Add support for passing in a partition number 0..63 to boot from.
Partition 63 is a special partiton indicating halt.
If the partition doesn't exist, the firmware falls back to partition 0.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/watchdog/bcm2835_wdt.c | 61 +++++++++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 25 deletions(-)

--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -35,13 +35,7 @@
 #define PM_RSTC_WRCFG_SET		0x00000030
 #define PM_RSTC_WRCFG_FULL_RESET	0x00000020
 #define PM_RSTC_RESET			0x00000102
-
-/*
- * The Raspberry Pi firmware uses the RSTS register to know which partiton
- * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10.
- * Partiton 63 is a special partition used by the firmware to indicate halt.
- */
-#define PM_RSTS_RASPBERRYPI_HALT	0x555
+#define PM_RSTS_PARTITION_CLR		0xfffffaaa
 
 #define SECS_TO_WDOG_TICKS(x) ((x) << 16)
 #define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
@@ -111,15 +105,28 @@ static struct watchdog_device bcm2835_wd
 	.timeout =	WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
 };
 
-static int
-bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd)
+/*
+ * The Raspberry Pi firmware uses the RSTS register to know which partiton
+ * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10.
+ * Partiton 63 is a special partition used by the firmware to indicate halt.
+ */
+
+static void bcm2835_restart(struct bcm2835_wdt *wdt, u8 partition)
 {
-	struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
-					       restart_handler);
-	u32 val;
+	u32 val, rsts;
+
+	rsts = (partition & BIT(0)) | ((partition & BIT(1)) << 1) |
+	       ((partition & BIT(2)) << 2) | ((partition & BIT(3)) << 3) |
+	       ((partition & BIT(4)) << 4) | ((partition & BIT(5)) << 5);
+
+	val = readl_relaxed(wdt->base + PM_RSTS);
+	val &= PM_RSTS_PARTITION_CLR;
+	val |= PM_PASSWORD | rsts;
+	writel_relaxed(val, wdt->base + PM_RSTS);
 
 	/* use a timeout of 10 ticks (~150us) */
 	writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
+
 	val = readl_relaxed(wdt->base + PM_RSTC);
 	val &= PM_RSTC_WRCFG_CLR;
 	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
@@ -127,6 +134,20 @@ bcm2835_restart(struct notifier_block *t
 
 	/* No sleeping, possibly atomic. */
 	mdelay(1);
+}
+
+static int bcm2835_restart_notifier_call(struct notifier_block *this,
+					 unsigned long mode, void *cmd)
+{
+	struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
+					       restart_handler);
+	unsigned long long val;
+	u8 partition = 0;
+
+	if (cmd && !kstrtoull(cmd, 0, &val) && val <= 63)
+		partition = val;
+
+	bcm2835_restart(wdt, partition);
 
 	return 0;
 }
@@ -142,19 +163,9 @@ static void bcm2835_power_off(void)
 		of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
 	struct platform_device *pdev = of_find_device_by_node(np);
 	struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
-	u32 val;
-
-	/*
-	 * We set the watchdog hard reset bit here to distinguish this reset
-	 * from the normal (full) reset. bootcode.bin will not reboot after a
-	 * hard reset.
-	 */
-	val = readl_relaxed(wdt->base + PM_RSTS);
-	val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT;
-	writel_relaxed(val, wdt->base + PM_RSTS);
 
-	/* Continue with normal reset mechanism */
-	bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL);
+	/* Partition 63 tells the firmware that this is a halt */
+	bcm2835_restart(wdt, 63);
 }
 
 static int bcm2835_wdt_probe(struct platform_device *pdev)
@@ -188,7 +199,7 @@ static int bcm2835_wdt_probe(struct plat
 		return err;
 	}
 
-	wdt->restart_handler.notifier_call = bcm2835_restart;
+	wdt->restart_handler.notifier_call = bcm2835_restart_notifier_call;
 	wdt->restart_handler.priority = 128;
 	register_restart_handler(&wdt->restart_handler);
 	if (pm_power_off == NULL)