1 /*******************************************************************************
2  * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PolarFire SoC (MPFS) microprocessor subsystem CAN bare metal software driver
7  * implementation.
8  */
9 
10 
11 /*******************************************************************************
12  * Include files
13  */
14 #include "mpfs_hal/mss_hal.h"
15 #include "mss_can.h"
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 /*******************************************************************************
22  * Macros
23  */
24 #define    CAN_ID_SHIFT                  18u
25 #define    CAN_ERROR_STATUS_SHIFT        16u
26 #define    CAN_ERROR_STATUS_MASK         0x03u
27 #define    CAN_RX_GTE96_SHIFT            19u
28 #define    CAN_FLAG_MASK                 0x01u
29 #define    CAN_ERROR_COUNT_SHIFT         8u
30 #define    CAN_ERROR_COUNT_MASK          0xFFu
31 #define    CAN_TXGTE96_SHIFT             18u
32 #define    CAN_INT_MASK                  0xFFFFFFFCu
33 #define    ENABLE                        1u
34 #define    DISABLE                       0u
35 #define    SYSREG_CAN_SOFTRESET_MASK     (uint32_t)(3 << 14u)
36 
37 /*******************************************************************************
38  * Instance definition
39  */
40 mss_can_instance_t g_mss_can_0_lo;
41 mss_can_instance_t g_mss_can_1_lo;
42 mss_can_instance_t g_mss_can_0_hi;
43 mss_can_instance_t g_mss_can_1_hi;
44 
45 static void global_init
46 (
47     mss_can_instance_t* this_wd
48 );
49 
50 /***************************************************************************//**
51  * MSS_CAN_init()
52  * See "mss_can.h" for details of how to use this function.
53  */
54 uint8_t
MSS_CAN_init(mss_can_instance_t * this_can,uint32_t bitrate,pmss_can_config_reg pcan_config,uint8_t basic_can_rx_mb,uint8_t basic_can_tx_mb)55 MSS_CAN_init
56 (
57     mss_can_instance_t* this_can,
58     uint32_t bitrate,
59     pmss_can_config_reg pcan_config,
60     uint8_t basic_can_rx_mb,
61     uint8_t basic_can_tx_mb
62 )
63 {
64     uint32_t temp;
65     uint8_t mailbox_number;
66     uint8_t ret_value;
67     mss_can_rxmsgobject canrxobj;
68 
69     global_init(this_can);
70 
71     /* Initialize the device structure */
72     this_can->basic_can_rx_mb = basic_can_rx_mb;
73     this_can->basic_can_tx_mb = basic_can_tx_mb;
74 
75     /* Initialize the rx mailbox */
76     canrxobj.ID = 0u;
77     canrxobj.DATAHIGH = 0u;
78     canrxobj.DATALOW = 0u;
79     canrxobj.AMR.L = 0u;
80     canrxobj.ACR.L = 0u;
81     canrxobj.AMR_D = 0u;
82     canrxobj.ACR_D = 0u;
83     canrxobj.RXB.L = (0u | CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL);
84 
85     for (mailbox_number = 0u; mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
86     {
87         ret_value = MSS_CAN_config_buffer_n(this_can, mailbox_number,
88                                             &canrxobj);
89     }
90 
91     /* Configure CAN controller */
92     if (CAN_SPEED_MANUAL == bitrate)
93     {
94         /*
95          * If user wants to specify registers directly  Check if parameters
96          * meet minimums.
97          */
98         if (pcan_config->CFG_TSEG1 < 2u)
99         {
100             return (CAN_TSEG1_TOO_SMALL );
101         }
102 
103         if ((pcan_config->CFG_TSEG2 == 0u) ||
104             ((pcan_config->SAMPLING_MODE == 1u) && (pcan_config->CFG_TSEG2
105              == 1u)))
106         {
107             return (CAN_TSEG2_TOO_SMALL);
108         }
109         temp = pcan_config->CFG_SJW;
110         if ((temp > pcan_config->CFG_TSEG1) ||
111             (temp > pcan_config->CFG_TSEG2))
112         {
113             return (CAN_SJW_TOO_BIG);
114         }
115 
116         this_can->hw_reg->Config.L = pcan_config->L;
117     }
118     else
119     {
120         /* User has chosen a default setting. */
121         this_can->hw_reg->Config.L = bitrate;
122     }
123 
124     /* Disable Interrupts */
125     this_can->hw_reg->IntEbl.L = DISABLE;
126 
127     return (CAN_OK);
128 }
129 
130 /***************************************************************************//**
131  * MSS_CAN_set_config_reg()
132  * See "mss_can.h" for details of how to use this function.
133  */
134 void
MSS_CAN_set_config_reg(mss_can_instance_t * this_can,uint32_t cfg)135 MSS_CAN_set_config_reg
136 (
137     mss_can_instance_t* this_can,
138     uint32_t cfg
139 )
140 {
141     /* Clear all pending interrupts */
142     this_can->hw_reg->IntStatus.L = DISABLE;
143 
144     /* Disable CAN Device */
145     this_can->hw_reg->Command.RUN_STOP = DISABLE;
146 
147     /* Disable receive interrupts. */
148     this_can->hw_reg->IntEbl.RX_MSG = DISABLE;
149 
150     /* Disable interrupts from CAN device. */
151     this_can->hw_reg->IntEbl.INT_EBL = DISABLE;
152 
153     /* Sets configuration bits */
154     this_can->hw_reg->Config.L = cfg;
155     MSS_CAN_start(this_can);
156 }
157 
158 /***************************************************************************//**
159  * MSS_CAN_set_mode()
160  * See "mss_can.h" for details of how to use this function.
161  */
162 void
MSS_CAN_set_mode(mss_can_instance_t * this_can,mss_can_mode_t mode)163 MSS_CAN_set_mode
164 (
165     mss_can_instance_t* this_can,
166     mss_can_mode_t mode
167 )
168 {
169     this_can->hw_reg->Command.RUN_STOP = DISABLE;
170     if (CANOP_SW_RESET == mode)
171     {
172         SYSREG->SOFT_RESET_CR |= SYSREG_CAN_SOFTRESET_MASK;
173         SYSREG->SOFT_RESET_CR &= ~SYSREG_CAN_SOFTRESET_MASK;
174     }
175     else
176     {
177         this_can->hw_reg->Command.L = (uint32_t)mode;
178     }
179 }
180 
181 /***************************************************************************//**
182  * MSS_CAN_start()
183  * See "mss_can.h" for details of how to use this function.
184  */
185 void
MSS_CAN_start(mss_can_instance_t * this_can)186 MSS_CAN_start
187 (
188     mss_can_instance_t* this_can
189 )
190 {
191     /* Clear all pending interrupts*/
192     this_can->hw_reg->IntStatus.L = DISABLE;
193 
194     /* Enable CAN Device*/
195     this_can->hw_reg->Command.RUN_STOP = ENABLE;
196 
197     /* Enable CAN Interrupt at NVIC level- if supported */
198 #ifdef MSS_CAN_ENABLE_INTERRUPTS
199     if (if (&g_mss_can_0_lo == this_can) || (&g_mss_can_0_hi == this_can))
200     {
201         PLIC_DisableIRQ(CAN0_PLIC);
202     }
203     else
204     {
205         PLIC_DisableIRQ(CAN1_PLIC);
206     }
207 #endif
208 
209     /* Enable receive interrupts. */
210     this_can->hw_reg->IntEbl.RX_MSG = ENABLE;
211 
212     /* Enable interrupts from CAN device.*/
213     this_can->hw_reg->IntEbl.INT_EBL = ENABLE;
214 
215 }
216 
217 /***************************************************************************//**
218  * MSS_CAN_stop()
219  * See "mss_can.h" for details of how to use this function.
220  */
221 void
MSS_CAN_stop(mss_can_instance_t * this_can)222 MSS_CAN_stop
223 (
224     mss_can_instance_t* this_can
225 )
226 {
227     this_can->hw_reg->Command.RUN_STOP = DISABLE;
228 }
229 
230 /***************************************************************************//**
231  * MSS_CAN_get_id()
232  * See "mss_can.h" for details of how to use this function.
233  */
234 uint32_t
MSS_CAN_get_id(pmss_can_msgobject pmsg)235 MSS_CAN_get_id
236 (
237     pmss_can_msgobject pmsg
238 )
239 {
240     if (pmsg->IDE)
241     {
242         return (pmsg->ID);
243     }
244     else
245     {
246         return (pmsg->ID >> CAN_ID_SHIFT);
247     }
248 }
249 
250 /***************************************************************************//**
251  * MSS_CAN_set_id()
252  * See "mss_can.h" for details of how to use this function.
253  */
254 uint32_t
MSS_CAN_set_id(pmss_can_msgobject pmsg)255 MSS_CAN_set_id
256 (
257     pmss_can_msgobject pmsg
258 )
259 {
260     if (pmsg->IDE)
261     {
262         return (pmsg->ID);
263     }
264     else
265     {
266         return (pmsg->ID << CAN_ID_SHIFT);
267     }
268 }
269 
270 /***************************************************************************//**
271  * MSS_CAN_get_msg_filter_mask()
272  * See "mss_can.h" for details of how to use this function.
273  */
274 uint32_t
MSS_CAN_get_msg_filter_mask(uint32_t id,uint8_t ide,uint8_t rtr)275 MSS_CAN_get_msg_filter_mask
276 (
277     uint32_t id,
278     uint8_t ide,
279     uint8_t rtr
280 )
281 {
282     if (ide)
283     {
284         id <<= 3u;
285     }
286     else
287     {
288         id <<= 21;
289 
290         /* Set unused ID bits to 1! */
291         id |= (0x3FFFF << 3u);
292     }
293     id |= ((uint32_t)(ide << 2u) | (uint32_t)(rtr << 1u));
294 
295     return (id);
296 }
297 
298 /***************************************************************************//**
299  * MSS_CAN_set_int_ebl()
300  * See "mss_can.h" for details of how to use this function.
301  */
302 void
MSS_CAN_set_int_ebl(mss_can_instance_t * this_can,uint32_t irq_flag)303 MSS_CAN_set_int_ebl
304 (
305     mss_can_instance_t* this_can,
306     uint32_t irq_flag
307 )
308 {
309     this_can->hw_reg->IntEbl.L |= irq_flag;
310 }
311 
312 /***************************************************************************//**
313  * MSS_CAN_clear_int_ebl()
314  * See "mss_can.h" for details of how to use this function.
315  */
316 void
MSS_CAN_clear_int_ebl(mss_can_instance_t * this_can,uint32_t irq_flag)317 MSS_CAN_clear_int_ebl
318 (
319     mss_can_instance_t* this_can,
320     uint32_t irq_flag
321 )
322 {
323     this_can->hw_reg->IntEbl.L &= ~irq_flag;
324 }
325 
326 /***************************************************************************//**
327  * MSS_CAN_get_global_int_ebl()
328  * See "mss_can.h" for details of how to use this function.
329  */
330 uint32_t
MSS_CAN_get_global_int_ebl(mss_can_instance_t * this_can)331 MSS_CAN_get_global_int_ebl
332 (
333     mss_can_instance_t* this_can
334 )
335 {
336     return (this_can->hw_reg->IntEbl.INT_EBL);
337 }
338 
339 /***************************************************************************//**
340  * MSS_CAN_get_int_ebl()
341  * See "mss_can.h" for details of how to use this function.
342  */
343 uint32_t
MSS_CAN_get_int_ebl(mss_can_instance_t * this_can)344 MSS_CAN_get_int_ebl
345 (
346     mss_can_instance_t* this_can
347 )
348 {
349     return (this_can->hw_reg->IntEbl.L & CAN_INT_MASK);
350 }
351 
352 /***************************************************************************//**
353  * MSS_CAN_clear_int_status()
354  * See "mss_can.h" for details of how to use this function.
355  */
356 void
MSS_CAN_clear_int_status(mss_can_instance_t * this_can,uint32_t irq_flag)357 MSS_CAN_clear_int_status
358 (
359     mss_can_instance_t* this_can,
360     uint32_t irq_flag
361 )
362 {
363     this_can->hw_reg->IntStatus.L = irq_flag;
364 }
365 
366 /***************************************************************************//**
367  * MSS_CAN_get_int_status()
368  * See "mss_can.h" for details of how to use this function.
369  */
370 uint32_t
MSS_CAN_get_int_status(mss_can_instance_t * this_can)371 MSS_CAN_get_int_status
372 (
373     mss_can_instance_t* this_can
374 )
375 {
376     return (this_can->hw_reg->IntStatus.L);
377 }
378 
379 /***************************************************************************//**
380  * MSS_CAN_set_rtr_message_n()
381  * See "mss_can.h" for details of how to use this function.
382  */
383 uint8_t
MSS_CAN_set_rtr_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)384 MSS_CAN_set_rtr_message_n
385 (
386     mss_can_instance_t* this_can,
387     uint8_t mailbox_number,
388     pmss_can_msgobject pmsg
389 )
390 {
391     /* Is buffer configured for Full CAN? */
392     if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
393     {
394         return (CAN_BASIC_CAN_MAILBOX);
395     }
396 
397     /* Is buffer configured for RTR auto-replay? */
398     if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLY == 0u)
399     {
400         return (CAN_NO_RTR_MAILBOX);
401     }
402     else
403     {
404         /* Transfer the ID. */
405         this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID;
406         this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
407         this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
408         return (CAN_OK);
409     }
410 }
411 
412 /***************************************************************************//**
413  * MSS_CAN_get_rtr_message_abort_n()
414  * See "mss_can.h" for details of how to use this function.
415  */
416 uint8_t
MSS_CAN_get_rtr_message_abort_n(mss_can_instance_t * this_can,uint8_t mailbox_number)417 MSS_CAN_get_rtr_message_abort_n
418 (
419     mss_can_instance_t* this_can,
420     uint8_t mailbox_number
421 )
422 {
423     /* Is buffer configured for Full CAN? */
424     if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
425     {
426         /* Mailbox is configured for basic CAN */
427         return (CAN_BASIC_CAN_MAILBOX);
428     }
429 
430     /* Set abort request */
431     this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRABORT = 1u;
432 
433     /* Check the abort is granted */
434     if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLYPEND == 0u)
435     {
436         /* If the RX buffer isn't busy. Abort was successful */
437         return (CAN_OK);
438     }
439     else
440     {
441         /* Message not aborted.*/
442         return (CAN_ERR);
443     }
444 }
445 
446 /***************************************************************************//**
447  * MSS_CAN_config_buffer()
448  * See "mss_can.h" for details of how to use this function.
449  */
450 uint8_t
MSS_CAN_config_buffer(mss_can_instance_t * this_can,pmss_can_filterobject pfilter)451 MSS_CAN_config_buffer
452 (
453     mss_can_instance_t* this_can,
454     pmss_can_filterobject pfilter
455 )
456 {
457     uint8_t success = CAN_NO_MSG;
458     uint8_t mailbox_number;
459 
460     /* Is a buffer configured for Basic CAN? */
461     if (this_can->basic_can_rx_mb == 0u)
462     {
463         return (CAN_INVALID_MAILBOX);
464     }
465 
466     /* Find next BASIC CAN buffer that has a message available */
467     for (mailbox_number = CAN_RX_MAILBOX - this_can->basic_can_rx_mb;  \
468                               mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
469     {
470         /* Set filters */
471         this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pfilter->ACR.L;
472         this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pfilter->AMR.L;
473         this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pfilter->AMCR_D.MASK;
474         this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pfilter->AMCR_D.CODE;
475 
476         /* Configure mailbox */
477         if (mailbox_number < (CAN_RX_MAILBOX - 1))
478         {
479             /* set link flag, if not last buffer */
480             this_can->hw_reg->RxMsg[mailbox_number].RXB.L =
481                                           (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
482                                           CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL | \
483                                           CAN_RX_LINK_EBL);
484         }
485         else
486         {
487             this_can->hw_reg->RxMsg[mailbox_number].RXB.L =
488                                           (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
489                                           CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL);
490         }
491         success = CAN_OK;
492     }
493     return (success);
494 }
495 
496 /***************************************************************************//**
497  * MSS_CAN_config_buffer_n()
498  * See "mss_can.h" for details of how to use this function.
499  */
500 uint8_t
MSS_CAN_config_buffer_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_rxmsgobject pmsg)501 MSS_CAN_config_buffer_n
502 (
503     mss_can_instance_t* this_can,
504     uint8_t mailbox_number,
505     pmss_can_rxmsgobject pmsg
506 )
507 {
508     /* Is buffer configured for Full CAN? */
509     if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
510     {
511         return (CAN_BASIC_CAN_MAILBOX);
512     }
513 
514     /* Configure mailbox */
515     this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID;
516     this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
517     this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
518     this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pmsg->ACR.L;
519     this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pmsg->AMR.L;
520     this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pmsg->AMR_D;
521     this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pmsg->ACR_D;
522     this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (pmsg->RXB.L | \
523                                            CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \
524                                            CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL);
525     return (CAN_OK);
526 }
527 
528 /***************************************************************************//**
529  * MSS_CAN_get_message_n()
530  * See "mss_can.h" for details of how to use this function.
531  */
532 uint8_t
MSS_CAN_get_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)533 MSS_CAN_get_message_n
534 (
535     mss_can_instance_t* this_can,
536     uint8_t mailbox_number,
537     pmss_can_msgobject pmsg
538 )
539 {
540     /* Is buffer configured for Full CAN? */
541     if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb))
542     {
543         return (CAN_BASIC_CAN_MAILBOX);
544     }
545 
546     /* Check that a new message is available and get it */
547     if ((ENABLE == this_can->hw_reg->Command.RUN_STOP) &&
548         (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV))
549     {
550         /* Copy ID */
551         pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID;
552 
553         /* Copy 4 of the data bytes */
554         pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW;
555 
556         /* Copy the other 4 data bytes. */
557         pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH;
558 
559         /* Get DLC, IDE and RTR and time stamp. */
560         pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L;
561 
562         /* Ack that it's been removed from the FIFO */
563         this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE;
564 
565         /* And let app know there is a message. */
566         return (CAN_VALID_MSG);
567     }
568     else
569     {
570         return (CAN_NO_MSG);
571     }
572 }
573 
574 /*******************************************************************************
575  * MSS_CAN_get_message()
576  * See "mss_can.h" for details of how to use this function.
577  */
578 uint8_t
MSS_CAN_get_message(mss_can_instance_t * this_can,pmss_can_msgobject pmsg)579 MSS_CAN_get_message
580 (
581     mss_can_instance_t* this_can,
582     pmss_can_msgobject pmsg
583 )
584 {
585     uint8_t success = CAN_NO_MSG;
586     uint8_t mailbox_number;
587 
588     /* Is a buffer configured for Basic CAN? */
589     if (this_can->basic_can_rx_mb == 0u)
590     {
591         return (CAN_INVALID_MAILBOX);
592     }
593 
594     /* Find next BASIC CAN buffer that has a message available */
595     for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb;  \
596                              mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
597     {
598         /* Check that if there is a valid message */
599         if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)
600         {
601             /* Copy ID */
602             pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID;
603 
604             /* Copy 4 of the data bytes */
605             pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW;
606 
607             /* Copy the other 4 data bytes.*/
608             pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH;
609 
610             /* Get DLC, IDE and RTR and time stamp.*/
611             pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L;
612 
613             /* Ack that it's been removed from the FIFO */
614             this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE;
615             success = CAN_VALID_MSG;
616             break;
617         }
618     }
619     return (success);
620 }
621 
622 /***************************************************************************//**
623  * MSS_CAN_get_message_av()
624  * See "mss_can.h" for details of how to use this function.
625  */
626 uint8_t
MSS_CAN_get_message_av(mss_can_instance_t * this_can)627 MSS_CAN_get_message_av
628 (
629     mss_can_instance_t* this_can
630 )
631 {
632     uint8_t success = CAN_NO_MSG;
633     uint8_t mailbox_number;
634 
635     /* Is a buffer configured for Basic CAN? */
636     if (this_can->basic_can_rx_mb == 0u)
637     {
638         return (CAN_INVALID_MAILBOX);
639     }
640 
641     /* Find next BASIC CAN buffer that has a message available */
642     for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb;  \
643                              mailbox_number < CAN_RX_MAILBOX; mailbox_number++)
644     {
645         /* Check that buffer is enabled and contains a message */
646         if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)
647         {
648             success = CAN_VALID_MSG;
649             break;
650         }
651     }
652     return (success);
653 }
654 
655 /***************************************************************************//**
656  * MSS_CAN_send_message_n()
657  * See "mss_can.h" for details of how to use this function.
658  */
659 uint8_t
MSS_CAN_send_message_n(mss_can_instance_t * this_can,uint8_t mailbox_number,pmss_can_msgobject pmsg)660 MSS_CAN_send_message_n
661 (
662     mss_can_instance_t* this_can,
663     uint8_t mailbox_number,
664     pmss_can_msgobject pmsg
665 )
666 {
667     /* Can't send if device is disabled */
668     if (DISABLE == this_can->hw_reg->Command.RUN_STOP)
669     {
670         /* Message not sent. */
671         return (CAN_NO_MSG);
672     }
673 
674     /* Is buffer configured for Full CAN? */
675     if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb))
676     {
677         /* mailbox is configured for basic CAN */
678         return (CAN_BASIC_CAN_MAILBOX);
679     }
680 
681     if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u)
682     {
683         /* If the Tx buffer isn't busy.... */
684         this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID;
685         this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
686         this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
687         this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \
688                                                    CAN_TX_WPNH_EBL | \
689                                                    CAN_TX_REQ);
690         return (CAN_VALID_MSG);
691     }
692     else
693     {
694         /* Message not sent. */
695         return (CAN_NO_MSG);
696     }
697 }
698 
699 /***************************************************************************//**
700  * MSS_CAN_send_message_abort_n()
701  * See "mss_can.h" for details of how to use this function.
702  */
703 uint8_t
MSS_CAN_send_message_abort_n(mss_can_instance_t * this_can,uint8_t mailbox_number)704 MSS_CAN_send_message_abort_n
705 (
706     mss_can_instance_t* this_can,
707     uint8_t mailbox_number
708 )
709 {
710     /* Is buffer configured for Full CAN? */
711     if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb))
712     {
713         /* mailbox is configured for basic CAN */
714         return (CAN_BASIC_CAN_MAILBOX);
715     }
716 
717     /* Set abort request */
718     this_can->hw_reg->TxMsg[mailbox_number].TXB.L =
719     ((this_can->hw_reg->TxMsg[mailbox_number].TXB.L & ~CAN_TX_REQ) | \
720      CAN_TX_ABORT);
721 
722     /* Check the abort is granted */
723     if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXABORT == 0u)
724     {
725         /* If the Tx buffer isn't busy, Abort was successful */
726         return (CAN_OK);
727     }
728     else
729     {
730         /* Message not aborted. */
731         return (CAN_ERR);
732     }
733 }
734 
735 /***************************************************************************//**
736  * MSS_CAN_send_message_ready()
737  * See "mss_can.h" for details of how to use this function.
738  */
739 uint8_t
MSS_CAN_send_message_ready(mss_can_instance_t * this_can)740 MSS_CAN_send_message_ready
741 (
742     mss_can_instance_t* this_can
743 )
744 {
745     uint8_t success = CAN_ERR;
746     uint8_t mailbox_number;
747 
748     /* Is a buffer configured for Basic CAN? */
749     if (this_can->basic_can_tx_mb == 0u)
750     {
751        return (CAN_INVALID_MAILBOX);
752     }
753 
754     /* Find next BASIC CAN buffer that is available */
755     for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \
756                              mailbox_number < CAN_TX_MAILBOX; mailbox_number++)
757     {
758         if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u)
759         {
760             /* Tx buffer isn't busy */
761             success = CAN_OK;
762             break;
763         }
764     }
765 
766     return (success);
767 }
768 
769 /***************************************************************************//**
770  * MSS_CAN_send_message()
771  * See "mss_can.h" for details of how to use this function.
772  */
773 uint8_t
MSS_CAN_send_message(mss_can_instance_t * this_can,pmss_can_msgobject pmsg)774 MSS_CAN_send_message
775 (
776     mss_can_instance_t* this_can,
777     pmss_can_msgobject pmsg
778 )
779 {
780     uint8_t success = CAN_NO_MSG;
781     uint8_t mailbox_number;
782 
783     /* Is a buffer configured for Basic CAN? */
784     if (this_can->basic_can_tx_mb == 0u)
785     {
786         return (CAN_INVALID_MAILBOX);
787     }
788 
789     /* Find next BASIC CAN buffer that is available */
790     for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb;  \
791                              mailbox_number < CAN_TX_MAILBOX; mailbox_number++)
792     {
793         /* Check which transmit mailbox is not busy and use it. */
794         if ((MSS_CAN_get_tx_buffer_status(this_can) & (1u << mailbox_number))
795             == 0)
796         {
797             /* If the Tx buffer isn't busy.... */
798             this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID;
799             this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW;
800             this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH;
801             this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \
802                                                    CAN_TX_WPNH_EBL | \
803                                                    CAN_TX_REQ);
804             success = CAN_VALID_MSG;
805             break;
806         }
807     }
808 
809     return (success);
810 }
811 
812 /***************************************************************************//**
813  * MSS_CAN_get_mask_n()
814  * See "mss_can.h" for details of how to use this function.
815  */
816 uint8_t
MSS_CAN_get_mask_n(mss_can_instance_t * this_can,uint8_t mailbox_number,uint32_t * pamr,uint32_t * pacr,uint16_t * pdta_amr,uint16_t * pdta_acr)817 MSS_CAN_get_mask_n
818 (
819     mss_can_instance_t* this_can,
820     uint8_t mailbox_number,
821     uint32_t *pamr,
822     uint32_t *pacr,
823     uint16_t *pdta_amr,
824     uint16_t *pdta_acr
825 )
826 {
827     if (mailbox_number >= CAN_RX_MAILBOX)
828     {
829         return (CAN_BASIC_CAN_MAILBOX);
830     }
831 
832     *pamr = this_can->hw_reg->RxMsg[mailbox_number].AMR.L;
833     *pacr = this_can->hw_reg->RxMsg[mailbox_number].ACR.L;
834     *pdta_acr = this_can->hw_reg->RxMsg[mailbox_number].ACR_D;
835     *pdta_amr = this_can->hw_reg->RxMsg[mailbox_number].AMR_D;
836 
837     return (CAN_OK);
838 }
839 
840 /***************************************************************************//**
841  * MSS_CAN_set_mask_n()
842  * See "mss_can.h" for details of how to use this function.
843  */
844 uint8_t
MSS_CAN_set_mask_n(mss_can_instance_t * this_can,uint8_t mailbox_number,uint32_t amr,uint32_t acr,uint16_t dta_amr,uint16_t dta_acr)845 MSS_CAN_set_mask_n
846 (
847     mss_can_instance_t* this_can,
848     uint8_t mailbox_number,
849     uint32_t amr,
850     uint32_t acr,
851     uint16_t dta_amr,
852     uint16_t dta_acr
853 )
854 {
855     if (mailbox_number >= CAN_RX_MAILBOX)
856     {
857         return (CAN_BASIC_CAN_MAILBOX);
858     }
859 
860     this_can->hw_reg->RxMsg[mailbox_number].AMR.L = amr;
861     this_can->hw_reg->RxMsg[mailbox_number].ACR.L = acr;
862     this_can->hw_reg->RxMsg[mailbox_number].AMR_D = (uint32_t)dta_amr;
863     this_can->hw_reg->RxMsg[mailbox_number].ACR_D = (uint32_t)dta_acr;
864 
865     return (CAN_OK);
866 }
867 
868 /***************************************************************************//**
869  * MSS_CAN_get_rx_buffer_status()
870  * See "mss_can.h" for details of how to use this function.
871  */
872 uint32_t
MSS_CAN_get_rx_buffer_status(mss_can_instance_t * this_can)873 MSS_CAN_get_rx_buffer_status
874 (
875     mss_can_instance_t* this_can
876 )
877 {
878 #ifdef CANMOD3
879     return (this_can->hw_reg->BufferStatus.L & 0x0000FFFF);
880 #else
881     return (this_can->hw_reg->BufferStatus.RXMSGAV);
882 #endif
883 }
884 
885 /***************************************************************************//**
886  * MSS_CAN_get_tx_buffer_status()
887  * See "mss_can.h" for details of how to use this function.
888  */
889 uint32_t
MSS_CAN_get_tx_buffer_status(mss_can_instance_t * this_can)890 MSS_CAN_get_tx_buffer_status
891 (
892     mss_can_instance_t* this_can
893 )
894 {
895 #ifdef CANMOD3
896     return ((this_can->hw_reg->BufferStatus.L >> 16u) & 0x00FF);
897 #else
898     return (this_can->hw_reg->BufferStatus.TXREQ);
899 #endif
900 }
901 
902 /***************************************************************************//**
903  * MSS_CAN_get_error_status()
904  * See "mss_can.h" for details of how to use this function.
905  */
906 uint8_t
MSS_CAN_get_error_status(mss_can_instance_t * this_can,uint32_t * status)907 MSS_CAN_get_error_status
908 (
909     mss_can_instance_t* this_can,
910     uint32_t *status
911 )
912 {
913     /* Supply error register info if user wants. */
914     *status = this_can->hw_reg->ErrorStatus.L;
915 
916     /* 00 Error Active, 01 Error Passive, 1x Bus Off */
917     return ((uint8_t)(((*status) >> CAN_ERROR_STATUS_SHIFT) &
918                       CAN_ERROR_STATUS_MASK));
919 }
920 
921 /***************************************************************************//**
922  * MSS_CAN_get_rx_error_count()
923  * See "mss_can.h" for details of how to use this function.
924  */
925 uint32_t
MSS_CAN_get_rx_error_count(mss_can_instance_t * this_can)926 MSS_CAN_get_rx_error_count
927 (
928     mss_can_instance_t* this_can
929 )
930 {
931     return ((this_can->hw_reg->ErrorStatus.L >> CAN_ERROR_COUNT_SHIFT) & \
932                                                           CAN_ERROR_COUNT_MASK);
933 }
934 
935 /***************************************************************************//**
936  * MSS_CAN_get_rx_gte96()
937  * See "mss_can.h" for details of how to use this function.
938  */
939 uint32_t
MSS_CAN_get_rx_gte96(mss_can_instance_t * this_can)940 MSS_CAN_get_rx_gte96
941 (
942     mss_can_instance_t* this_can
943 )
944 {
945     return ((this_can->hw_reg->ErrorStatus.L >> CAN_RX_GTE96_SHIFT) & \
946                                                                 CAN_FLAG_MASK);
947 }
948 
949 /***************************************************************************//**
950  * MSS_CAN_get_tx_error_count()
951  * See "mss_can.h" for details of how to use this function.
952  */
953 uint32_t
MSS_CAN_get_tx_error_count(mss_can_instance_t * this_can)954 MSS_CAN_get_tx_error_count
955 (
956     mss_can_instance_t* this_can
957 )
958 {
959     return (this_can->hw_reg->ErrorStatus.L & CAN_ERROR_COUNT_MASK);
960 }
961 
962 /***************************************************************************//**
963  * MSS_CAN_get_tx_gte96 ()
964  * See "mss_can.h" for details of how to use this function.
965  */
966 uint32_t
MSS_CAN_get_tx_gte96(mss_can_instance_t * this_can)967 MSS_CAN_get_tx_gte96
968 (
969     mss_can_instance_t* this_can
970 )
971 {
972     return ((this_can->hw_reg->ErrorStatus.L >> CAN_TXGTE96_SHIFT) & \
973                                                                 CAN_FLAG_MASK);
974 }
975 
976 /*******************************************************************************
977  * Global initialization for all modes
978  */
global_init(mss_can_instance_t * this_wd)979 static void global_init
980 (
981     mss_can_instance_t* this_wd
982 )
983 {
984     if (&g_mss_can_0_lo == this_wd)
985     {
986         this_wd->hw_reg = MSS_CAN_0_LO_BASE;
987         this_wd->irqn = CAN0_PLIC;
988         this_wd->int_type = 0;
989     }
990     else if (&g_mss_can_1_lo == this_wd)
991     {
992         this_wd->hw_reg = MSS_CAN_1_LO_BASE;
993         this_wd->irqn = CAN1_PLIC;
994         this_wd->int_type = 0;
995     }
996     else if (&g_mss_can_0_hi == this_wd)
997     {
998         this_wd->hw_reg = MSS_CAN_0_HI_BASE;
999         this_wd->irqn = CAN0_PLIC;
1000         this_wd->int_type = 0;
1001     }
1002     else if (&g_mss_can_1_hi == this_wd)
1003     {
1004         this_wd->hw_reg = MSS_CAN_1_HI_BASE;
1005         this_wd->irqn = CAN1_PLIC;
1006         this_wd->int_type = 0;
1007     }
1008     else
1009     {
1010         ;/* LDRA Warning */
1011     }
1012 }
1013 
1014 #ifndef MSS_CAN_USER_ISR
1015 /***************************************************************************//**
1016  * CAN interrupt service routine.
1017  * CAN_IRQHandler is included within the RISC-V vector table as part of the
1018  * MPFS HAL.
1019  */
External_can0_plic_IRQHandler(void)1020 uint8_t External_can0_plic_IRQHandler(void)
1021 {
1022 #ifdef MSS_CAN_ENABLE_INTERRUPTS
1023     /* User provided code is required here to handle interrupts from the MSS CAN
1024      * peripheral. Remove the assert once this is in place.*/
1025     ASSERT(!"An ISR is required here if interrupts are enabled");
1026 #else
1027     ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \
1028            disabled");
1029 #endif
1030     return 0;
1031 }
1032 
can1_IRQHandler(void)1033 uint8_t can1_IRQHandler(void)
1034 {
1035 #ifdef MSS_CAN_ENABLE_INTERRUPTS
1036     /* User provided code is required here to handle interrupts from the MSS CAN
1037      * peripheral. Remove the assert once this is in place.*/
1038     ASSERT(!"An ISR is required here if interrupts are enabled");
1039 #else
1040     ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \
1041            disabled");
1042 #endif
1043     return 0;
1044 }
1045 #endif
1046 
1047 #ifdef __cplusplus
1048 }
1049 #endif
1050