1 /*
2 * Copyright 2020-2022 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_imu.h"
9
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.imu"
13 #endif
14
15 /*******************************************************************************
16 * Variables
17 ******************************************************************************/
18
19 /******************************************************************************
20 * Code
21 *****************************************************************************/
22
23 /*
24 * Initializes the IMU module.
25 *
26 * This function sets IMU to initialized state, including:
27 *
28 * - Flush the send FIFO.
29 * - Unlock the send FIFO.
30 * - Set the water mark to (IMU_MAX_MSG_FIFO_WATER_MARK)
31 *
32 */
IMU_Init(imu_link_t link)33 status_t IMU_Init(imu_link_t link)
34 {
35 status_t status;
36
37 if (link >= kIMU_LinkMax)
38 {
39 status = kStatus_InvalidArgument;
40 }
41 else
42 {
43 IMU_FlushSendFifo(link);
44 IMU_LockSendFifo(link, false);
45 IMU_SetSendFifoWaterMark(link, IMU_MAX_MSG_FIFO_WATER_MARK);
46
47 /* Flush RX FIFO. */
48 while (!IMU_RX_FIFO_EMPTY(link))
49 {
50 (void)IMU_RD_MSG(link);
51 }
52
53 status = kStatus_Success;
54 }
55
56 return status;
57 }
58
59 /*
60 * De-initializes the IMU module.
61 *
62 */
IMU_Deinit(imu_link_t link)63 void IMU_Deinit(imu_link_t link)
64 {
65 }
66
67 /*
68 * Blocking to send messages.
69 *
70 * This function blocks until all messages have been filled to TX FIFO.
71 *
72 * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED.
73 * - If TX FIFO not locked, this function waits the available empty slot in TX FIFO,
74 * and fills the message to TX FIFO.
75 * - To lock TX FIFO after filling all messages, set lockSendFifo to true.
76 *
77 * param link IMU link.
78 * param msgs The messages to send.
79 * param msgCount Message count, one message is a 32-bit word.
80 * param lockSendFifo If set to true, the TX FIFO is locked after all messages filled to TX FIFO.
81 * return If TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED,
82 * otherwise, this function returns the actual message count sent out, it equals msgCount
83 * because this function is blocking function, it returns until all messages have been
84 * filled into TX FIFO.
85 */
IMU_SendMsgsBlocking(imu_link_t link,const uint32_t * msgs,int32_t msgCount,bool lockSendFifo)86 int32_t IMU_SendMsgsBlocking(imu_link_t link, const uint32_t *msgs, int32_t msgCount, bool lockSendFifo)
87 {
88 int32_t ret;
89 int32_t curSent;
90 int32_t fifoEmptySpace;
91
92 if (msgCount <= 0)
93 {
94 ret = 0;
95 }
96 else if (IMU_TX_FIFO_LOCKED(link))
97 {
98 ret = IMU_ERR_TX_FIFO_LOCKED;
99 }
100 else
101 {
102 ret = msgCount;
103
104 /* Send the first (msgCount - 1), the last message should
105 * be sent with the lock configuration.
106 */
107 msgCount--;
108
109 while (msgCount > 0)
110 {
111 fifoEmptySpace = (int32_t)IMU_GetSendFifoEmptySpace(link);
112 curSent = MIN(msgCount, fifoEmptySpace);
113
114 msgCount -= curSent;
115
116 while (0 != (curSent--))
117 {
118 IMU_WR_MSG(link, *msgs);
119 msgs++;
120 }
121 }
122
123 /* To lock TX FIFO, set the lock bit before last message write. */
124 if (lockSendFifo)
125 {
126 IMU_LOCK_TX_FIFO(link);
127 }
128
129 /* Send the last. */
130 while (0UL == IMU_GetSendFifoEmptySpace(link))
131 {
132 }
133 IMU_WR_MSG(link, *msgs);
134 }
135
136 return ret;
137 }
138
139 /*
140 * Try to send messages.
141 *
142 * This function is similar with @ref IMU_SendMsgsBlocking, the difference is,
143 * this function tries to send as many as possible, if there is not enough
144 * empty slot in TX FIFO, this function fills messages to available empty slots
145 * and returns how many messages have been filled.
146 *
147 * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED.
148 * - If TX FIFO not locked, this function fills messages to TX FIFO empty slot,
149 * and returns how many messages have been filled.
150 * - If lockSendFifo is set to true, TX FIFO is locked after all messages have
151 * been filled to TX FIFO. In other word, TX FIFO is locked if the function
152 * return value equals msgCount, when lockSendFifo set to true.
153 *
154 * param link IMU link.
155 * param msgs The messages to send.
156 * param msgCount Message count, one message is a 32-bit word.
157 * param lockSendFifo If set to true, the TX FIFO is locked after all messages filled to TX FIFO.
158 * return If TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED,
159 * otherwise, this function returns the actual message count sent out.
160 */
IMU_TrySendMsgs(imu_link_t link,const uint32_t * msgs,int32_t msgCount,bool lockSendFifo)161 int32_t IMU_TrySendMsgs(imu_link_t link, const uint32_t *msgs, int32_t msgCount, bool lockSendFifo)
162 {
163 int32_t ret;
164 int32_t curSent;
165 int32_t fifoEmptySpace;
166
167 if (msgCount <= 0)
168 {
169 ret = 0;
170 }
171 else if (IMU_TX_FIFO_LOCKED(link))
172 {
173 ret = IMU_ERR_TX_FIFO_LOCKED;
174 }
175 else
176 {
177 ret = 0;
178
179 /* Send the first (msgCount - 1), the last message should
180 * be sent with the lock configuration.
181 */
182 msgCount--;
183
184 while (true)
185 {
186 fifoEmptySpace = (int32_t)IMU_GetSendFifoEmptySpace(link);
187
188 if (fifoEmptySpace == 0)
189 {
190 break;
191 }
192 /* If this is the last and have FIFO space to send. */
193 else if (0 == msgCount)
194 {
195 if (lockSendFifo)
196 {
197 IMU_LOCK_TX_FIFO(link);
198 }
199
200 /* Send the last. */
201 IMU_WR_MSG(link, *msgs);
202 ret++;
203 break;
204 }
205 else
206 {
207 curSent = MIN(msgCount, fifoEmptySpace);
208
209 /* Send the data. */
210 msgCount -= curSent;
211 ret += curSent;
212 while (0 != (curSent--))
213 {
214 IMU_WR_MSG(link, *msgs);
215 msgs++;
216 }
217 }
218 }
219 }
220
221 return ret;
222 }
223
224 /*
225 * Try to receive messages.
226 *
227 * This function tries to read messages from RX FIFO. It reads the messages already
228 * exists in RX FIFO and returns the actual read count.
229 *
230 * - If the RX FIFO has enough messages, this function reads the messages and returns.
231 * - If the RX FIFO does not have enough messages, this function the messages in RX FIFO
232 * and returns the actual read count.
233 * - During message reading, if RX FIFO is empty and locked, in this case peer CPU will not
234 * send message until current CPU send lock ack message. Then this function
235 * returns the message count actually received, and sets needAckLock to true
236 * to inform upper layer.
237 *
238 * param link IMU link.
239 * param msgs The buffer to read messages.
240 * param desiredMsgCount Desired read count, one message is a 32-bit word.
241 * param needAckLock Upper layer should always check this value. When this is
242 * set to true by this function, upper layer should send lock ack message to peer CPU.
243 * return Count of messages actually received.
244 */
IMU_TryReceiveMsgs(imu_link_t link,uint32_t * msgs,int32_t desiredMsgCount,bool * needAckLock)245 int32_t IMU_TryReceiveMsgs(imu_link_t link, uint32_t *msgs, int32_t desiredMsgCount, bool *needAckLock)
246 {
247 int32_t receivedCount = 0;
248 int32_t rxFifoMsgCount;
249 int32_t countToRead;
250 uint32_t rxFifoStatus;
251 bool localNeedAckLock = false;
252
253 while (true)
254 {
255 rxFifoStatus = IMU_RX_FIFO_STATUS(link);
256
257 rxFifoMsgCount = (int32_t)(uint32_t)IMU_RX_FIFO_MSG_COUNT_FROM_STATUS(rxFifoStatus);
258
259 if (0 == rxFifoMsgCount)
260 {
261 if (IMU_RX_FIFO_LOCKED_FROM_STATUS(rxFifoStatus))
262 {
263 localNeedAckLock = true;
264 }
265 break;
266 }
267
268 /*
269 * Dont need to check RX FIFO lock status, only notify upper layer
270 * when last message read out.
271 */
272 if (0 == desiredMsgCount)
273 {
274 break;
275 }
276
277 countToRead = MIN(desiredMsgCount, rxFifoMsgCount);
278 receivedCount += countToRead;
279 desiredMsgCount -= countToRead;
280
281 while (0 != (countToRead--))
282 {
283 *msgs++ = IMU_RD_MSG(link);
284 }
285 }
286
287 if (needAckLock != NULL)
288 {
289 *needAckLock = localNeedAckLock;
290 }
291
292 return receivedCount;
293 }
294
295 /*
296 * Blocking to receive messages.
297 *
298 * This function blocks until all desired messages have been received or the RX FIFO
299 * is locked.
300 *
301 * - If the RX FIFO has enough messages, this function reads the messages and returns.
302 * - If the RX FIFO does not have enough messages, this function waits for the new
303 * messages.
304 * - During message reading, if RX FIFO is empty and locked, in this case peer CPU will not
305 * send message until current CPU send lock ack message. Then this function
306 * returns the message count actually received, and sets needAckLock to true
307 * to inform upper layer.
308 *
309 * param link IMU link.
310 * param msgs The buffer to read messages.
311 * param desiredMsgCount Desired read count, one message is a 32-bit word.
312 * param needAckLock Upper layer should always check this value. When this is
313 * set to true by this function, upper layer should send lock ack message to peer CPU.
314 * return Count of messages actually received.
315 */
IMU_ReceiveMsgsBlocking(imu_link_t link,uint32_t * msgs,int32_t desiredMsgCount,bool * needAckLock)316 int32_t IMU_ReceiveMsgsBlocking(imu_link_t link, uint32_t *msgs, int32_t desiredMsgCount, bool *needAckLock)
317 {
318 int32_t receivedCount = 0;
319 int32_t rxFifoMsgCount;
320 int32_t countToRead;
321 uint32_t rxFifoStatus;
322 bool localNeedAckLock;
323
324 while (true)
325 {
326 rxFifoStatus = IMU_RX_FIFO_STATUS(link);
327
328 rxFifoMsgCount = (int32_t)(uint32_t)IMU_RX_FIFO_MSG_COUNT_FROM_STATUS(rxFifoStatus);
329
330 if ((0 == rxFifoMsgCount) && (IMU_RX_FIFO_LOCKED_FROM_STATUS(rxFifoStatus)))
331 {
332 localNeedAckLock = true;
333 break;
334 }
335
336 if (0 == desiredMsgCount)
337 {
338 localNeedAckLock = false;
339 break;
340 }
341
342 countToRead = MIN(desiredMsgCount, rxFifoMsgCount);
343 receivedCount += countToRead;
344 desiredMsgCount -= countToRead;
345
346 while (0 != (countToRead--))
347 {
348 *msgs++ = IMU_RD_MSG(link);
349 }
350 }
351
352 if (NULL != needAckLock)
353 {
354 *needAckLock = localNeedAckLock;
355 }
356
357 return receivedCount;
358 }
359
360 /*
361 * brief Blocking to send messages pointer.
362 *
363 * Compared with @ref IMU_SendMsgsBlocking, this function fills message pointer
364 * to TX FIFO, but not the message content.
365 *
366 * This function blocks until the message pointer is filled to TX FIFO.
367 *
368 * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED.
369 * - If TX FIFO not locked, this function waits the available empty slot in TX FIFO,
370 * and fills the message pointer to TX FIFO.
371 * - To lock TX FIFO after filling the message pointer, set lockSendFifo to true.
372 *
373 * param link IMU link.
374 * param msgPtr The buffer pointer to message to send.
375 * param needAckLock Upper layer should always check this value. When this is
376 * set to true by this function, upper layer should send lock ack message to peer CPU.
377 * retval 0 The message pointer set successfully.
378 * retval IMU_ERR_TX_FIFO_LOCKED The TX FIFO is locked, send failed.
379 */
IMU_SendMsgPtrBlocking(imu_link_t link,uint32_t msgPtr,bool lockSendFifo)380 int32_t IMU_SendMsgPtrBlocking(imu_link_t link, uint32_t msgPtr, bool lockSendFifo)
381 {
382 int32_t ret = 0;
383
384 if (IMU_TX_FIFO_LOCKED(link))
385 {
386 ret = IMU_ERR_TX_FIFO_LOCKED;
387 }
388 else
389 {
390 while (IMU_TX_FIFO_ALMOST_FULL(link))
391 {
392 }
393
394 if (lockSendFifo)
395 {
396 IMU_LOCK_TX_FIFO(link);
397 }
398
399 IMU_WR_MSG(link, msgPtr);
400 }
401
402 return ret;
403 }
404
405 /*
406 * brief Flush the send FIFO.
407 *
408 * Flush all messages in send FIFO.
409 *
410 * param link IMU link.
411 */
IMU_FlushSendFifo(imu_link_t link)412 void IMU_FlushSendFifo(imu_link_t link)
413 {
414 IMU_TX_FIFO_CNTL(link) |= IMU_MSG_FIFO_CNTL_FIFO_FLUSH_MASK;
415 IMU_TX_FIFO_CNTL(link) &= ~IMU_MSG_FIFO_CNTL_FIFO_FLUSH_MASK;
416 }
417
418 /*
419 * Gets the IMU status flags.
420 *
421 * param link IMU link.
422 * return Bit mask of the IMU status flags, see _imu_status_flags.
423 */
IMU_GetStatusFlags(imu_link_t link)424 uint32_t IMU_GetStatusFlags(imu_link_t link)
425 {
426 uint32_t txFifoStatus = IMU_TX_FIFO_STATUS(link);
427 uint32_t rxFifoStatus = IMU_RX_FIFO_STATUS(link);
428
429 return txFifoStatus | (rxFifoStatus << 8U);
430 }
431