1 /*******************************************************************************
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PolarFire SoC Microprocessor Subsystem MMUART bare metal software driver
7  * implementation.
8  *
9  */
10 #include "mpfs_hal/mss_hal.h"
11 #include "mss_uart_regs.h"
12 #include "mss_uart.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 #define MSS_UART0_LO_BASE           (MSS_UART_TypeDef*)0x20000000UL
19 #define MSS_UART1_LO_BASE           (MSS_UART_TypeDef*)0x20100000UL
20 #define MSS_UART2_LO_BASE           (MSS_UART_TypeDef*)0x20102000UL
21 #define MSS_UART3_LO_BASE           (MSS_UART_TypeDef*)0x20104000UL
22 #define MSS_UART4_LO_BASE           (MSS_UART_TypeDef*)0x20106000UL
23 
24 #define MSS_UART0_HI_BASE           (MSS_UART_TypeDef*)0x28000000UL
25 #define MSS_UART1_HI_BASE           (MSS_UART_TypeDef*)0x28100000UL
26 #define MSS_UART2_HI_BASE           (MSS_UART_TypeDef*)0x28102000UL
27 #define MSS_UART3_HI_BASE           (MSS_UART_TypeDef*)0x28104000UL
28 #define MSS_UART4_HI_BASE           (MSS_UART_TypeDef*)0x28106000UL
29 
30 
31 mss_uart_instance_t g_mss_uart0_lo;
32 mss_uart_instance_t g_mss_uart1_lo;
33 mss_uart_instance_t g_mss_uart2_lo;
34 mss_uart_instance_t g_mss_uart3_lo;
35 mss_uart_instance_t g_mss_uart4_lo;
36 
37 mss_uart_instance_t g_mss_uart0_hi;
38 mss_uart_instance_t g_mss_uart1_hi;
39 mss_uart_instance_t g_mss_uart2_hi;
40 mss_uart_instance_t g_mss_uart3_hi;
41 mss_uart_instance_t g_mss_uart4_hi;
42 
43 /* This variable tracks if the UART peripheral is located on S5 or S6 on AXI
44  * switch. This will be used to determine which UART instance to be passed to
45  * UART interrupt handler. value 0 = S5(low). value 1 = S6(high)
46  * Bit positions:
47  * 0 ==> MMUART0
48  * 1 ==> MMUART1
49  * 2 ==> MMUART2
50  * 3 ==> MMUART3
51  * 4 ==> MMUART4
52 
53  */
54 static uint32_t g_uart_axi_pos = 0x0u;
55 
56 /*******************************************************************************
57  * Defines
58  */
59 #define TX_COMPLETE                     0u
60 #define TX_FIFO_SIZE                    16u
61 
62 #define FCR_TRIG_LEVEL_MASK             0xC0u
63 
64 #define IIRF_MASK                       0x0Fu
65 
66 #define INVALID_INTERRUPT               0u
67 #define INVALID_IRQ_HANDLER             ((mss_uart_irq_handler_t) 0)
68 #define NULL_HANDLER                    ((mss_uart_irq_handler_t) 0)
69 
70 #define MSS_UART_DATA_READY             ((uint8_t) 0x01)
71 
72 #define SYNC_ASYNC_MODE_MASK            (0x7u)
73 
74 #define UART0_POSITION_MASK              0x01u
75 #define UART1_POSITION_MASK              0x02u
76 #define UART2_POSITION_MASK              0x04u
77 #define UART3_POSITION_MASK              0x08u
78 #define UART4_POSITION_MASK              0x10u
79 
80 /*******************************************************************************
81  * Possible values for Interrupt Identification Register Field.
82  */
83 #define IIRF_MODEM_STATUS               0x00u
84 #define IIRF_THRE                       0x02u
85 #define IIRF_MMI                        0x03u
86 #define IIRF_RX_DATA                    0x04u
87 #define IIRF_RX_LINE_STATUS             0x06u
88 #define IIRF_DATA_TIMEOUT               0x0Cu
89 
90 /*******************************************************************************
91  * Receiver error status mask.
92  */
93 #define STATUS_ERROR_MASK    ( MSS_UART_OVERUN_ERROR | MSS_UART_PARITY_ERROR | \
94                                MSS_UART_FRAMING_ERROR  | MSS_UART_BREAK_ERROR | \
95                                MSS_UART_FIFO_ERROR)
96 
97 /*******************************************************************************
98  * Local functions.
99  */
100 static void global_init(mss_uart_instance_t * this_uart, uint32_t baud_rate,
101                                                          uint8_t line_config);
102 static void uart_isr(mss_uart_instance_t * this_uart);
103 static void default_tx_handler(mss_uart_instance_t * this_uart);
104 static void enable_irq(const mss_uart_instance_t * this_uart);
105 static void disable_irq(const mss_uart_instance_t * this_uart);
106 static void config_baud_divisors
107 (
108     mss_uart_instance_t * this_uart,
109     uint32_t baudrate
110 );
111 
112 /*******************************************************************************
113  * Public Functions
114  *******************************************************************************/
115 /***************************************************************************//**
116  * See mss_uart.h for details of how to use this function.
117  */
118 void
MSS_UART_init(mss_uart_instance_t * this_uart,uint32_t baud_rate,uint8_t line_config)119 MSS_UART_init
120 (
121     mss_uart_instance_t* this_uart,
122     uint32_t baud_rate,
123     uint8_t line_config
124 )
125 {
126     /* Perform generic initialization */
127     global_init(this_uart, baud_rate, line_config);
128 
129     /* Disable LIN mode */
130     this_uart->hw_reg->MM0 &= ~ELIN_MASK;
131 
132     /* Disable IrDA mode */
133     this_uart->hw_reg->MM1 &= ~EIRD_MASK;
134 
135     /* Disable SmartCard Mode */
136     this_uart->hw_reg->MM2 &= ~EERR_MASK;
137 
138     /* set default tx handler for automated TX using interrupt in USART mode */
139     this_uart->tx_handler = default_tx_handler;
140 }
141 
142 /***************************************************************************//**
143  * See mss_uart.h for details of how to use this function.
144  */
MSS_UART_lin_init(mss_uart_instance_t * this_uart,uint32_t baud_rate,uint8_t line_config)145 void MSS_UART_lin_init
146 (
147     mss_uart_instance_t* this_uart,
148     uint32_t baud_rate,
149     uint8_t line_config
150 )
151 {
152     /* Perform generic initialization */
153     global_init(this_uart, baud_rate, line_config);
154 
155      /* Enable LIN mode */
156     this_uart->hw_reg->MM0 |= ELIN_MASK;
157 
158     /* Disable IrDA mode */
159     this_uart->hw_reg->MM1 &= ~EIRD_MASK;
160 
161     /* Disable SmartCard Mode */
162     this_uart->hw_reg->MM2 &= ~EERR_MASK;
163 }
164 
165 /***************************************************************************//**
166  * See mss_uart.h for details of how to use this function.
167  */
168 void
MSS_UART_irda_init(mss_uart_instance_t * this_uart,uint32_t baud_rate,uint8_t line_config,mss_uart_rzi_polarity_t rxpol,mss_uart_rzi_polarity_t txpol,mss_uart_rzi_pulsewidth_t pw)169 MSS_UART_irda_init
170 (
171     mss_uart_instance_t* this_uart,
172     uint32_t baud_rate,
173     uint8_t line_config,
174     mss_uart_rzi_polarity_t rxpol,
175     mss_uart_rzi_polarity_t txpol,
176     mss_uart_rzi_pulsewidth_t pw
177 )
178 {
179     /* Perform generic initialization */
180     global_init(this_uart, baud_rate, line_config);
181 
182      /* Enable LIN mode */
183     this_uart->hw_reg->MM0 &= ~ELIN_MASK;
184 
185     /* Disable IrDA mode */
186     this_uart->hw_reg->MM1 |= EIRD_MASK;
187 
188     ((rxpol == MSS_UART_ACTIVE_LOW) ? (this_uart->hw_reg->MM1 &= ~EIRX_MASK) :
189                                       (this_uart->hw_reg->MM1 |= EIRX_MASK));
190 
191     ((txpol == MSS_UART_ACTIVE_LOW) ? (this_uart->hw_reg->MM1 &= ~EITX_MASK) :
192                                       (this_uart->hw_reg->MM1 |= EITX_MASK));
193 
194     ((pw == MSS_UART_3_BY_16) ? (this_uart->hw_reg->MM1 &= ~EITP_MASK) :
195                                       (this_uart->hw_reg->MM1 |= EITP_MASK));
196     /* Disable SmartCard Mode */
197     this_uart->hw_reg->MM2 &= ~EERR_MASK;
198 }
199 
200 /***************************************************************************//**
201  * See mss_uart.h for details of how to use this function.
202  */
203 void
MSS_UART_smartcard_init(mss_uart_instance_t * this_uart,uint32_t baud_rate,uint8_t line_config)204 MSS_UART_smartcard_init
205 (
206     mss_uart_instance_t* this_uart,
207     uint32_t baud_rate,
208     uint8_t line_config
209 )
210 {
211     /* Perform generic initialization */
212     global_init(this_uart, baud_rate, line_config);
213 
214     /* Disable LIN mode */
215     this_uart->hw_reg->MM0 &= ~ELIN_MASK;
216 
217     /* Disable IrDA mode */
218     this_uart->hw_reg->MM1 &= ~EIRD_MASK;
219 
220     /* Enable SmartCard Mode : Only when data is 8-bit and 2 stop bits */
221     if ((MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS) ==
222         (line_config & (MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS)))
223     {
224         this_uart->hw_reg->MM2 |= EERR_MASK;
225 
226         /* Enable single wire half-duplex mode */
227         this_uart->hw_reg->MM2 |= ESWM_MASK;
228     }
229 }
230 
231 /***************************************************************************//**
232  * See mss_uart.h for details of how to use this function.
233  */
234 void
MSS_UART_polled_tx(mss_uart_instance_t * this_uart,const uint8_t * pbuff,uint32_t tx_size)235 MSS_UART_polled_tx
236 (
237     mss_uart_instance_t * this_uart,
238     const uint8_t * pbuff,
239     uint32_t tx_size
240 )
241 {
242     uint32_t char_idx = 0u;
243     uint32_t size_sent;
244     uint8_t status;
245     uint32_t temp_tx_size = tx_size;
246 
247     ASSERT(pbuff != ( (uint8_t*)0));
248     ASSERT(tx_size > 0u);
249 
250     if ((pbuff != ((uint8_t*)0)) && (temp_tx_size > 0u))
251     {
252         /* Remain in this loop until the entire input buffer
253          * has been transferred to the UART.
254          */
255         do
256         {
257             /* Read the Line Status Register and update the sticky record */
258             status = this_uart->hw_reg->LSR;
259             this_uart->status |= status;
260 
261             /* Check if TX FIFO is empty. */
262             if (status & MSS_UART_THRE)
263             {
264                 uint32_t fill_size = TX_FIFO_SIZE;
265 
266                 /* Calculate the number of bytes to transmit. */
267                 if (temp_tx_size < TX_FIFO_SIZE)
268                 {
269                     fill_size = temp_tx_size;
270                 }
271 
272                 /* Fill the TX FIFO with the calculated the number of bytes. */
273                 for (size_sent = 0u; size_sent < fill_size; ++size_sent)
274                 {
275                     /* Send next character in the buffer. */
276                     this_uart->hw_reg->THR = pbuff[char_idx];
277                     char_idx++;
278                 }
279 
280                 /* find the number of bytes remaining(not transmitted yet) */
281                 temp_tx_size -= size_sent;
282             }
283         }while (temp_tx_size);
284     }
285 }
286 
287 /***************************************************************************//**
288  * See mss_uart.h for details of how to use this function.
289  */
290 void
MSS_UART_polled_tx_string(mss_uart_instance_t * this_uart,const uint8_t * p_sz_string)291 MSS_UART_polled_tx_string
292 (
293     mss_uart_instance_t * this_uart,
294     const uint8_t * p_sz_string
295 )
296 {
297     uint32_t char_idx = 0u;
298     uint32_t fill_size;
299     uint8_t data_byte;
300     uint8_t status;
301 
302     ASSERT(p_sz_string != ((uint8_t*)0));
303 
304     if (p_sz_string != ((uint8_t*)0))
305     {
306         /* Get the first data byte from the input buffer */
307         data_byte = p_sz_string[char_idx];
308 
309         /* First check for the NULL terminator byte.
310          * Then remain in this loop until the entire string in the input buffer
311          * has been transferred to the UART.
312          */
313         while (0u != data_byte)
314         {
315             /* Wait until TX FIFO is empty. */
316             do
317             {
318                 status = this_uart->hw_reg->LSR;
319                 this_uart->status |= status;
320             }while (0u == (status & MSS_UART_THRE));
321 
322             /* Send bytes from the input buffer until the TX FIFO is full
323              * or we reach the NULL terminator byte.
324              */
325             fill_size = 0u;
326 
327             while ((0u != data_byte) && (fill_size < TX_FIFO_SIZE))
328             {
329                 /* Send the data byte */
330                 this_uart->hw_reg->THR = data_byte;
331                 ++fill_size;
332                 char_idx++;
333                 /* Get the next data byte from the input buffer */
334                 data_byte = p_sz_string[char_idx];
335             }
336         }
337     }
338 }
339 
340 /***************************************************************************//**
341  * See mss_uart.h for details of how to use this function.
342  */
343 void
MSS_UART_irq_tx(mss_uart_instance_t * this_uart,const uint8_t * pbuff,uint32_t tx_size)344 MSS_UART_irq_tx
345 (
346     mss_uart_instance_t * this_uart,
347     const uint8_t * pbuff,
348     uint32_t tx_size
349 )
350 {
351     ASSERT(pbuff != ((uint8_t*)0));
352     ASSERT(tx_size > 0u);
353 
354     if ((tx_size > 0u) && (pbuff != ((uint8_t*)0)))
355     {
356         /* Initialize the transmit info for the UART instance with the
357          * arguments */
358         this_uart->tx_buffer = pbuff;
359         this_uart->tx_buff_size = tx_size;
360         this_uart->tx_idx = 0u;
361 
362         /* assign default handler for data transfer */
363         this_uart->tx_handler = default_tx_handler;
364 
365         /* enables TX interrupt */
366         this_uart->hw_reg->IER |= ETBEI_MASK;
367         enable_irq(this_uart);
368     }
369 }
370 
371 /***************************************************************************//**
372  * See mss_uart.h for details of how to use this function.
373  */
374 int8_t
MSS_UART_tx_complete(mss_uart_instance_t * this_uart)375 MSS_UART_tx_complete
376 (
377     mss_uart_instance_t * this_uart
378 )
379 {
380     int8_t ret_value = 0;
381     uint8_t status = 0u;
382 
383     /* Read the Line Status Register and update the sticky record. */
384     status = this_uart->hw_reg->LSR;
385     this_uart->status |= status;
386 
387     if ((TX_COMPLETE == this_uart->tx_buff_size) &&
388        ((status & MSS_UART_TEMT) != 0u))
389     {
390         ret_value = (int8_t)1;
391     }
392 
393     return ret_value;
394 }
395 
396 /***************************************************************************//**
397  * See mss_uart.h for details of how to use this function.
398  */
399 size_t
MSS_UART_get_rx(mss_uart_instance_t * this_uart,uint8_t * rx_buff,size_t buff_size)400 MSS_UART_get_rx
401 (
402     mss_uart_instance_t * this_uart,
403     uint8_t * rx_buff,
404     size_t buff_size
405 )
406 {
407     size_t rx_size = 0u;
408     uint8_t status = 0u;
409 
410     ASSERT(rx_buff != ((uint8_t*)0));
411     ASSERT(buff_size > 0u);
412 
413     if ((rx_buff != (uint8_t*)0) && (buff_size > 0u))
414     {
415         status = this_uart->hw_reg->LSR;
416         this_uart->status |= status;
417 
418         while (((status & MSS_UART_DATA_READY) != 0u) && (rx_size < buff_size))
419         {
420             rx_buff[rx_size] = this_uart->hw_reg->RBR;
421             ++rx_size;
422             status = this_uart->hw_reg->LSR;
423             this_uart->status |= status;
424         }
425     }
426 
427     return rx_size;
428 }
429 
430 /***************************************************************************//**
431  * See mss_uart.h for details of how to use this function.
432  */
433 void
MSS_UART_enable_irq(mss_uart_instance_t * this_uart,mss_uart_irq_t irq_mask)434 MSS_UART_enable_irq
435 (
436     mss_uart_instance_t * this_uart,
437     mss_uart_irq_t irq_mask
438 )
439 {
440     ASSERT(MSS_UART_INVALID_IRQ > irq_mask);
441 
442     enable_irq(this_uart);
443 
444     if (MSS_UART_INVALID_IRQ > irq_mask)
445     {
446         /* irq_mask encoding: 1- enable
447          * bit 0 - Receive Data Available Interrupt
448          * bit 1 - Transmitter Holding  Register Empty Interrupt
449          * bit 2 - Receiver Line Status Interrupt
450          * bit 3 - Modem Status Interrupt
451          */
452         this_uart->hw_reg->IER |= ((uint8_t)(((uint32_t)irq_mask &
453                                                          (uint32_t)IIRF_MASK)));
454 
455 
456         /*
457          * bit 4 - Receiver time-out interrupt
458          * bit 5 - NACK / ERR signal interrupt
459          * bit 6 - PID parity error interrupt
460          * bit 7 - LIN break detection interrupt
461          * bit 8 - LIN Sync detection interrupt
462          */
463         this_uart->hw_reg->IEM |= (uint8_t)(((uint32_t)irq_mask >> 4u) &
464                                                          ((uint32_t)IIRF_MASK));
465     }
466 }
467 
468 /***************************************************************************//**
469  * See mss_uart.h for details of how to use this function.
470  */
471 void
MSS_UART_disable_irq(mss_uart_instance_t * this_uart,mss_uart_irq_t irq_mask)472 MSS_UART_disable_irq
473 (
474     mss_uart_instance_t * this_uart,
475     mss_uart_irq_t irq_mask
476 )
477 {
478      /* irq_mask encoding: 1 - disable
479      * bit 0 - Receive Data Available Interrupt
480      * bit 1 - Transmitter Holding  Register Empty Interrupt
481      * bit 2 - Receiver Line Status Interrupt
482      * bit 3 - Modem Status Interrupt
483      */
484     this_uart->hw_reg->IER &= ((uint8_t)(~((uint32_t)irq_mask &
485                                                         (uint32_t)IIRF_MASK)));
486 
487     /*
488      * bit 4 - Receiver time-out interrupt
489      * bit 5 - NACK / ERR signal interrupt
490      * bit 6 - PID parity error interrupt
491      * bit 7 - LIN break detection interrupt
492      * bit 8 - LIN Sync detection interrupt
493      */
494     this_uart->hw_reg->IEM &= (uint8_t)(~(((uint32_t)irq_mask >> 4u) &
495                                                         ((uint32_t)IIRF_MASK)));
496 
497     if(1 == this_uart->local_irq_enabled)
498     {
499         __disable_local_irq((int8_t)MMUART0_E51_INT);
500     }
501     else
502     {
503         disable_irq(this_uart);
504     }
505 }
506 
507 /***************************************************************************//**
508  * See mss_uart.h for details of how to use this function.
509  */
510 void
MSS_UART_set_rx_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler,mss_uart_rx_trig_level_t trigger_level)511 MSS_UART_set_rx_handler
512 (
513     mss_uart_instance_t *       this_uart,
514     mss_uart_irq_handler_t      handler,
515     mss_uart_rx_trig_level_t    trigger_level
516 )
517 {
518     ASSERT(handler != INVALID_IRQ_HANDLER );
519     ASSERT(trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL);
520 
521     if ((handler != INVALID_IRQ_HANDLER) &&
522        (trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL))
523     {
524         this_uart->rx_handler = handler;
525 
526         /* Set the receive interrupt trigger level. */
527         this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR &
528                                  (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) |
529                                  (uint8_t)trigger_level;
530 
531         /* Enable receive interrupt. */
532         this_uart->hw_reg->IER |= ERBFI_MASK;
533 
534         enable_irq(this_uart);
535     }
536 }
537 
538 /***************************************************************************//**
539  * See mss_uart.h for details of how to use this function.
540  */
541 void
MSS_UART_set_loopback(mss_uart_instance_t * this_uart,mss_uart_loopback_t loopback)542 MSS_UART_set_loopback
543 (
544     mss_uart_instance_t *   this_uart,
545     mss_uart_loopback_t     loopback
546 )
547 {
548     ASSERT(MSS_UART_INVALID_LOOPBACK > loopback);
549 
550     if (MSS_UART_INVALID_LOOPBACK > loopback)
551     {
552         switch (loopback)
553         {
554             case MSS_UART_LOCAL_LOOPBACK_OFF:
555                 /* Disable local loopback */
556                 this_uart->hw_reg->MCR &= ~LOOP_MASK;
557             break;
558 
559             case MSS_UART_LOCAL_LOOPBACK_ON:
560                 /* Enable local loopback */
561                 this_uart->hw_reg->MCR |= LOOP_MASK;
562             break;
563 
564             case MSS_UART_REMOTE_LOOPBACK_OFF:
565             case MSS_UART_AUTO_ECHO_OFF:
566                 /* Disable remote loopback & automatic echo */
567                 this_uart->hw_reg->MCR &= ~(RLOOP_MASK|ECHO_MASK);
568             break;
569 
570             case MSS_UART_REMOTE_LOOPBACK_ON:
571                 /* Enable remote loopback */
572                 this_uart->hw_reg->MCR |= (1u << RLOOP);
573                 break;
574 
575             case MSS_UART_AUTO_ECHO_ON:
576                 /* Enable automatic echo */
577                 this_uart->hw_reg->MCR |= (1u << ECHO);
578             break;
579 
580             case MSS_UART_INVALID_LOOPBACK:
581                 /* Fall through to default. */
582             default:
583                 ASSERT(0);
584             break;
585         }
586     }
587 }
588 
589 /***************************************************************************//**
590  * interrupt service routine.
591  */
mmuart0_plic_77_IRQHandler(void)592 uint8_t mmuart0_plic_77_IRQHandler(void)
593 {
594     if (g_uart_axi_pos & UART0_POSITION_MASK)
595     {
596         uart_isr(&g_mss_uart0_hi);
597     }
598     else
599     {
600         uart_isr(&g_mss_uart0_lo);
601     }
602 
603     return EXT_IRQ_KEEP_ENABLED;
604 }
605 
mmuart1_plic_IRQHandler(void)606 uint8_t mmuart1_plic_IRQHandler(void)
607 {
608     if (g_uart_axi_pos & UART1_POSITION_MASK)
609     {
610         uart_isr(&g_mss_uart1_hi);
611     }
612     else
613     {
614         uart_isr(&g_mss_uart1_lo);
615     }
616 
617     return EXT_IRQ_KEEP_ENABLED;
618 }
619 
mmuart2_plic_IRQHandler(void)620 uint8_t mmuart2_plic_IRQHandler(void)
621 {
622     if (g_uart_axi_pos & UART2_POSITION_MASK)
623     {
624         uart_isr(&g_mss_uart2_hi);
625     }
626     else
627     {
628         uart_isr(&g_mss_uart2_lo);
629     }
630 
631     return EXT_IRQ_KEEP_ENABLED;
632 }
633 
mmuart3_plic_IRQHandler(void)634 uint8_t mmuart3_plic_IRQHandler(void)
635 {
636     if (g_uart_axi_pos & UART3_POSITION_MASK)
637     {
638         uart_isr(&g_mss_uart3_hi);
639     }
640     else
641     {
642         uart_isr(&g_mss_uart3_lo);
643     }
644 
645     return EXT_IRQ_KEEP_ENABLED;
646 }
647 
mmuart4_plic_IRQHandler(void)648 uint8_t mmuart4_plic_IRQHandler(void)
649 {
650     if (g_uart_axi_pos & UART4_POSITION_MASK)
651     {
652         uart_isr(&g_mss_uart4_hi);
653     }
654     else
655     {
656         uart_isr(&g_mss_uart4_lo);
657     }
658 
659     return EXT_IRQ_KEEP_ENABLED;
660 }
661 
mmuart0_e51_local_IRQHandler_11(void)662 void mmuart0_e51_local_IRQHandler_11(void)
663 {
664     if (g_uart_axi_pos & UART0_POSITION_MASK)
665     {
666         uart_isr(&g_mss_uart0_hi);
667     }
668     else
669     {
670         uart_isr(&g_mss_uart0_lo);
671     }
672 }
673 
mmuart_u54_h1_local_IRQHandler_11(void)674 void mmuart_u54_h1_local_IRQHandler_11(void)
675 {
676     if (g_uart_axi_pos & UART1_POSITION_MASK)
677     {
678         uart_isr(&g_mss_uart1_hi);
679     }
680     else
681     {
682         uart_isr(&g_mss_uart1_lo);
683     }
684 }
685 
mmuart_u54_h2_local_IRQHandler_11(void)686 void mmuart_u54_h2_local_IRQHandler_11(void)
687 {
688     if (g_uart_axi_pos & UART2_POSITION_MASK)
689     {
690         uart_isr(&g_mss_uart2_hi);
691     }
692     else
693     {
694         uart_isr(&g_mss_uart2_lo);
695     }
696 }
697 
mmuart_u54_h3_local_IRQHandler_11(void)698 void mmuart_u54_h3_local_IRQHandler_11(void)
699 {
700     if (g_uart_axi_pos & UART3_POSITION_MASK)
701     {
702         uart_isr(&g_mss_uart3_hi);
703     }
704     else
705     {
706         uart_isr(&g_mss_uart3_lo);
707     }
708 }
709 
mmuart_u54_h4_local_IRQHandler_11(void)710 void mmuart_u54_h4_local_IRQHandler_11(void)
711 {
712     if (g_uart_axi_pos & UART4_POSITION_MASK)
713     {
714         uart_isr(&g_mss_uart4_hi);
715     }
716     else
717     {
718         uart_isr(&g_mss_uart4_lo);
719     }
720 }
721 
722 /***************************************************************************//**
723  * See mss_uart.h for details of how to use this function.
724  */
725 void
MSS_UART_set_rxstatus_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)726 MSS_UART_set_rxstatus_handler
727 (
728     mss_uart_instance_t * this_uart,
729     mss_uart_irq_handler_t handler
730 )
731 {
732     ASSERT(handler != INVALID_IRQ_HANDLER);
733 
734     if (handler != INVALID_IRQ_HANDLER)
735     {
736         this_uart->linests_handler = handler;
737 
738         /* Enable receiver line status interrupt. */
739         this_uart->hw_reg->IER |= ELSI_MASK;
740 
741         enable_irq(this_uart);
742     }
743 }
744 
745 /***************************************************************************//**
746  * See mss_uart.h for details of how to use this function.
747  */
748 void
MSS_UART_set_tx_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)749 MSS_UART_set_tx_handler
750 (
751     mss_uart_instance_t * this_uart,
752     mss_uart_irq_handler_t handler
753 )
754 {
755     ASSERT(handler != INVALID_IRQ_HANDLER);
756 
757     if (handler != INVALID_IRQ_HANDLER)
758     {
759         this_uart->tx_handler = handler;
760 
761         /* Make TX buffer info invalid */
762         this_uart->tx_buffer = (const uint8_t*)0;
763         this_uart->tx_buff_size = 0u;
764 
765         /* Enable transmitter holding register Empty interrupt. */
766         this_uart->hw_reg->IER |= ETBEI_MASK;
767         enable_irq(this_uart);
768     }
769 }
770 
771 /***************************************************************************//**
772  * See mss_uart.h for details of how to use this function.
773  */
774 void
MSS_UART_set_modemstatus_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)775 MSS_UART_set_modemstatus_handler
776 (
777     mss_uart_instance_t * this_uart,
778     mss_uart_irq_handler_t handler
779 )
780 {
781     ASSERT(handler != INVALID_IRQ_HANDLER);
782 
783     if (handler != INVALID_IRQ_HANDLER)
784     {
785         this_uart->modemsts_handler = handler;
786 
787         /* Enable modem status interrupt. */
788         this_uart->hw_reg->IER |= EDSSI_MASK;
789         enable_irq(this_uart);
790     }
791 }
792 
793 /***************************************************************************//**
794  * See mss_uart.h for details of how to use this function.
795  */
796 size_t
MSS_UART_fill_tx_fifo(mss_uart_instance_t * this_uart,const uint8_t * tx_buffer,size_t tx_size)797 MSS_UART_fill_tx_fifo
798 (
799     mss_uart_instance_t * this_uart,
800     const uint8_t * tx_buffer,
801     size_t tx_size
802 )
803 {
804     uint8_t status = 0u;
805     uint32_t size_sent = 0u;
806 
807     ASSERT(tx_buffer != ( (uint8_t*)0));
808     ASSERT(tx_size > 0);
809 
810     /* Fill the UART's Tx FIFO until the FIFO is full or the complete input
811      * buffer has been written. */
812     if ((tx_buffer != ((uint8_t*)0)) && (tx_size > 0u))
813     {
814         status = this_uart->hw_reg->LSR;
815         this_uart->status |= status;
816 
817         if (status & MSS_UART_THRE)
818         {
819             uint32_t fill_size = TX_FIFO_SIZE;
820 
821             if (tx_size < TX_FIFO_SIZE)
822             {
823                 fill_size = tx_size;
824             }
825 
826             /* Fill up FIFO */
827             for (size_sent = 0u; size_sent < fill_size; size_sent++)
828             {
829                 /* Send next character in the buffer. */
830                 this_uart->hw_reg->THR = tx_buffer[size_sent];
831             }
832         }
833     }
834 
835     return size_sent;
836 }
837 
838 /***************************************************************************//**
839  * See mss_uart.h for details of how to use this function.
840  */
841 uint8_t
MSS_UART_get_rx_status(mss_uart_instance_t * this_uart)842 MSS_UART_get_rx_status
843 (
844     mss_uart_instance_t * this_uart
845 )
846 {
847     uint8_t status = MSS_UART_INVALID_PARAM;
848 
849     /*
850      * Extract UART receive error status.
851      * Bit 1 - Overflow error status
852      * Bit 2 - Parity error status
853      * Bit 3 - Frame error status
854      * Bit 4 - Break interrupt indicator
855      * Bit 7 - FIFO data error status
856      */
857     this_uart->status |= (this_uart->hw_reg->LSR);
858     status = (this_uart->status & STATUS_ERROR_MASK);
859     /* Clear the sticky status after reading */
860     this_uart->status = 0u;
861 
862     return status;
863 }
864 
865 /***************************************************************************//**
866  * See mss_uart.h for details of how to use this function.
867  */
868 uint8_t
MSS_UART_get_modem_status(const mss_uart_instance_t * this_uart)869 MSS_UART_get_modem_status
870 (
871     const mss_uart_instance_t * this_uart
872 )
873 {
874     uint8_t status = MSS_UART_INVALID_PARAM;
875 
876     /*
877      * Extract UART modem status and place in lower bits of "status".
878      * Bit 0 - Delta Clear to Send Indicator
879      * Bit 1 - Delta Clear to Receive Indicator
880      * Bit 2 - Trailing edge of Ring Indicator detector
881      * Bit 3 - Delta Data Carrier Detect indicator
882      * Bit 4 - Clear To Send
883      * Bit 5 - Data Set Ready
884      * Bit 6 - Ring Indicator
885      * Bit 7 - Data Carrier Detect
886      */
887     status = this_uart->hw_reg->MSR;
888 
889     return status;
890 }
891 
892 /***************************************************************************//**
893  * MSS_UART_get_tx_status.
894  * See mss_uart.h for details of how to use this function.
895  */
896 uint8_t
MSS_UART_get_tx_status(mss_uart_instance_t * this_uart)897 MSS_UART_get_tx_status
898 (
899     mss_uart_instance_t * this_uart
900 )
901 {
902     uint8_t status = MSS_UART_TX_BUSY;
903 
904     /* Read the Line Status Register and update the sticky record. */
905     status = this_uart->hw_reg->LSR;
906     this_uart->status |= status;
907 
908     /*
909      * Extract the transmit status bits from the UART's Line Status Register.
910      * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status.
911                (If = 1, TX FIFO is empty)
912      * Bit 6 - Transmitter Empty (TEMT) status.
913                (If = 1, both TX FIFO and shift register are empty)
914      */
915     status &= (MSS_UART_THRE | MSS_UART_TEMT);
916 
917     return status;
918 }
919 
920 /***************************************************************************//**
921  * See mss_uart.h for details of how to use this function.
922  */
923 void
MSS_UART_set_break(mss_uart_instance_t * this_uart)924 MSS_UART_set_break
925 (
926     mss_uart_instance_t * this_uart
927 )
928 {
929     /* set break character on Tx line */
930     this_uart->hw_reg->LCR |= SB_MASK;
931 }
932 
933 /***************************************************************************//**
934  * See mss_uart.h for details of how to use this function.
935  */
936 void
MSS_UART_clear_break(mss_uart_instance_t * this_uart)937 MSS_UART_clear_break
938 (
939     mss_uart_instance_t * this_uart
940 )
941 {
942     /* remove break character from Tx line */
943     this_uart->hw_reg->LCR &= ~SB_MASK;
944 }
945 
946 /***************************************************************************//**
947  * See mss_uart.h for details of how to use this function.
948  */
949 void
MSS_UART_set_pidpei_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)950 MSS_UART_set_pidpei_handler
951 (
952     mss_uart_instance_t * this_uart,
953     mss_uart_irq_handler_t handler
954 )
955 {
956     ASSERT(handler != INVALID_IRQ_HANDLER);
957 
958     if (handler != INVALID_IRQ_HANDLER)
959     {
960         this_uart->pid_pei_handler = handler;
961 
962         /* Enable PID parity error interrupt. */
963         this_uart->hw_reg->IEM |= EPID_PEI_MASK;
964         enable_irq(this_uart);
965     }
966 }
967 
968 /***************************************************************************//**
969  * See mss_uart.h for details of how to use this function.
970  */
971 void
MSS_UART_set_linbreak_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)972 MSS_UART_set_linbreak_handler
973 (
974     mss_uart_instance_t * this_uart,
975     mss_uart_irq_handler_t handler
976 )
977 {
978     ASSERT(handler != INVALID_IRQ_HANDLER);
979 
980     if (handler != INVALID_IRQ_HANDLER)
981     {
982         this_uart->break_handler = handler;
983 
984         /* Enable LIN break detection interrupt. */
985         this_uart->hw_reg->IEM |= ELINBI_MASK;
986         enable_irq(this_uart);
987     }
988 }
989 
990 /***************************************************************************//**
991  * See mss_uart.h for details of how to use this function.
992  */
993 void
MSS_UART_set_linsync_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)994 MSS_UART_set_linsync_handler
995 (
996     mss_uart_instance_t * this_uart,
997     mss_uart_irq_handler_t handler
998 )
999 {
1000     ASSERT(handler != INVALID_IRQ_HANDLER);
1001 
1002     if (handler != INVALID_IRQ_HANDLER)
1003     {
1004         this_uart->sync_handler = handler;
1005 
1006         /* Enable LIN sync detection interrupt. */
1007         this_uart->hw_reg->IEM |= ELINSI_MASK;
1008         enable_irq(this_uart);
1009     }
1010 }
1011 
1012 /***************************************************************************//**
1013  * See mss_uart.h for details of how to use this function.
1014  */
1015 void
MSS_UART_set_nack_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)1016 MSS_UART_set_nack_handler
1017 (
1018     mss_uart_instance_t * this_uart,
1019     mss_uart_irq_handler_t handler
1020 )
1021 {
1022     ASSERT(handler != INVALID_IRQ_HANDLER);
1023 
1024     if (handler != INVALID_IRQ_HANDLER)
1025     {
1026         this_uart->nack_handler = handler;
1027 
1028         /* Enable LIN sync detection interrupt. */
1029         this_uart->hw_reg->IEM |= ENACKI_MASK;
1030         enable_irq(this_uart);
1031     }
1032 }
1033 
1034 /***************************************************************************//**
1035  * See mss_uart.h for details of how to use this function.
1036  */
1037 void
MSS_UART_set_rx_timeout_handler(mss_uart_instance_t * this_uart,mss_uart_irq_handler_t handler)1038 MSS_UART_set_rx_timeout_handler
1039 (
1040     mss_uart_instance_t * this_uart,
1041     mss_uart_irq_handler_t handler
1042 )
1043 {
1044     ASSERT(handler != INVALID_IRQ_HANDLER);
1045 
1046     if (handler != INVALID_IRQ_HANDLER)
1047     {
1048         this_uart->rto_handler = handler;
1049 
1050         /* Enable receiver timeout interrupt. */
1051         this_uart->hw_reg->IEM |= ERTOI_MASK;
1052         enable_irq(this_uart);
1053     }
1054 }
1055 
1056 /***************************************************************************//**
1057  * See mss_uart.h for details of how to use this function.
1058  */
1059 void
MSS_UART_enable_half_duplex(mss_uart_instance_t * this_uart)1060 MSS_UART_enable_half_duplex
1061 (
1062     mss_uart_instance_t * this_uart
1063 )
1064 {
1065     /* enable single wire half-duplex mode */
1066     this_uart->hw_reg->MM2 |= ESWM_MASK;
1067 }
1068 
1069 /***************************************************************************//**
1070  * See mss_uart.h for details of how to use this function.
1071  */
1072 void
MSS_UART_disable_half_duplex(mss_uart_instance_t * this_uart)1073 MSS_UART_disable_half_duplex
1074 (
1075     mss_uart_instance_t * this_uart
1076 )
1077 {
1078     /* enable single wire half-duplex mode */
1079     this_uart->hw_reg->MM2 &= ~ESWM_MASK;
1080 }
1081 
1082 /***************************************************************************//**
1083  * See mss_uart.h for details of how to use this function.
1084  */
1085 void
MSS_UART_set_rx_endian(mss_uart_instance_t * this_uart,mss_uart_endian_t endian)1086 MSS_UART_set_rx_endian
1087 (
1088     mss_uart_instance_t * this_uart,
1089     mss_uart_endian_t endian
1090 )
1091 {
1092     ASSERT(MSS_UART_INVALID_ENDIAN > endian);
1093 
1094     if (MSS_UART_INVALID_ENDIAN > endian)
1095     {
1096         /* Configure MSB first / LSB first for receiver */
1097         ((MSS_UART_LITTLEEND == endian) ? (this_uart->hw_reg->MM1 &= ~E_MSB_RX_MASK) :
1098                                      (this_uart->hw_reg->MM1 |= E_MSB_RX_MASK));
1099     }
1100 }
1101 
1102 /***************************************************************************//**
1103  * See mss_uart.h for details of how to use this function.
1104  */
1105 void
MSS_UART_set_tx_endian(mss_uart_instance_t * this_uart,mss_uart_endian_t endian)1106 MSS_UART_set_tx_endian
1107 (
1108     mss_uart_instance_t * this_uart,
1109     mss_uart_endian_t endian
1110 )
1111 {
1112     ASSERT(MSS_UART_INVALID_ENDIAN > endian);
1113 
1114     if (MSS_UART_INVALID_ENDIAN > endian)
1115     {
1116         /* Configure MSB first / LSB first for transmitter */
1117         ((MSS_UART_LITTLEEND == endian) ? (this_uart->hw_reg->MM1 &= ~E_MSB_TX_MASK) :
1118                                     (this_uart->hw_reg->MM1 |= E_MSB_TX_MASK));
1119     }
1120 }
1121 
1122 /***************************************************************************//**
1123  * See mss_uart.h for details of how to use this function.
1124  */
1125 void
MSS_UART_set_filter_length(mss_uart_instance_t * this_uart,mss_uart_filter_length_t length)1126 MSS_UART_set_filter_length
1127 (
1128     mss_uart_instance_t * this_uart,
1129     mss_uart_filter_length_t length
1130 )
1131 {
1132     ASSERT(MSS_UART_INVALID_FILTER_LENGTH > length);
1133 
1134     if (MSS_UART_INVALID_FILTER_LENGTH > length)
1135     {
1136         /* Configure glitch filter length */
1137         this_uart->hw_reg->GFR = (uint8_t)length;
1138     }
1139 }
1140 
1141 /***************************************************************************//**
1142  * See mss_uart.h for details of how to use this function.
1143  */
1144 void
MSS_UART_enable_afm(mss_uart_instance_t * this_uart)1145 MSS_UART_enable_afm
1146 (
1147      mss_uart_instance_t * this_uart
1148 )
1149 {
1150     /* Disable RX FIFO till address flag with correct address is received */
1151     this_uart->hw_reg->MM2 |= EAFM_MASK;
1152 }
1153 
1154 /***************************************************************************//**
1155  * See mss_uart.h for details of how to use this function.
1156  */
1157 void
MSS_UART_disable_afm(mss_uart_instance_t * this_uart)1158 MSS_UART_disable_afm
1159 (
1160      mss_uart_instance_t * this_uart
1161 )
1162 {
1163     /* Enable RX FIFO irrespective of address flag and
1164        correct address is received */
1165     this_uart->hw_reg->MM2 &= ~EAFM_MASK;
1166 }
1167 
1168 /***************************************************************************//**
1169  * See mss_uart.h for details of how to use this function.
1170  */
1171 void
MSS_UART_enable_afclear(mss_uart_instance_t * this_uart)1172 MSS_UART_enable_afclear
1173 (
1174      mss_uart_instance_t * this_uart
1175 )
1176 {
1177     /* Enable address flag clearing */
1178     /* Disable RX FIFO till another address flag with
1179        correct address is received */
1180     this_uart->hw_reg->MM2 |= EAFC_MASK;
1181 }
1182 
1183 /***************************************************************************//**
1184  * See mss_uart.h for details of how to use this function.
1185  */
1186 void
MSS_UART_disable_afclear(mss_uart_instance_t * this_uart)1187 MSS_UART_disable_afclear
1188 (
1189      mss_uart_instance_t * this_uart
1190 )
1191 {
1192     /* Disable address flag clearing */
1193     this_uart->hw_reg->MM2 &= ~EAFC_MASK;
1194 }
1195 
1196 /***************************************************************************//**
1197  * See mss_uart.h for details of how to use this function.
1198  */
1199 void
MSS_UART_enable_rx_timeout(mss_uart_instance_t * this_uart,uint8_t timeout)1200 MSS_UART_enable_rx_timeout
1201 (
1202     mss_uart_instance_t * this_uart,
1203     uint8_t timeout
1204 )
1205 {
1206     /* Load the receive timeout value */
1207     this_uart->hw_reg->RTO = timeout;
1208 
1209     /*Enable receiver time-out */
1210     this_uart->hw_reg->MM0 |= ERTO_MASK;
1211 }
1212 
1213 /***************************************************************************//**
1214  * See mss_uart.h for details of how to use this function.
1215  */
1216 void
MSS_UART_disable_rx_timeout(mss_uart_instance_t * this_uart)1217 MSS_UART_disable_rx_timeout
1218 (
1219     mss_uart_instance_t * this_uart
1220 )
1221 {
1222     /* Disable receiver time-out */
1223     this_uart->hw_reg->MM0 &= ~ERTO_MASK;
1224 }
1225 
1226 /***************************************************************************//**
1227  * See mss_uart.h for details of how to use this function.
1228  */
1229 void
MSS_UART_enable_tx_time_guard(mss_uart_instance_t * this_uart,uint8_t timeguard)1230 MSS_UART_enable_tx_time_guard
1231 (
1232     mss_uart_instance_t * this_uart,
1233     uint8_t timeguard
1234 )
1235 {
1236     /* Load the transmitter time guard value */
1237     this_uart->hw_reg->TTG = timeguard;
1238 
1239     /* Enable transmitter time guard */
1240     this_uart->hw_reg->MM0 |= ETTG_MASK;
1241 }
1242 
1243 /***************************************************************************//**
1244  * See mss_uart.h for details of how to use this function.
1245  */
1246 void
MSS_UART_disable_tx_time_guard(mss_uart_instance_t * this_uart)1247 MSS_UART_disable_tx_time_guard
1248 (
1249     mss_uart_instance_t * this_uart
1250 )
1251 {
1252     /* Disable transmitter time guard */
1253     this_uart->hw_reg->MM0 &= ~ETTG_MASK;
1254 }
1255 
1256 /***************************************************************************//**
1257  * See mss_uart.h for details of how to use this function.
1258  */
1259 void
MSS_UART_set_address(mss_uart_instance_t * this_uart,uint8_t address)1260 MSS_UART_set_address
1261 (
1262     mss_uart_instance_t * this_uart,
1263     uint8_t address
1264 )
1265 {
1266     this_uart->hw_reg->ADR = address;
1267 }
1268 
1269 /***************************************************************************//**
1270  * See mss_uart.h for details of how to use this function.
1271  */
1272 void
MSS_UART_set_ready_mode(mss_uart_instance_t * this_uart,mss_uart_ready_mode_t mode)1273 MSS_UART_set_ready_mode
1274 (
1275     mss_uart_instance_t * this_uart,
1276     mss_uart_ready_mode_t mode
1277 )
1278 {
1279     ASSERT(MSS_UART_INVALID_READY_MODE > mode);
1280 
1281     if (MSS_UART_INVALID_READY_MODE > mode )
1282     {
1283         /* Configure mode 0 or mode 1 for TXRDY and RXRDY */
1284         ((MSS_UART_READY_MODE0 == mode) ? (this_uart->hw_reg->FCR &= ~RDYMODE_MASK) :
1285                                      (this_uart->hw_reg->FCR |= RDYMODE_MASK) );
1286     }
1287 }
1288 
1289 /***************************************************************************//**
1290  * See mss_uart.h for details of how to use this function.
1291  */
1292 void
MSS_UART_set_usart_mode(mss_uart_instance_t * this_uart,mss_uart_usart_mode_t mode)1293 MSS_UART_set_usart_mode
1294 (
1295     mss_uart_instance_t * this_uart,
1296     mss_uart_usart_mode_t mode
1297 )
1298 {
1299     ASSERT(MSS_UART_INVALID_SYNC_MODE > mode);
1300 
1301     if (MSS_UART_INVALID_SYNC_MODE > mode)
1302     {
1303         /* Nothing to do for the baudrate:
1304                                 operates at PCLK / 2 + glitch filter length */
1305         /* Clear the ESYN bits 2:0 */
1306         this_uart->hw_reg->MM0 &= ~SYNC_ASYNC_MODE_MASK;
1307         this_uart->hw_reg->MM0 |= (uint8_t)mode;
1308     }
1309 }
1310 
1311 /***************************************************************************//**
1312  * See mss_uart.h for details of how to use this function.
1313  */
1314 void
MSS_UART_enable_local_irq(mss_uart_instance_t * this_uart)1315 MSS_UART_enable_local_irq
1316 (
1317     mss_uart_instance_t * this_uart
1318 )
1319 {
1320     /* Make sure to disable interrupt on PLIC as it might have been enabled
1321      * when application registered an interrupt handler function or
1322      * used MSS_UART_enable_irq() to enable PLIC interrupt */
1323     disable_irq(this_uart);
1324 
1325     this_uart->local_irq_enabled = 1u;
1326 
1327     /* Enable local interrupt UART instance.
1328      * Local interrupt will be enabled on the HART on which the application
1329      * calling this API is being executed*/
1330     __enable_local_irq((int8_t)MMUART0_E51_INT);
1331 }
1332 
1333 /*******************************************************************************
1334  * Local Functions
1335  ******************************************************************************/
1336 /*******************************************************************************
1337  * Global initialization for all modes
1338  */
global_init(mss_uart_instance_t * this_uart,uint32_t baud_rate,uint8_t line_config)1339 static void global_init
1340 (
1341     mss_uart_instance_t * this_uart,
1342     uint32_t baud_rate,
1343     uint8_t line_config
1344 )
1345 {
1346     if ((&g_mss_uart0_lo == this_uart))
1347     {
1348         this_uart->hw_reg = MSS_UART0_LO_BASE;
1349         g_uart_axi_pos &= ~0x01u;
1350     }
1351 
1352     else if (&g_mss_uart1_lo == this_uart)
1353     {
1354 
1355         this_uart->hw_reg = MSS_UART1_LO_BASE;
1356         g_uart_axi_pos &= ~0x02u;
1357     }
1358 
1359     else if (&g_mss_uart2_lo == this_uart)
1360     {
1361         this_uart->hw_reg = MSS_UART2_LO_BASE;
1362         g_uart_axi_pos &= ~0x04u;
1363     }
1364 
1365     else if (&g_mss_uart3_lo == this_uart)
1366     {
1367         this_uart->hw_reg = MSS_UART3_LO_BASE;
1368         g_uart_axi_pos &= ~0x08u;
1369     }
1370 
1371     else if (&g_mss_uart4_lo == this_uart)
1372     {
1373         this_uart->hw_reg = MSS_UART4_LO_BASE;
1374         g_uart_axi_pos &= ~0x10u;
1375     }
1376 
1377     else if ((&g_mss_uart0_hi == this_uart))
1378     {
1379         this_uart->hw_reg = MSS_UART0_HI_BASE;
1380         g_uart_axi_pos |= 0x01u;
1381     }
1382 
1383     else if (&g_mss_uart1_hi == this_uart)
1384     {
1385         this_uart->hw_reg = MSS_UART1_HI_BASE;
1386         g_uart_axi_pos |= 0x02u;
1387     }
1388 
1389     else if (&g_mss_uart2_hi == this_uart)
1390     {
1391         this_uart->hw_reg = MSS_UART2_HI_BASE;
1392         g_uart_axi_pos |= 0x04u;
1393     }
1394 
1395     else if (&g_mss_uart3_hi == this_uart)
1396     {
1397         this_uart->hw_reg = MSS_UART3_HI_BASE;
1398         g_uart_axi_pos |= 0x08u;
1399     }
1400 
1401     else if (&g_mss_uart4_hi == this_uart)
1402     {
1403         this_uart->hw_reg = MSS_UART4_HI_BASE;
1404         g_uart_axi_pos |= 0x10u;
1405     }
1406     else
1407     {
1408         ASSERT(0); /* Comment to avoid LDRA warning */
1409     }
1410 
1411     /* disable interrupts */
1412     this_uart->hw_reg->IER = 0u;
1413 
1414     /* FIFO configuration */
1415     this_uart->hw_reg->FCR = 0u;
1416 
1417     /* clear receiver FIFO */
1418     this_uart->hw_reg->FCR |= CLEAR_RX_FIFO_MASK;
1419 
1420     /* clear transmitter FIFO */
1421     this_uart->hw_reg->FCR |= CLEAR_TX_FIFO_MASK;
1422 
1423     /* set default READY mode : Mode 0*/
1424     /* enable RXRDYN and TXRDYN pins. The earlier FCR write to set the TX FIFO
1425      * trigger level inadvertently disabled the FCR_RXRDY_TXRDYN_EN bit. */
1426     this_uart->hw_reg->FCR |= RXRDY_TXRDYN_EN_MASK;
1427 
1428     /* disable loopback : local * remote */
1429     this_uart->hw_reg->MCR &= ~LOOP_MASK;
1430 
1431     this_uart->hw_reg->MCR &= ~RLOOP_MASK;
1432 
1433     /* set default TX endian */
1434     this_uart->hw_reg->MM1 &= ~E_MSB_TX_MASK;
1435 
1436     /* set default RX endian */
1437     this_uart->hw_reg->MM1 &= ~E_MSB_RX_MASK;
1438 
1439     /* default AFM : disabled */
1440     this_uart->hw_reg->MM2 &= ~EAFM_MASK;
1441 
1442     /* disable TX time guard */
1443     this_uart->hw_reg->MM0 &= ~ETTG_MASK;
1444 
1445     /* set default RX timeout */
1446     this_uart->hw_reg->MM0 &= ~ERTO_MASK;
1447 
1448     /* disable fractional baud-rate */
1449     this_uart->hw_reg->MM0 &= ~EFBR_MASK;
1450 
1451     /* disable single wire mode */
1452     this_uart->hw_reg->MM2 &= ~ESWM_MASK;
1453 
1454     /* set filter to minimum value */
1455     this_uart->hw_reg->GFR = 0u;
1456 
1457     /* set default TX time guard */
1458     this_uart->hw_reg->TTG = 0u;
1459 
1460     /* set default RX timeout */
1461     this_uart->hw_reg->RTO = 0u;
1462 
1463     /*
1464      * Configure baud rate divisors. This uses the fractional baud rate divisor
1465      * where possible to provide the most accurate baud rat possible.
1466      */
1467     config_baud_divisors(this_uart, baud_rate);
1468 
1469     /* set the line control register (bit length, stop bits, parity) */
1470     this_uart->hw_reg->LCR = line_config;
1471 
1472     /* Instance setup */
1473     this_uart->baudrate = baud_rate;
1474     this_uart->lineconfig = line_config;
1475     this_uart->tx_buff_size = TX_COMPLETE;
1476     this_uart->tx_buffer = (const uint8_t*)0;
1477     this_uart->tx_idx = 0u;
1478 
1479     /* Default handlers for MSS UART interrupts */
1480     this_uart->rx_handler       = NULL_HANDLER;
1481     this_uart->tx_handler       = NULL_HANDLER;
1482     this_uart->linests_handler  = NULL_HANDLER;
1483     this_uart->modemsts_handler = NULL_HANDLER;
1484     this_uart->rto_handler      = NULL_HANDLER;
1485     this_uart->nack_handler     = NULL_HANDLER;
1486     this_uart->pid_pei_handler  = NULL_HANDLER;
1487     this_uart->break_handler    = NULL_HANDLER;
1488     this_uart->sync_handler     = NULL_HANDLER;
1489 
1490     this_uart->local_irq_enabled = 0u;
1491 
1492     /* Initialize the sticky status */
1493     this_uart->status = 0u;
1494 }
1495 
1496 /***************************************************************************//**
1497  * Configure baud divisors using fractional baud rate if possible.
1498  */
1499 static void
config_baud_divisors(mss_uart_instance_t * this_uart,uint32_t baudrate)1500 config_baud_divisors
1501 (
1502     mss_uart_instance_t * this_uart,
1503     uint32_t baudrate
1504 )
1505 {
1506     uint32_t baud_value;
1507     uint32_t baud_value_by_64;
1508     uint32_t baud_value_by_128;
1509     uint32_t fractional_baud_value;
1510     uint64_t pclk_freq;
1511 
1512     this_uart->baudrate = baudrate;
1513 
1514     pclk_freq = LIBERO_SETTING_MSS_APB_AHB_CLK;
1515 
1516     /*
1517      * Compute baud value based on requested baud rate and PCLK frequency.
1518      * The baud value is computed using the following equation:
1519      *      baud_value = PCLK_Frequency / (baud_rate * 16)
1520      */
1521     baud_value_by_128 = (uint32_t)((8UL * pclk_freq) / baudrate);
1522     baud_value_by_64 = baud_value_by_128 / 2u;
1523     baud_value = baud_value_by_64 / 64u;
1524     fractional_baud_value = baud_value_by_64 - (baud_value * 64u);
1525     fractional_baud_value += (baud_value_by_128 - (baud_value * 128u))
1526                              - (fractional_baud_value * 2u);
1527 
1528     /* Assert if integer baud value fits in 16-bit. */
1529     ASSERT(baud_value <= UINT16_MAX);
1530 
1531     if (baud_value <= (uint32_t)UINT16_MAX)
1532     {
1533         if (baud_value > 1u)
1534         {
1535             /* Use Fractional baud rate divisors */
1536             /* set divisor latch */
1537             this_uart->hw_reg->LCR |= DLAB_MASK;
1538 
1539             /* MSB of baud value */
1540             this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8);
1541 
1542             /* LSB of baud value */
1543             this_uart->hw_reg->DLR = (uint8_t)baud_value;
1544 
1545             /* reset divisor latch */
1546             this_uart->hw_reg->LCR &= ~DLAB_MASK;
1547 
1548             /* Enable Fractional baud rate */
1549             this_uart->hw_reg->MM0 |= EFBR_MASK;
1550 
1551             /* Load the fractional baud rate register */
1552             ASSERT(fractional_baud_value <= (uint32_t)UINT8_MAX);
1553             this_uart->hw_reg->DFR = (uint8_t)fractional_baud_value;
1554         }
1555         else
1556         {
1557             /* Do NOT use Fractional baud rate divisors. */
1558             /* set divisor latch */
1559             this_uart->hw_reg->LCR |= DLAB_MASK;
1560 
1561             /* MSB of baud value */
1562             this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8u);
1563 
1564             /* LSB of baud value */
1565             this_uart->hw_reg->DLR = (uint8_t)baud_value;
1566 
1567             /* reset divisor latch */
1568             this_uart->hw_reg->LCR &= ~DLAB_MASK;
1569 
1570             /* Disable Fractional baud rate */
1571             this_uart->hw_reg->MM0 &= ~EFBR_MASK;
1572         }
1573     }
1574 }
1575 
1576 /***************************************************************************//**
1577  * Interrupt service routine triggered by any MSS UART interrupt. This routine
1578  * will call the handler function appropriate to the interrupt from the
1579  * handlers previously registered with the driver through calls to the
1580  * MSS_UART_set_*_handler() functions, or it will call the default_tx_handler()
1581  * function in response to transmit interrupts if MSS_UART_irq_tx() is used to
1582  * transmit data.
1583  */
1584 static void
uart_isr(mss_uart_instance_t * this_uart)1585 uart_isr
1586 (
1587     mss_uart_instance_t * this_uart
1588 )
1589 {
1590     uint8_t iirf;
1591 
1592     iirf = this_uart->hw_reg->IIR & IIRF_MASK;
1593 
1594     switch (iirf)
1595     {
1596         case IIRF_MODEM_STATUS:  /* Modem status interrupt */
1597         {
1598             ASSERT(NULL_HANDLER != this_uart->modemsts_handler);
1599             if (NULL_HANDLER != this_uart->modemsts_handler)
1600             {
1601                (*(this_uart->modemsts_handler))(this_uart);
1602             }
1603         }
1604         break;
1605 
1606         case IIRF_THRE: /* Transmitter Holding Register Empty */
1607         {
1608             ASSERT(NULL_HANDLER != this_uart->tx_handler);
1609             if (NULL_HANDLER != this_uart->tx_handler)
1610             {
1611                 (*(this_uart->tx_handler))(this_uart);
1612             }
1613         }
1614         break;
1615 
1616         case IIRF_RX_DATA:      /* Received Data Available */
1617         case IIRF_DATA_TIMEOUT: /* Received Data Timed-out */
1618         {
1619             ASSERT(NULL_HANDLER != this_uart->rx_handler);
1620             if (NULL_HANDLER != this_uart->rx_handler)
1621             {
1622                 (*(this_uart->rx_handler))(this_uart);
1623             }
1624         }
1625         break;
1626 
1627         case IIRF_RX_LINE_STATUS:  /* Line Status Interrupt */
1628         {
1629             ASSERT(NULL_HANDLER != this_uart->linests_handler);
1630             if (NULL_HANDLER != this_uart->linests_handler)
1631             {
1632                (*(this_uart->linests_handler))(this_uart);
1633             }
1634         }
1635         break;
1636 
1637         case IIRF_MMI:
1638         {
1639             /* Identify multi-mode interrupts and handle */
1640 
1641             /* Receiver time-out interrupt */
1642             if (this_uart->hw_reg->IIM & ERTOI_MASK)
1643             {
1644                 ASSERT(NULL_HANDLER != this_uart->rto_handler);
1645 
1646                 if (NULL_HANDLER != this_uart->rto_handler)
1647                 {
1648                     (*(this_uart->rto_handler))(this_uart);
1649                 }
1650             }
1651 
1652             /* NACK interrupt */
1653             if (this_uart->hw_reg->IIM &ENACKI)
1654             {
1655                 ASSERT(NULL_HANDLER != this_uart->nack_handler);
1656 
1657                 if (NULL_HANDLER != this_uart->nack_handler)
1658                 {
1659                     (*(this_uart->nack_handler))(this_uart);
1660                 }
1661             }
1662 
1663             /* PID parity error interrupt */
1664             if (this_uart->hw_reg->IIM & EPID_PEI)
1665             {
1666                 ASSERT(NULL_HANDLER != this_uart->pid_pei_handler);
1667 
1668                 if (NULL_HANDLER != this_uart->pid_pei_handler)
1669                 {
1670                     (*(this_uart->pid_pei_handler))(this_uart);
1671                 }
1672             }
1673 
1674             /* LIN break detection interrupt */
1675             if (this_uart->hw_reg->IIM & ELINBI)
1676             {
1677                 ASSERT(NULL_HANDLER != this_uart->break_handler);
1678 
1679                 if (NULL_HANDLER != this_uart->break_handler)
1680                 {
1681                     (*(this_uart->break_handler))(this_uart);
1682                 }
1683             }
1684 
1685             /* LIN Sync detection interrupt */
1686             if (this_uart->hw_reg->IIM & ELINSI)
1687             {
1688                 ASSERT(NULL_HANDLER != this_uart->sync_handler);
1689 
1690                 if (NULL_HANDLER != this_uart->sync_handler)
1691                 {
1692                     (*(this_uart->sync_handler))(this_uart);
1693                 }
1694             }
1695             break;
1696         }
1697         default:
1698         {
1699             ASSERT(INVALID_INTERRUPT); /* Comment to avoid LDRA warning */
1700         }
1701         break;
1702     }
1703 }
1704 
1705 /***************************************************************************//**
1706  * See mss_uart.h for details of how to use this function.
1707  */
1708 static void
default_tx_handler(mss_uart_instance_t * this_uart)1709 default_tx_handler
1710 (
1711     mss_uart_instance_t * this_uart
1712 )
1713 {
1714     uint8_t status;
1715 
1716     ASSERT(( (uint8_t*)0 ) != this_uart->tx_buffer);
1717     ASSERT(0u < this_uart->tx_buff_size);
1718 
1719     if ((((uint8_t*)0 ) != this_uart->tx_buffer) &&
1720        (0u < this_uart->tx_buff_size))
1721     {
1722         /* Read the Line Status Register and update the sticky record. */
1723         status = this_uart->hw_reg->LSR;
1724         this_uart->status |= status;
1725 
1726         /*
1727          * This function should only be called as a result of a THRE interrupt.
1728          * Verify that this is true before proceeding to transmit data.
1729          */
1730         if (status & MSS_UART_THRE)
1731         {
1732             uint32_t cnt;
1733             uint32_t fill_size = TX_FIFO_SIZE;
1734             uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx;
1735 
1736             /* Calculate the number of bytes to transmit. */
1737             if (tx_remain < TX_FIFO_SIZE)
1738             {
1739                 fill_size = tx_remain;
1740             }
1741 
1742             /* Fill the TX FIFO with the calculated the number of bytes. */
1743             for (cnt = 0u; cnt < fill_size; ++cnt)
1744             {
1745                 /* Send next character in the buffer. */
1746                 this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
1747                 ++this_uart->tx_idx;
1748             }
1749         }
1750 
1751         /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */
1752         if (this_uart->tx_idx == this_uart->tx_buff_size)
1753         {
1754             this_uart->tx_buff_size = TX_COMPLETE;
1755 
1756             /* disables TX interrupt */
1757             this_uart->hw_reg->IER &= ~ETBEI_MASK;
1758         }
1759     }
1760 }
1761 
1762 static void
enable_irq(const mss_uart_instance_t * this_uart)1763 enable_irq
1764 (
1765     const mss_uart_instance_t * this_uart
1766 )
1767 {
1768     PLIC_IRQn_Type plic_num = 0;
1769 
1770     if(0u == this_uart->local_irq_enabled)
1771     {
1772         if (((&g_mss_uart0_lo == this_uart)) || ((&g_mss_uart0_hi == this_uart)))
1773         {
1774             plic_num = MMUART0_PLIC_77;
1775         }
1776         else if (((&g_mss_uart1_lo == this_uart)) || ((&g_mss_uart1_hi == this_uart)))
1777         {
1778             plic_num = MMUART1_PLIC;
1779         }
1780         else if (((&g_mss_uart2_lo == this_uart)) || ((&g_mss_uart2_hi == this_uart)))
1781         {
1782             plic_num = MMUART2_PLIC;
1783         }
1784         else if (((&g_mss_uart3_lo == this_uart)) || ((&g_mss_uart3_hi == this_uart)))
1785         {
1786             plic_num = MMUART3_PLIC;
1787         }
1788         else if (((&g_mss_uart4_lo == this_uart)) || ((&g_mss_uart4_hi == this_uart)))
1789         {
1790             plic_num = MMUART4_PLIC;
1791         }
1792         else
1793         {
1794             ASSERT(0); /* Comment to avoid LDRA warning */
1795         }
1796 
1797         /* Enable UART instance interrupt in PLIC. */
1798         PLIC_EnableIRQ(plic_num);
1799     }
1800 }
1801 
1802 static void
disable_irq(const mss_uart_instance_t * this_uart)1803 disable_irq
1804 (
1805     const mss_uart_instance_t * this_uart
1806 )
1807 {
1808     PLIC_IRQn_Type plic_num = 0;
1809 
1810     if (((&g_mss_uart0_lo == this_uart)) || ((&g_mss_uart0_hi == this_uart)))
1811     {
1812         plic_num = MMUART0_PLIC_77;
1813     }
1814     else if (((&g_mss_uart1_lo == this_uart)) || ((&g_mss_uart1_hi == this_uart)))
1815     {
1816         plic_num = MMUART1_PLIC;
1817     }
1818     else if (((&g_mss_uart2_lo == this_uart)) || ((&g_mss_uart2_hi == this_uart)))
1819     {
1820         plic_num = MMUART2_PLIC;
1821     }
1822     else if (((&g_mss_uart3_lo == this_uart)) || ((&g_mss_uart3_hi == this_uart)))
1823     {
1824         plic_num = MMUART3_PLIC;
1825     }
1826     else if (((&g_mss_uart4_lo == this_uart)) || ((&g_mss_uart4_hi == this_uart)))
1827     {
1828         plic_num = MMUART4_PLIC;
1829     }
1830     else
1831     {
1832         ASSERT(0); /* Comment to avoid LDRA warning */
1833     }
1834 
1835     /* Disable UART instance interrupt in PLIC. */
1836     PLIC_DisableIRQ(plic_num);
1837 }
1838 
1839 #ifdef __cplusplus
1840 }
1841 #endif
1842