Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
qm_wdt.c
1 /*
2  * {% copyright %}
3  */
4 
5 #include "qm_wdt.h"
6 #include "clk.h"
7 #include "soc_watch.h"
8 
9 static void (*callback[QM_WDT_NUM])(void *data);
10 static void *callback_data[QM_WDT_NUM];
11 
12 #ifndef UNIT_TEST
13 qm_wdt_reg_t *qm_wdt[QM_WDT_NUM] = {((qm_wdt_reg_t *)QM_WDT_0_BASE),
14 #if (NUM_WDT_CONTROLLERS > 1)
15  ((qm_wdt_reg_t *)QM_WDT_1_BASE)
16 #endif /* NUM_WDT_CONTROLLERS >1 */
17 };
18 #endif /* UNIT_TEST */
19 
20 QM_ISR_DECLARE(qm_wdt_0_isr)
21 {
22  if (callback[QM_WDT_0]) {
23  callback[QM_WDT_0](callback_data[QM_WDT_0]);
24  }
25 
26  /* Clear the interrupt by reading. */
27  QM_WDT[QM_WDT_0]->wdt_eoi;
28  QM_ISR_EOI(QM_IRQ_WDT_0_INT_VECTOR);
29 }
30 
31 #if (NUM_WDT_CONTROLLERS > 1)
32 QM_ISR_DECLARE(qm_wdt_1_isr)
33 {
34  if (NULL != callback[QM_WDT_1]) {
35  (callback[QM_WDT_1])(callback_data[QM_WDT_1]);
36  }
37 
38  /* Clear the interrupt by reading. */
39  QM_WDT[QM_WDT_1]->wdt_eoi;
40  QM_ISR_EOI(QM_IRQ_WDT_1_INT_VECTOR);
41 }
42 #endif /* (NUM_WDT_CONTROLLERS > 1) */
43 
44 int qm_wdt_start(const qm_wdt_t wdt)
45 {
46  QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
47 
48  QM_WDT[wdt]->wdt_cr |= QM_WDT_CR_WDT_ENABLE;
49 
50 #if (HAS_WDT_CLOCK_ENABLE)
52  QM_SCSS_PERIPHERAL->periph_cfg0 |= BIT(1);
53 #endif /* HAS_WDT_CLOCK_ENABLE */
54 
55  qm_wdt_reload(wdt);
56 
57  return 0;
58 }
59 
60 int qm_wdt_set_config(const qm_wdt_t wdt, const qm_wdt_config_t *const cfg)
61 {
62  QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
63  QM_CHECK(cfg != NULL, -EINVAL);
64  QM_CHECK(cfg->timeout <= QM_WDT_TORR_TOP_MASK, -EINVAL);
65 
66  qm_wdt_reload(wdt);
67 
68  if (cfg->mode == QM_WDT_MODE_INTERRUPT_RESET) {
69  callback[wdt] = cfg->callback;
70  callback_data[wdt] = cfg->callback_data;
71  }
72 
73  QM_WDT[wdt]->wdt_cr &= ~QM_WDT_CR_RMOD;
74  QM_WDT[wdt]->wdt_cr |= cfg->mode << QM_WDT_CR_RMOD_OFFSET;
75 
76 /* If the SoC has the C2 Pause enable bit for LMT WDT. */
77 #if (HAS_WDT_PAUSE)
78  /* Make sure WDT0 is the one requested to be configured. */
79  QM_CHECK(QM_WDT_0 == wdt, -EINVAL);
80  (QM_SCU_AON_CRU_BLOCK)->wdt0_tclk_en &= ~C2_WDT_PAUSE_EN_MASK;
81  (QM_SCU_AON_CRU_BLOCK)->wdt0_tclk_en |= cfg->pause_en
82  << C2_WDT_PAUSE_EN_SHIFT;
83 #endif /* HAS_WDT_PAUSE */
84 
85  /*
86  * Timeout range register. Select the timeout from the pre-defined
87  * tables. These tables can be found in the SoC databook or register
88  * file.
89  */
90  QM_WDT[wdt]->wdt_torr = cfg->timeout;
91 
92  /* kick the WDT to load the Timeout Period(TOP) value */
93  qm_wdt_reload(wdt);
94 
95  return 0;
96 }
97 
98 int qm_wdt_reload(const qm_wdt_t wdt)
99 {
100  QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
101 
102  /*
103  * This register is used to restart the WDT counter. As a safety feature
104  * to prevent accidental restarts the value 0x76 must be written.
105  * A restart also clears the WDT interrupt.
106  */
107  QM_WDT[wdt]->wdt_crr = QM_WDT_RELOAD_VALUE;
108 
109  return 0;
110 }
111 
112 #if (ENABLE_RESTORE_CONTEXT)
113 int qm_wdt_save_context(const qm_wdt_t wdt, qm_wdt_context_t *const ctx)
114 {
115  QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
116  QM_CHECK(ctx != NULL, -EINVAL);
117 
118  ctx->wdt_torr = QM_WDT[wdt]->wdt_torr;
119  ctx->wdt_cr = QM_WDT[wdt]->wdt_cr;
120 
121  return 0;
122 }
123 
125  const qm_wdt_context_t *const ctx)
126 {
127  QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
128  QM_CHECK(ctx != NULL, -EINVAL);
129 
130  /*
131  * TOP_INIT field has to be written before Watchdog Timer is enabled.
132  */
133  QM_WDT[wdt]->wdt_torr = ctx->wdt_torr;
134  QM_WDT[wdt]->wdt_cr = ctx->wdt_cr;
135 
136  /*
137  * Reload the wdt value to avoid interrupts to fire on wake up.
138  */
139  QM_WDT[wdt]->wdt_crr = QM_WDT_RELOAD_VALUE;
140 
141  return 0;
142 }
143 #else
144 int qm_wdt_save_context(const qm_wdt_t wdt, qm_wdt_context_t *const ctx)
145 {
146  (void)wdt;
147  (void)ctx;
148 
149  return 0;
150 }
151 
153  const qm_wdt_context_t *const ctx)
154 {
155  (void)wdt;
156  (void)ctx;
157 
158  return 0;
159 }
160 #endif /* ENABLE_RESTORE_CONTEXT */
Watchdog Interrupt Reset Response Mode.
Definition: qm_wdt.h:33
qm_wdt_mode_t mode
Watchdog response mode.
Definition: qm_wdt.h:48
bool pause_en
Pause enable in LMT power state C2 and C2 Plus.
Definition: qm_wdt.h:60
QM WDT configuration type.
Definition: qm_wdt.h:39
int clk_periph_enable(const clk_periph_t clocks)
Enable clocks for peripherals / registers.
Definition: clk.c:319
uint32_t timeout
Index for the WDT timeout table.
Definition: qm_wdt.h:47
void(* callback)(void *data)
User callback.
Definition: qm_wdt.h:68
Peripheral Clock Enable.
Definition: qm_soc_regs.h:1370
int qm_wdt_restore_context(const qm_wdt_t wdt, const qm_wdt_context_t *const ctx)
Restore watchdog context.
Definition: qm_wdt.c:124
Watchdog Clock Enable.
Definition: qm_soc_regs.h:1376
int qm_wdt_reload(const qm_wdt_t wdt)
Reload the WDT counter.
Definition: qm_wdt.c:98
int qm_wdt_save_context(const qm_wdt_t wdt, qm_wdt_context_t *const ctx)
Save watchdog context.
Definition: qm_wdt.c:113
QM_ISR_DECLARE(qm_wdt_0_isr)
ISR for WDT 0 interrupt.
Definition: qm_wdt.c:20
int qm_wdt_set_config(const qm_wdt_t wdt, const qm_wdt_config_t *const cfg)
Set configuration of WDT module.
Definition: qm_wdt.c:60
qm_wdt_t
Number of WDT controllers.
Definition: qm_soc_regs.h:467
int qm_wdt_start(const qm_wdt_t wdt)
Start WDT.
Definition: qm_wdt.c:44
Watchdog timer register map.
Definition: qm_soc_regs.h:470
void * callback_data
Callback user data.
Definition: qm_wdt.h:69