Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

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. */
110 qm_mbox_destination_t dest;
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
185 int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch,
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
350 int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
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 }
qm_mbox_callback_t
void(* qm_mbox_callback_t)(void *data)
Definition of the mailbox callback function prototype.
Definition: qm_mailbox.h:78
QM_MBOX_PAYLOAD_1
Payload index value 1.
Definition: qm_mailbox.h:45
qm_mbox_ch_read
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg)
Read specified mailbox channel.
Definition: qm_mailbox_se_2.c:300
qm_mbox_ch_t
qm_mbox_ch_t
Mailbox channel identifiers.
Definition: qm_mailbox_defs.h:18
qm_mailbox_t::ch_data
QM_RW uint32_t ch_data[4]
Channel Payload Data Word 0.
Definition: qm_soc_regs.h:636
qm_mbox_config_t::dest
qm_mbox_destination_t dest
< Mailbox Destination
Definition: qm_mailbox.h:85
qm_mailbox_t::ch_ctrl
QM_RW uint32_t ch_ctrl
Channel Control Word.
Definition: qm_soc_regs.h:635
QM_MBOX_POLLING_MODE
Mailbox channel operates in polling mode.
Definition: qm_mailbox.h:58
qm_mbox_msg_t::data
uint32_t data[QM_MBOX_PAYLOAD_NUM]
Mailbox data buffer.
Definition: qm_mailbox.h:70
QM_MBOX_PAYLOAD_2
Payload index value 2.
Definition: qm_mailbox.h:46
qm_mbox_ch_write
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.
Definition: qm_mailbox_se_2.c:273
qm_mbox_ch_get_status
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.
Definition: qm_mailbox_se_2.c:350
qm_mbox_msg_t::ctrl
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
qm_mbox_msg_t
Definition of the mailbox message.
Definition: qm_mailbox.h:64
QM_ISR_DECLARE
QM_ISR_DECLARE(qm_mailbox_0_isr)
ISR for Mailbox interrupt.
Definition: qm_mailbox_se_2.c:132
qm_mailbox_t::ch_sts
QM_RW uint32_t ch_sts
Channel status.
Definition: qm_soc_regs.h:637
qm_mbox_ch_set_config
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.
Definition: qm_mailbox_se_2.c:185
qm_mailbox_t
Mailbox register structure.
Definition: qm_soc_regs.h:634
qm_mbox_destination_t
qm_mbox_destination_t
Definition of the mailbox direction of operation The direction of communication for each channel is c...
Definition: qm_mailbox_defs.h:35
QM_MBOX_INTERRUPT_MODE
Mailbox channel operates in interrupt mode.
Definition: qm_mailbox.h:56
qm_mbox_config_t::mode
qm_mbox_mode_t mode
Message callback.
Definition: qm_mailbox.h:87
qm_mbox_mode_t
qm_mbox_mode_t
Definition of the mailbox mode of operation, interrupt mode or polling mode.
Definition: qm_mailbox.h:54
QM_MBOX_PAYLOAD_3
Payload index value 3.
Definition: qm_mailbox.h:47
QM_MBOX_PAYLOAD_0
Payload index value 0.
Definition: qm_mailbox.h:44
qm_mbox_config_t
Mailbox Configuration Structure.
Definition: qm_mailbox.h:83
qm_mbox_config_t::callback
qm_mbox_callback_t callback
Callback function data to return via the callback function.
Definition: qm_mailbox.h:99
QM_MBOX_CH_0
Channel 0.
Definition: qm_mailbox_defs.h:19
qm_mbox_ch_status_t
qm_mbox_ch_status_t
Mailbox channel status return codes.
Definition: qm_mailbox.h:23