Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
qm_aon_counters.c
1 /*
2  * {% copyright %}
3  */
4 
5 #include "qm_aon_counters.h"
6 
7 #if (HAS_SOC_CONTEXT_RETENTION)
8 #include "power_states.h"
9 #endif /* HAS_SOC_CONTEXT_RETENTION */
10 
11 static void (*callback[QM_AONC_NUM])(void *) = {NULL};
12 static void *callback_data[QM_AONC_NUM];
13 
14 #ifndef UNIT_TEST
15 qm_aonc_reg_t *qm_aonc[QM_AONC_NUM] = {((qm_aonc_reg_t *)QM_AONC_0_BASE),
16 #if (NUM_AONC_CONTROLLERS > 1)
17  ((qm_aonc_reg_t *)QM_AONC_1_BASE)
18 #endif /* NUM_AONC_CONTROLLERS >1 */
19 };
20 #endif /* UNIT_TEST */
21 
22 #define BUSY_CHECK(_aonc)
23 
24 #if (FIX_2 || FIX_3)
25 /* Cannot write to clear bit twice in one RTC clock cycle. */
26 
27 static void wait_single_cycle(const qm_aonc_t aonc)
28 {
29  uint32_t aonc_cfg, initial_cnt;
30 
31  /* Ensure the AON counter is enabled */
32  aonc_cfg = QM_AONC[aonc]->aonc_cfg;
33  QM_AONC[aonc]->aonc_cfg |= QM_AONC_ENABLE;
34  initial_cnt = QM_AONC[aonc]->aonc_cnt;
35 
36  while (initial_cnt == QM_AONC[aonc]->aonc_cnt) {
37  }
38 
39  QM_AONC[aonc]->aonc_cfg = aonc_cfg;
40 }
41 #endif /* (FIX_2 || FIX_3) */
42 
43 #if (FIX_3)
44 #define CLEAR_CHECK(_aonc) \
45  while (QM_AONC[(_aonc)]->aonpt_ctrl & QM_AONPT_CLR) { \
46  } \
47  wait_single_cycle(_aonc);
48 
49 #define RESET_CHECK(_aonc) \
50  while (QM_AONC[(_aonc)]->aonpt_ctrl & QM_AONPT_RST) { \
51  } \
52  wait_single_cycle(_aonc);
53 #else /* FIX_3 */
54 #define CLEAR_CHECK(_aonc) \
55  while (QM_AONC[(_aonc)]->aonpt_ctrl & QM_AONPT_CLR) { \
56  }
57 
58 #define RESET_CHECK(_aonc) \
59  while (QM_AONC[(_aonc)]->aonpt_ctrl & QM_AONPT_RST) { \
60  }
61 #endif /* FIX_3 */
62 
63 #define AONPT_CLEAR(_aonc) \
64  /* Clear the alarm and wait for it to complete. */ \
65  QM_AONC[(_aonc)]->aonpt_ctrl |= QM_AONPT_CLR; \
66  CLEAR_CHECK(_aonc) \
67  BUSY_CHECK(_aonc)
68 
69 /* AONPT requires one RTC clock edge before first timer reset. */
70 static __inline__ void pt_reset(const qm_aonc_t aonc)
71 {
72 #if (FIX_2)
73  uint32_t aonc_cfg;
74  static bool first_run = true;
75 
76  /*
77  * After Power on Reset, it is required to wait for one RTC clock cycle
78  * before asserting QM_AONPT_CTRL_RST. Note the AON counter is enabled
79  * with an initial value of 0 at Power on Reset.
80  */
81  if (first_run) {
82  first_run = false;
83  /* Ensure the AON counter is enabled */
84  aonc_cfg = QM_AONC[aonc]->aonc_cfg;
85  QM_AONC[aonc]->aonc_cfg |= QM_AONC_ENABLE;
86 
87  while (0 == QM_AONC[aonc]->aonc_cnt) {
88  }
89 
90  QM_AONC[aonc]->aonc_cfg = aonc_cfg;
91  }
92 #endif /* FIX_2 */
93 
94  /* Reset the counter. */
95  QM_AONC[aonc]->aonpt_ctrl |= QM_AONPT_RST;
96  RESET_CHECK(aonc);
97  BUSY_CHECK(aonc);
98 }
99 
100 /* AONPT requires one RTC clock edge before first timer reset. */
101 #define AONPT_RESET(_aonc) pt_reset((_aonc))
102 
103 QM_ISR_DECLARE(qm_aonpt_0_isr)
104 {
105  qm_aonc_t aonc;
106 
107 #if (HAS_SOC_CONTEXT_RETENTION)
108  if (QM_SCSS_GP->gps0 & QM_GPS0_POWER_STATES_MASK) {
110  }
111 #endif
112 
113  /*
114  * Check each always on counter for the interrupt status and calls
115  * the callback if it has been set.
116  */
117  for (aonc = QM_AONC_0; aonc < QM_AONC_NUM; aonc++) {
118  if ((QM_AONC[aonc]->aonpt_stat & QM_AONPT_INTERRUPT)) {
119  if (callback[aonc]) {
120  (*callback[aonc])(callback_data[aonc]);
121  }
122  /* Clear pending interrupt. */
123  AONPT_CLEAR(aonc);
124  }
125  }
126 
127  QM_ISR_EOI(QM_IRQ_AONPT_0_INT_VECTOR);
128 }
129 
130 int qm_aonc_enable(const qm_aonc_t aonc)
131 {
132  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
133  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
134 
135  QM_AONC[aonc]->aonc_cfg = QM_AONC_ENABLE;
136 
137  return 0;
138 }
139 
140 int qm_aonc_disable(const qm_aonc_t aonc)
141 {
142  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
143  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
144 
145  QM_AONC[aonc]->aonc_cfg = QM_AONC_DISABLE;
146 
147  return 0;
148 }
149 
150 int qm_aonc_get_value(const qm_aonc_t aonc, uint32_t *const val)
151 {
152  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
153  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
154  QM_CHECK(val != NULL, -EINVAL);
155 
156  *val = QM_AONC[aonc]->aonc_cnt;
157  return 0;
158 }
159 
161  const qm_aonpt_config_t *const cfg)
162 {
163  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
164  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
165  QM_CHECK(cfg != NULL, -EINVAL);
166 
167  QM_AONC[aonc]->aonpt_cfg = cfg->count;
168 
169  /* Clear pending interrupts. */
170  AONPT_CLEAR(aonc);
171 
172  if (cfg->int_en) {
173  callback[aonc] = cfg->callback;
174  callback_data[aonc] = cfg->callback_data;
175  } else {
176  callback[aonc] = NULL;
177  }
178 
179  AONPT_RESET(aonc);
180 
181  return 0;
182 }
183 
184 int qm_aonpt_get_value(const qm_aonc_t aonc, uint32_t *const val)
185 {
186  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
187  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
188  QM_CHECK(val != NULL, -EINVAL);
189 
190  *val = QM_AONC[aonc]->aonpt_cnt;
191 
192  return 0;
193 }
194 
195 int qm_aonpt_get_status(const qm_aonc_t aonc, qm_aonpt_status_t *const status)
196 {
197  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
198  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
199  QM_CHECK(status != NULL, -EINVAL);
200 
201  if (QM_AONC[aonc]->aonpt_stat & QM_AONPT_INTERRUPT) {
202  *status = QM_AONPT_EXPIRED;
203  } else {
204  *status = QM_AONPT_READY;
205  }
206 
207  return 0;
208 }
209 
210 int qm_aonpt_clear(const qm_aonc_t aonc)
211 {
212  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
213  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
214 
215  /*
216  * Clear pending interrupt and poll until the command has been
217  * completed.
218  */
219  AONPT_CLEAR(aonc);
220 
221  return 0;
222 }
223 
224 int qm_aonpt_reset(const qm_aonc_t aonc)
225 {
226  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
227  QM_CHECK(aonc >= QM_AONC_0, -EINVAL);
228 
229  AONPT_RESET(aonc);
230 
231  return 0;
232 }
233 
234 #if (ENABLE_RESTORE_CONTEXT)
235 int qm_aonpt_save_context(const qm_aonc_t aonc, qm_aonc_context_t *const ctx)
236 {
237  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
238  QM_CHECK(ctx != NULL, -EINVAL);
239 
240  (void)aonc;
241  (void)ctx;
242 
243  return 0;
244 }
245 
247  const qm_aonc_context_t *const ctx)
248 {
249  uint32_t int_aonpt_mask;
250  QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
251  QM_CHECK(ctx != NULL, -EINVAL);
252 
253  (void)aonc;
254  (void)ctx;
255 
256  /* The interrupt router registers are sticky and retain their
257  * values across warm resets, so we don't need to save them.
258  * But for wake capable peripherals, if their interrupts are
259  * configured to be edge sensitive, the wake event will be lost
260  * by the time the interrupt controller is reconfigured, while
261  * the interrupt is still pending. By masking and unmasking again
262  * the corresponding routing register, the interrupt is forwarded
263  * to the core and the ISR will be serviced as expected.
264  */
265  int_aonpt_mask = QM_INTERRUPT_ROUTER->aonpt_0_int_mask;
266  QM_INTERRUPT_ROUTER->aonpt_0_int_mask = 0xFFFFFFFF;
267  QM_INTERRUPT_ROUTER->aonpt_0_int_mask = int_aonpt_mask;
268 
269  return 0;
270 }
271 #else
272 int qm_aonpt_save_context(const qm_aonc_t aonc, qm_aonc_context_t *const ctx)
273 {
274  (void)aonc;
275  (void)ctx;
276 
277  return 0;
278 }
279 
280 int qm_aonpt_restore_context(const qm_aonc_t aonc,
281  const qm_aonc_context_t *const ctx)
282 {
283  (void)aonc;
284  (void)ctx;
285 
286  return 0;
287 }
288 #endif /* ENABLE_RESTORE_CONTEXT */
int qm_aonc_disable(const qm_aonc_t aonc)
Disable the Always-on Counter.
void qm_power_soc_restore(void)
Restore system state after sleep or deep sleep.
Definition: power_states.c:402
int qm_aonpt_clear(const qm_aonc_t aonc)
Clear the status of the Always-on Periodic Timer.
uint32_t count
Time to count down from in clock cycles.
void(* callback)(void *data)
User callback.
QM_ISR_DECLARE(qm_aonpt_0_isr)
ISR for Always-on Periodic Timer 0 interrupt.
void * callback_data
Callback data.
qm_aonpt_status_t
Always on counter status.
int qm_aonc_enable(const qm_aonc_t aonc)
Enable the Always-on Counter.
int qm_aonpt_get_status(const qm_aonc_t aonc, qm_aonpt_status_t *const status)
Get the current status of an Always-on Periodic Timer.
int qm_aonc_get_value(const qm_aonc_t aonc, uint32_t *const val)
Get the current value of the Always-on Counter.
Always-on Counter Controller register map.
Definition: qm_soc_regs.h:258
int qm_aonpt_save_context(const qm_aonc_t aonc, qm_aonc_context_t *const ctx)
Save the Always-on Periodic Timer context.
Default Timer Status.
int qm_aonpt_get_value(const qm_aonc_t aonc, uint32_t *const val)
Get the current value of the Always-on Periodic Timer.
Timer expired.
bool int_en
Enable/disable the interrupts.
QM Always-on Periodic Timer configuration type.
int qm_aonpt_reset(const qm_aonc_t aonc)
Reset the Always-on Periodic Timer back to the configured value.
int qm_aonpt_set_config(const qm_aonc_t aonc, const qm_aonpt_config_t *const cfg)
Set the Always-on Periodic Timer configuration.
int qm_aonpt_restore_context(const qm_aonc_t aonc, const qm_aonc_context_t *const ctx)
Restore the Always-on Periodic Timer context.
qm_aonc_t
Number of Always-on counter controllers.
Definition: qm_soc_regs.h:255