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