Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
qm_mailbox_se_2.c
1 /*
2  * {% copyright %}
3  */
4 
5 #include "qm_common.h"
6 #include "qm_mailbox.h"
7 #include "qm_interrupt.h"
8 #include "qm_interrupt_router.h"
9 
10 /**
11  * The Active core/agent can be either Lakemont, the Sensor Sub-System,
12  * the Bluetooth Sub-System or System Management Mode.
13  * The active core is determined using CFLAGS passed by the build.
14  *
15  * Core specific mailbox #defines are grouped here to prevent duplication below.
16  */
17 
18 #if HAS_MAILBOX_SMM_DEST
19 #define MBOX_CHECK_IF_ACTIVE_AGENT_MBOX_ACTIVE_AGENT_IS_SMM \
20  (QM_LAKEMONT && QM_SMM)
21 #else /* HAS_MAILBOX_SMM_DEST */
22 #define MBOX_CHECK_IF_ACTIVE_AGENT_MBOX_ACTIVE_AGENT_IS_SMM (0)
23 #endif /* HAS_MAILBOX_SMM_DEST */
24 
25 #if HAS_MAILBOX_LAKEMONT_DEST
26 #if MBOX_CHECK_IF_ACTIVE_AGENT_MBOX_ACTIVE_AGENT_IS_SMM
27 #define MBOX_ACTIVE_AGENT_IS_SMM (1)
28 #define ACTIVE_CORE_DEST QM_MBOX_TO_SMM
29 #define MBOX_ACTIVE_CORE_ALL_INT_MASK QM_IR_MBOX_SMI_ALL_INT_MASK
30 #define MBOX_INT_LOCK_MASK(N) QM_IR_MBOX_SMI_INT_LOCK_MASK(N)
31 /* SMM does not have Halt masks. */
32 #define MBOX_INT_LOCK_HALT_MASK(N)
33 #define MBOX_IS_INT_MASK_EN(N) QM_IR_MBOX_IS_SMI_INT_MASK_EN(N)
34 #define MBOX_ENABLE_INT_MASK(N) QM_IR_MBOX_ENABLE_SMM_INT_MASK(N)
35 #define MBOX_DISABLE_INT_MASK(N) QM_IR_MBOX_DISABLE_SMM_INT_MASK(N)
36 #elif QM_LAKEMONT
37 #define MBOX_ACTIVE_AGENT_IS_SMM (0)
38 #define ACTIVE_CORE_DEST QM_MBOX_TO_LMT
39 #define MBOX_ACTIVE_CORE_ALL_INT_MASK QM_IR_MBOX_LMT_ALL_INT_MASK
40 #define MBOX_INT_LOCK_MASK(N) QM_IR_MBOX_LMT_INT_LOCK_MASK(N)
41 #define MBOX_INT_LOCK_HALT_MASK(N) QM_IR_MBOX_LMT_INT_LOCK_HALT_MASK(N)
42 #define MBOX_IS_INT_MASK_EN(N) QM_IR_MBOX_IS_LMT_INT_MASK_EN(N)
43 #define MBOX_ENABLE_INT_MASK(N) QM_IR_MBOX_ENABLE_LMT_INT_MASK(N)
44 #define MBOX_DISABLE_INT_MASK(N) QM_IR_MBOX_DISABLE_LMT_INT_MASK(N)
45 #endif /* MBOX_CHECK_IF_ACTIVE_AGENT_MBOX_ACTIVE_AGENT_IS_SMM */
46 #endif /* HAS_MAILBOX_LAKEMONT_DEST */
47 
48 #if HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST
49 #if QM_SENSOR
50 #define MBOX_ACTIVE_AGENT_IS_SMM (0)
51 #define ACTIVE_CORE_DEST QM_MBOX_TO_SS
52 #define MBOX_ACTIVE_CORE_ALL_INT_MASK QM_IR_MBOX_SS_ALL_INT_MASK
53 #define MBOX_INT_LOCK_MASK(N) QM_IR_MBOX_SS_INT_LOCK_HALT_MASK(N)
54 #define MBOX_INT_LOCK_HALT_MASK(N) QM_IR_MBOX_SS_INT_LOCK_MASK(N)
55 #define MBOX_IS_INT_MASK_EN(N) QM_IR_MBOX_IS_SS_INT_MASK_EN(N)
56 #define MBOX_ENABLE_INT_MASK(N) QM_IR_MBOX_ENABLE_SS_INT_MASK(N)
57 #define MBOX_DISABLE_INT_MASK(N) QM_IR_MBOX_DISABLE_SS_INT_MASK(N)
58 #endif /* QM_SENSOR */
59 #endif /* HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST */
60 
61 #if HAS_MAILBOX_BLUETOOTH_SUB_SYSTEM_DEST
62 #if QM_BLE
63 #define MBOX_ACTIVE_AGENT_IS_SMM (0)
64 #define ACTIVE_CORE_DEST QM_MBOX_TO_BLE
65 #define MBOX_ALL_INT_MASK QM_MBOX_BLE_ALL_INT_MASK
66 
67 /*
68  * BLE does not have access to the event router.
69  * Since BLE cannot mask/unmask using the event router it is
70  * effectively locked from the BLE perspective.
71  */
72 #define MBOX_INT_LOCK_MASK(N) (true)
73 #define MBOX_INT_LOCK_HALT_MASK(N) (true)
74 
75 /* Since BLE cannot read the actual mask settings, it must assume
76  * that another core with access has configured the event router correctly.
77  */
78 #define MBOX_IS_INT_MASK_EN(N) (true)
79 #define MBOX_ENABLE_INT_MASK(N) QM_IR_MBOX_ENABLE_BLE_INT_MASK(N)
80 #define MBOX_DISABLE_INT_MASK(N) QM_IR_MBOX_DISABLE_BLE_INT_MASK(N)
81 #endif /* QM_BLE */
82 #endif /* HAS_MAILBOX_BLUETOOTH_SUB_SYSTEM_DEST */
83 
84 #if MBOX_ACTIVE_AGENT_IS_SMM
85 /**
86  * SMM has full priviledge in controlling mailboxes thus it is not required to
87  * check the destination before accessing the mailbox.
88  */
89 #define MBOX_CHECK_DESTINATION(_dest) (true)
90 /**
91  * When the Mailbox interrupt is routed to SMM an SMI is triggered.
92  * This does not trigger the mailbox ISR and thus all status bits must be
93  * cleared
94  * by the mailbox read function.
95  */
96 #define MBOX_CHECK_POLLING_MODE(_dest) (true)
97 #else /* MBOX_ACTIVE_AGENT_IS_SMM */
98 #define MBOX_CHECK_DESTINATION(_dest) (ACTIVE_CORE_DEST == (_dest))
99 #define MBOX_CHECK_POLLING_MODE(_mode) (QM_MBOX_POLLING_MODE == (_mode))
100 #endif /* MBOX_ACTIVE_AGENT_IS_SMM */
101 #if (!MBOX_ACTIVE_AGENT_IS_SMM)
102 
103 static void mailbox_isr_handler(void);
104 
105 /**
106  * Private data structure maintained by the driver
107  */
108 typedef struct {
109  /** Destination of the mailbox channel. */
111  /** Defines if the mailbox channel operates in interrupt
112  * mode or polling mode. */
113  qm_mbox_mode_t mode;
114  /** Callback function registered with the application. */
115  qm_mbox_callback_t callback;
116  /** Callback function data return via the callback function. */
117  void *callback_data;
118 } qm_mailbox_info_t;
119 
120 /*
121  * Need a quick way of keeping track of which mailbox channels have interrupts
122  * enabled for the active processor. Maps to QM_MAILBOX->mbox_chan_int_sts and
123  * is
124  * used by the mailbox isr to determine if there are any remaining interrupts
125  * it needs to handle.
126  */
127 static volatile uint32_t active_proc_active_ints = 0;
128 
129 /* Mailbox channels private data structures */
130 static qm_mailbox_info_t mailbox_devs[NUM_MAILBOXES];
131 
132 QM_ISR_DECLARE(qm_mailbox_0_isr)
133 {
134  mailbox_isr_handler();
135  QM_ISR_EOI(QM_IRQ_MAILBOX_0_INT_VECTOR);
136 }
137 
138 /**
139  * Mailbox interrupt handler.
140  */
141 static void mailbox_isr_handler(void)
142 {
143  qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_MAILBOX;
144  uint32_t i = 0;
145  uint32_t chall_int_sts =
146  (QM_MAILBOX->mbox_chan_int_sts & active_proc_active_ints);
147 
148 #if (ACTIVE_CORE_DEST != QM_MBOX_TO_BLE)
149  /*
150  * If the interrupt occurred, but no configured mailbox owns the
151  * interrupt
152  * read the event router to determine all potential active interrupts
153  * for the
154  * active core.
155  * Note that the BLE core cannot read the event router and must rely on
156  * calling
157  * the qm_mailbox_set_config before enabling mailbox interrupts.
158  */
159  if (0 == chall_int_sts) {
160  chall_int_sts = (~MBOX_ACTIVE_CORE_ALL_INT_MASK) &
161  (QM_MAILBOX->mbox_chan_int_sts) &
162  (BIT(NUM_MAILBOXES + 1) - 1);
163  }
164 #endif /* ACTIVE_CORE_DEST != QM_MBOX_TO_BLE */
165 
166  for (i = 0; chall_int_sts; i++, chall_int_sts >>= 1) {
167  if ((chall_int_sts & 1) == 0) {
168  continue;
169  }
170  if (mbox_reg[i].ch_sts & QM_MBOX_CH_STS_CTRL_INT) {
171  if (NULL != mailbox_devs[i].callback) {
172  /* Callback */
173  mailbox_devs[i].callback(
174  mailbox_devs[i].callback_data);
175  }
176  /* Clear the interrupt.
177  * Note write 1 to clear register, do
178  * not OR contents or you will clear
179  * other bits too! */
180  mbox_reg[i].ch_sts = QM_MBOX_CH_STS_CTRL_INT;
181  }
182  }
183 }
184 
186  const qm_mbox_config_t *const config)
187 {
188 
189  QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < NUM_MAILBOXES),
190  -EINVAL);
191  qm_mailbox_info_t *device = &mailbox_devs[mbox_ch];
192 
193  /* Block interrupts while configuring MBOX */
194  QM_IR_MASK_INT(QM_IRQ_MAILBOX_0_INT);
195 
196  /* Store the device destination */
197  device->dest = config->dest;
198 
199  /* Check if we are enabling or disabling the channel. */
200  if (QM_MBOX_UNUSED != config->dest) {
201 
202  if (QM_MBOX_INTERRUPT_MODE == config->mode) {
203  QM_CHECK(NULL != config->callback, -EINVAL);
204 
205  /* Register callback function */
206  device->callback = config->callback;
207  /* Register callback function data */
208  device->callback_data = config->callback_data;
209  /* Update the mode of operation for the mailbox channel.
210  */
211  device->mode = QM_MBOX_INTERRUPT_MODE;
212 
213  active_proc_active_ints |= BIT(mbox_ch);
214 /*
215  * Note that the BLE Sub-System does not have access to its Event router
216  * interrupt masks
217  */
218 #if (!QM_BLE)
219  /* Enable the mailbox interrupt if the lock is not set.
220  */
221  if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
222  /* Note: Routing is done now, cannot be done in
223  * irq_request! */
224  MBOX_ENABLE_INT_MASK(mbox_ch);
225  } else {
226  /* The lock is set, but we need to check if the
227  * interrupt is routed */
228  QM_CHECK(MBOX_IS_INT_MASK_EN(mbox_ch), -EIO);
229  }
230 #endif /* !QM_BLE */
231 
232  } else {
233  device->mode = QM_MBOX_POLLING_MODE;
234 #if (!QM_BLE)
235  /* Disable the mailbox interrupt if the lock is not set.
236  */
237  if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
238  /* Note: Routing is done now, cannot be done in
239  * irq_request! */
240  MBOX_DISABLE_INT_MASK(mbox_ch);
241  }
242 #endif /* !QM_BLE */
243 
244  device->callback = NULL;
245  device->callback_data = 0;
246  }
247  } else {
248 #if (!QM_BLE)
249  /* Disable the mailbox interrupt if the lock is not set. */
250  if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
251  /* Note: Routing is done now, cannot be done in
252  * irq_request! */
253  MBOX_DISABLE_INT_MASK(mbox_ch);
254  }
255 #endif /* !QM_BLE */
256 
257  /* Set the mailbox channel to its default configuration. */
258 
259  active_proc_active_ints &= ~(BIT(mbox_ch));
260 
261  device->dest = QM_MBOX_UNUSED;
262  device->mode = QM_MBOX_INTERRUPT_MODE;
263  device->callback = NULL;
264  device->callback_data = 0;
265  }
266 
267  /* UnBlock MBOX interrupts. */
268  QM_IR_UNMASK_INT(QM_IRQ_MAILBOX_0_INT);
269  return 0;
270 }
271 #endif /* !MBOX_ACTIVE_AGENT_IS_SMM */
272 
273 int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch, const qm_mbox_msg_t *const msg)
274 {
275  QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < NUM_MAILBOXES),
276  -EINVAL);
277  QM_CHECK(NULL != msg, -EINVAL);
278  qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_MAILBOX + mbox_ch;
279 
280  uint32_t status = 0;
281 
282  status = QM_MAILBOX->mbox[mbox_ch].ch_sts;
283 
284  /* Check if the previous message has been consumed. */
285  if (false == (status & (QM_MBOX_CH_STS_CTRL_INT | QM_MBOX_CH_STS))) {
286  /* Write the payload data to the mailbox channel. */
287  mbox_reg->ch_data[0] = msg->data[QM_MBOX_PAYLOAD_0];
288  mbox_reg->ch_data[1] = msg->data[QM_MBOX_PAYLOAD_1];
289  mbox_reg->ch_data[2] = msg->data[QM_MBOX_PAYLOAD_2];
290  mbox_reg->ch_data[3] = msg->data[QM_MBOX_PAYLOAD_3];
291  /* Write the control word and trigger the channel interrupt. */
292  mbox_reg->ch_ctrl = msg->ctrl | QM_MBOX_CH_CTRL_INT;
293  return 0;
294  }
295 
296  /* Previous message has not been consumed. */
297  return -EIO;
298 }
299 
300 int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg)
301 {
302  QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < NUM_MAILBOXES),
303  -EINVAL);
304  QM_CHECK(NULL != msg, -EINVAL);
305 
306  int rc = 0;
307  uint32_t status = 0;
308 
309  qm_mailbox_t *mbox_reg = &QM_MAILBOX->mbox[mbox_ch];
310 
311  if (MBOX_CHECK_DESTINATION(mailbox_devs[mbox_ch].dest)) {
312  status = mbox_reg->ch_sts;
313 
314  /* If there is data pending consume it */
315  if (status & QM_MBOX_CH_STS) {
316  /* Read data from the mailbox channel and clear bit 31
317  * of the control word. */
318  msg->ctrl = mbox_reg->ch_ctrl & (~QM_MBOX_CH_CTRL_INT);
319  msg->data[0] = mbox_reg->ch_data[0];
320  msg->data[1] = mbox_reg->ch_data[1];
321  msg->data[2] = mbox_reg->ch_data[2];
322  msg->data[3] = mbox_reg->ch_data[3];
323 
324  if (MBOX_CHECK_POLLING_MODE(
325  mailbox_devs[mbox_ch].mode)) {
326  /* In polling mode the interrupt status still
327  * needs to be cleared since we are not using
328  * the ISR. Note we write 1 to clear the bit.
329  */
330  mbox_reg->ch_sts = QM_MBOX_CH_STS_CTRL_INT;
331  }
332 
333  /* Clear data status bit. This indicates to others that
334  * the mailbox data has been consumed and a new message
335  * can be sent on the channel */
336  mbox_reg->ch_sts = QM_MBOX_CH_STS;
337  } else {
338  /* there is no pending data in the mailbox */
339  rc = -EIO;
340  }
341  } else {
342  /* Active destination has not been configured to consume data
343  * from this channel */
344  rc = -EINVAL;
345  }
346 
347  return rc;
348 }
349 
351  qm_mbox_ch_status_t *const status)
352 {
353  QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < NUM_MAILBOXES),
354  -EINVAL);
355  QM_CHECK(NULL != status, -EINVAL);
356 
357  *status = QM_MAILBOX->mbox[mbox_ch].ch_sts;
358 
359  return 0;
360 }
void(* qm_mbox_callback_t)(void *data)
Definition of the mailbox callback function prototype.
Definition: qm_mailbox.h:78
Payload index value 1.
Definition: qm_mailbox.h:45
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg)
Read specified mailbox channel.
qm_mbox_ch_t
Mailbox channel identifiers.
QM_RW uint32_t ch_data[4]
Channel Payload Data Word 0.
Definition: qm_soc_regs.h:636
qm_mbox_destination_t dest
< Mailbox Destination
Definition: qm_mailbox.h:85
QM_RW uint32_t ch_ctrl
Channel Control Word.
Definition: qm_soc_regs.h:635
Mailbox channel operates in polling mode.
Definition: qm_mailbox.h:58
uint32_t data[QM_MBOX_PAYLOAD_NUM]
Mailbox data buffer.
Definition: qm_mailbox.h:70
Payload index value 2.
Definition: qm_mailbox.h:46
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch, const qm_mbox_msg_t *const msg)
Write to a specified mailbox channel.
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch, qm_mbox_ch_status_t *const status)
Retrieve the specified mailbox channel status.
uint32_t ctrl
Control word - bits 30 to 0 used as data/message id, bit 31 triggers channel interrupt when set by th...
Definition: qm_mailbox.h:68
Definition of the mailbox message.
Definition: qm_mailbox.h:64
QM_ISR_DECLARE(qm_mailbox_0_isr)
ISR for Mailbox interrupt.
QM_RW uint32_t ch_sts
Channel status.
Definition: qm_soc_regs.h:637
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, const qm_mbox_config_t *const config)
Set the mailbox channel configuration.
Mailbox register structure.
Definition: qm_soc_regs.h:634
qm_mbox_destination_t
Definition of the mailbox direction of operation The direction of communication for each channel is c...
Mailbox channel operates in interrupt mode.
Definition: qm_mailbox.h:56
qm_mbox_mode_t mode
Message callback.
Definition: qm_mailbox.h:87
qm_mbox_mode_t
Definition of the mailbox mode of operation, interrupt mode or polling mode.
Definition: qm_mailbox.h:54
Payload index value 3.
Definition: qm_mailbox.h:47
Payload index value 0.
Definition: qm_mailbox.h:44
Mailbox Configuration Structure.
Definition: qm_mailbox.h:83
qm_mbox_callback_t callback
Callback function data to return via the callback function.
Definition: qm_mailbox.h:99
Channel 0.
qm_mbox_ch_status_t
Mailbox channel status return codes.
Definition: qm_mailbox.h:23