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
125
126
127
128
129
130
131
|
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -4,6 +4,7 @@
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+ * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
@@ -12,6 +13,7 @@
#include <linux/ssb/ssb_regs.h>
#include <linux/export.h>
#include <linux/pci.h>
+#include <linux/bcm47xx_wdt.h>
#include "ssb_private.h"
@@ -306,6 +308,43 @@ static u32 ssb_chipco_watchdog_get_max_t
return (1 << nb) - 1;
}
+u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt, u32 ticks)
+{
+ struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
+
+ if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
+ return 0;
+
+ return ssb_chipco_watchdog_timer_set(cc, ticks);
+}
+
+u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms)
+{
+ struct ssb_chipcommon *cc = bcm47xx_wdt_get_drvdata(wdt);
+ u32 ticks;
+
+ if (cc->dev->bus->bustype != SSB_BUSTYPE_SSB)
+ return 0;
+
+ ticks = ssb_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
+ return ticks / cc->ticks_per_ms;
+}
+
+static int ssb_chipco_watchdog_ticks_per_ms(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+ /* based on 32KHz ILP clock */
+ return 32;
+ } else {
+ if (cc->dev->id.revision < 18)
+ return ssb_clockspeed(bus) / 1000;
+ else
+ return ssb_chipco_alp_clock(cc) / 1000;
+ }
+}
+
void ssb_chipcommon_init(struct ssb_chipcommon *cc)
{
if (!cc->dev)
@@ -323,6 +362,11 @@ void ssb_chipcommon_init(struct ssb_chip
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
calc_fast_powerup_delay(cc);
+
+ if (cc->dev->bus->bustype == SSB_BUSTYPE_SSB) {
+ cc->ticks_per_ms = ssb_chipco_watchdog_ticks_per_ms(cc);
+ cc->max_timer_ms = ssb_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ }
}
void ssb_chipco_suspend(struct ssb_chipcommon *cc)
@@ -421,7 +465,7 @@ void ssb_chipco_timing_init(struct ssb_c
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
-void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
{
u32 maxt;
enum ssb_clkmode clkmode;
@@ -441,6 +485,7 @@ void ssb_chipco_watchdog_timer_set(struc
/* instant NMI */
chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
}
+ return ticks;
}
void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value)
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -3,6 +3,7 @@
#include <linux/ssb/ssb.h>
#include <linux/types.h>
+#include <linux/bcm47xx_wdt.h>
#define PFX "ssb: "
@@ -226,4 +227,8 @@ static inline int ssb_sflash_init(struct
extern struct platform_device ssb_pflash_dev;
+extern u32 ssb_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
+ u32 ticks);
+extern u32 ssb_chipco_watchdog_timer_set_ms(struct bcm47xx_wdt *wdt, u32 ms);
+
#endif /* LINUX_SSB_PRIVATE_H_ */
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -607,6 +607,8 @@ struct ssb_chipcommon {
#ifdef CONFIG_SSB_SFLASH
struct bcm47xx_sflash sflash;
#endif
+ u32 ticks_per_ms;
+ u32 max_timer_ms;
};
static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
@@ -646,8 +648,7 @@ enum ssb_clkmode {
extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
enum ssb_clkmode mode);
-extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
- u32 ticks);
+extern u32 ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks);
void ssb_chipco_irq_mask(struct ssb_chipcommon *cc, u32 mask, u32 value);
|