Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:42

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMCycVContrib
0005  */
0006 
0007 /******************************************************************************
0008  *
0009  * Copyright 2013 Altera Corporation. All Rights Reserved.
0010  * 
0011  * Redistribution and use in source and binary forms, with or without
0012  * modification, are permitted provided that the following conditions are met:
0013  * 
0014  * 1. Redistributions of source code must retain the above copyright notice,
0015  * this list of conditions and the following disclaimer.
0016  * 
0017  * 2. Redistributions in binary form must reproduce the above copyright notice,
0018  * this list of conditions and the following disclaimer in the documentation
0019  * and/or other materials provided with the distribution.
0020  * 
0021  * 3. The name of the author may not be used to endorse or promote products
0022  * derived from this software without specific prior written permission.
0023  * 
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
0025  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
0027  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0028  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0029  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0030  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0031  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0032  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
0033  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0034  * 
0035  ******************************************************************************/
0036 
0037 #include <bsp/alt_16550_uart.h>
0038 #include <bsp/alt_clock_manager.h>
0039 #include <bsp/socal/alt_rstmgr.h>
0040 #include <bsp/socal/alt_uart.h>
0041 #include <bsp/socal/hps.h>
0042 #include <bsp/socal/socal.h>
0043 
0044 /////
0045 
0046 #define ALT_16550_HANDLE_DATA_UART_ENABLED_MSK   (1UL << 31)
0047 #define ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(value) (value & 0xffff)
0048 
0049 #define ALT_ALTERA_16550_CPR_OFST        (0xF4)
0050 #define ALT_ALTERA_16550_CPR_ADDR(base)  ALT_CAST(void *, (ALT_CAST(char *, (base)) + ALT_ALTERA_16550_CPR_OFST))
0051 #define ALT_ALTERA_16550_CPR_FIFO_MODE_GET(value) (((value) >> 16) & 0xff)
0052 #define ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK (1 << 4)
0053 
0054 /////
0055 
0056 // Remove these macros as part of case:123835.
0057 #define ALT_UART_IER_DLH_VALUE_SET(value) ((value) & 0xff)
0058 #define ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK ALT_UART_IER_DLH_ETBEI_DLHL_SET_MSK
0059 
0060 /////
0061 
0062 //
0063 // Helper function which resets the UART and if requested, initializes the UART
0064 // to the default settings. Currently the default settings are:
0065 //  - 8 databits
0066 //  - no parity
0067 //  - 1 stopbit
0068 //  - 57600 baudrate
0069 // The reset routines depends on the hardware implementation of the UART.
0070 //
0071 
0072 // This helper is needed because the regular alt_read_word(src) essentially
0073 // resolves to "*(volatile uint32_t *)src". As there is no assignment, this
0074 // could potentially be optimized away. With the helper, the actual register
0075 // read should occur and be returned (and subsequently discarded).
0076 static inline uint32_t alt_read_word_helper(const void * addr)
0077 {
0078     return alt_read_word(addr);
0079 }
0080 
0081 //
0082 // Helper function write the divisor in hardware.
0083 //
0084 static ALT_STATUS_CODE alt_16550_write_divisor_helper(ALT_16550_HANDLE_t * handle,
0085                                                       uint32_t divisor)
0086 {
0087     // Validate the divisor parameter.
0088     if (divisor > 0xffff)
0089     {
0090         // This should never happen as it is verified in divisor_set.
0091         return ALT_E_ERROR;
0092     }
0093 
0094     switch (handle->device)
0095     {
0096     case ALT_16550_DEVICE_SOCFPGA_UART0:
0097     case ALT_16550_DEVICE_SOCFPGA_UART1:
0098     case ALT_16550_DEVICE_ALTERA_16550_UART:
0099         // Set LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)
0100         alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);
0101 
0102         // Write DLL (Divisor Latch Low).
0103         alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), ALT_UART_RBR_THR_DLL_VALUE_SET(divisor));
0104 
0105         // Write DLH (Divisor Latch High).
0106         alt_write_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_VALUE_SET(divisor >> 8));
0107 
0108         // Clear LCR::DLAB (Line Control Register :: Divisor Latch Access Bit)
0109         alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_DLAB_SET_MSK);
0110 
0111         break;
0112 
0113     default:
0114         return ALT_E_ERROR;
0115     }
0116 
0117     // Update the enabled state in the handle data.
0118     if (divisor != 0)
0119     {
0120         handle->data |= ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;
0121     }
0122     else
0123     {
0124         handle->data &= ~ALT_16550_HANDLE_DATA_UART_ENABLED_MSK;
0125     }
0126 
0127     return ALT_E_SUCCESS;
0128 }
0129 
0130 //
0131 // Helper function to reset the UART.
0132 //
0133 static ALT_STATUS_CODE alt_16550_reset_helper(ALT_16550_HANDLE_t * handle, bool enable_init)
0134 {
0135     switch (handle->device)
0136     {
0137     case ALT_16550_DEVICE_SOCFPGA_UART0:
0138     case ALT_16550_DEVICE_SOCFPGA_UART1:
0139         // Write SRR::UR (Shadow Reset Register :: UART Reset)
0140         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_UR_SET_MSK);
0141 
0142         // Read the MSR to work around case:119085.
0143         alt_read_word_helper(ALT_UART_MSR_ADDR(handle->location));
0144         break;
0145 
0146     case ALT_16550_DEVICE_ALTERA_16550_UART:
0147         alt_16550_write_divisor_helper(handle, 0); // Disable UART
0148         alt_16550_int_disable_all(handle);         // Disable interrupts
0149         alt_16550_fifo_disable(handle);            // Disable FIFOs
0150         alt_write_word(ALT_UART_MCR_ADDR(handle->location), 0); // 0 -> MCR (AFCE, LP, OUT2, OUT1, RTS, DTR)
0151         break;
0152 
0153     default:
0154         return ALT_E_ERROR;
0155     }
0156 
0157     // If we are initializing (as opposed to just uninitializing)
0158     if (enable_init)
0159     {
0160         ALT_STATUS_CODE status;
0161 
0162         // Set bit IER::PTIME (Interrupt Enable Register :: Programmable THRE Mode Enable)
0163         alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), ALT_UART_IER_DLH_PTIME_DLH7_SET_MSK);
0164 
0165         // Set the line configuration to use 8-N-1.
0166         status = alt_16550_line_config_set(handle, ALT_16550_DATABITS_8,
0167                                                    ALT_16550_PARITY_DISABLE,
0168                                                    ALT_16550_STOPBITS_1);
0169         if (status != ALT_E_SUCCESS)
0170         {
0171             return status;
0172         }
0173 
0174         uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
0175         if (divisor == 0)
0176         {
0177             // Set the default baudrate to 57600.
0178             status = alt_16550_baudrate_set(handle, ALT_16550_BAUDRATE_57600);
0179             if (status != ALT_E_SUCCESS)
0180             {
0181                 return status;
0182             }
0183         }
0184     }
0185 
0186     return ALT_E_SUCCESS;
0187 }
0188 
0189 ALT_STATUS_CODE alt_16550_init(ALT_16550_DEVICE_t device,
0190                                void * location,
0191                                alt_freq_t clock_freq,
0192                                ALT_16550_HANDLE_t * handle)
0193 {
0194     handle->device = device;
0195     handle->data   = 0;
0196     handle->fcr    = 0;
0197 
0198     switch (device)
0199     {
0200     case ALT_16550_DEVICE_SOCFPGA_UART0:
0201     case ALT_16550_DEVICE_SOCFPGA_UART1:
0202         // The ALT_CLK_L4_SP is required for all SoCFPGA UARTs. Check that it's enabled.
0203         if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE)
0204         {
0205             return ALT_E_BAD_CLK;
0206         }
0207         else
0208         {
0209             ALT_STATUS_CODE status;
0210             status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
0211             if (status != ALT_E_SUCCESS)
0212             {
0213                 return status;
0214             }
0215 
0216             if (device == ALT_16550_DEVICE_SOCFPGA_UART0)
0217             {
0218                 handle->location = ALT_UART0_ADDR;
0219 
0220                 // Bring UART0 out of reset.
0221                 alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);
0222             }
0223             else // device == ALT_16550_DEVICE_SOCFPGA_UART1
0224             {
0225                 handle->location = ALT_UART1_ADDR;
0226 
0227                 // Bring UART1 out of reset.
0228                 alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);
0229             } 
0230 
0231             // Verify the UCR (UART Component Version)
0232             uint32_t ucr = alt_read_word(ALT_UART_UCV_ADDR(handle->location));
0233             if (ucr != ALT_UART_UCV_UART_COMPONENT_VER_RESET)
0234             {
0235                 return ALT_E_ERROR;
0236             }
0237         }
0238         break;
0239     case ALT_16550_DEVICE_ALTERA_16550_UART:
0240         handle->location   = location;
0241         handle->clock_freq = clock_freq;
0242         break;
0243     default:
0244         return ALT_E_BAD_ARG;
0245     }
0246 
0247     return alt_16550_reset_helper(handle, true);
0248 }
0249 
0250 ALT_STATUS_CODE alt_16550_uninit(ALT_16550_HANDLE_t * handle)
0251 {
0252     switch (handle->device)
0253     {
0254     case ALT_16550_DEVICE_SOCFPGA_UART0:
0255         alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART0_SET_MSK);
0256         return ALT_E_SUCCESS;
0257     case ALT_16550_DEVICE_SOCFPGA_UART1:
0258         alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_UART1_SET_MSK);
0259         return ALT_E_SUCCESS;
0260     case ALT_16550_DEVICE_ALTERA_16550_UART:
0261     default:
0262         return alt_16550_reset_helper(handle, false);
0263     }
0264 }
0265 
0266 ALT_STATUS_CODE alt_16550_reset(ALT_16550_HANDLE_t * handle)
0267 {
0268     return alt_16550_reset_helper(handle, true);
0269 }
0270 
0271 ALT_STATUS_CODE alt_16550_enable(ALT_16550_HANDLE_t * handle)
0272 {
0273     // Write the divisor cached in the handle data to the divisor registers.
0274     // This will effectively enable the UART.
0275     return alt_16550_write_divisor_helper(handle,
0276                                           ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data));
0277 }
0278 
0279 ALT_STATUS_CODE alt_16550_disable(ALT_16550_HANDLE_t * handle)
0280 {
0281     // Write 0 to the divisor the divisor registers. This will effectively
0282     // disable the UART.
0283     return alt_16550_write_divisor_helper(handle, 0);
0284 }
0285 
0286 ALT_STATUS_CODE alt_16550_read(ALT_16550_HANDLE_t * handle,
0287                                char * item)
0288 {
0289     // Verify that the UART is enabled
0290     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
0291     {
0292         return ALT_E_ERROR;
0293     }
0294 
0295     // Verify that the FIFO is disabled
0296     if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)
0297     {
0298         return ALT_E_ERROR;
0299     }
0300 
0301     switch (handle->device)
0302     {
0303     case ALT_16550_DEVICE_SOCFPGA_UART0:
0304     case ALT_16550_DEVICE_SOCFPGA_UART1:
0305     case ALT_16550_DEVICE_ALTERA_16550_UART:
0306         // Read the RBR (Receive Buffer Register) into *item.
0307         *item = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));
0308         break;
0309     default:
0310         return ALT_E_ERROR;
0311     }
0312     return ALT_E_SUCCESS;
0313 }
0314 
0315 ALT_STATUS_CODE alt_16550_write(ALT_16550_HANDLE_t * handle,
0316                                 char item)
0317 {
0318     // Verify that the UART is enabled
0319     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
0320     {
0321         return ALT_E_ERROR;
0322     }
0323 
0324     // Verify that the FIFO is disabled
0325     if (handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK)
0326     {
0327         return ALT_E_ERROR;
0328     }
0329 
0330     switch (handle->device)
0331     {
0332     case ALT_16550_DEVICE_SOCFPGA_UART0:
0333     case ALT_16550_DEVICE_SOCFPGA_UART1:
0334     case ALT_16550_DEVICE_ALTERA_16550_UART:
0335         // Write the buffer into the THR (Transmit Holding Register)
0336         alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), item);
0337         break;
0338     default:
0339         return ALT_E_ERROR;
0340     }
0341 
0342     return ALT_E_SUCCESS;
0343 }
0344 
0345 /////
0346 
0347 ALT_STATUS_CODE alt_16550_fifo_enable(ALT_16550_HANDLE_t * handle)
0348 {
0349     switch (handle->device)
0350     {
0351     case ALT_16550_DEVICE_SOCFPGA_UART0:
0352     case ALT_16550_DEVICE_SOCFPGA_UART1:
0353     case ALT_16550_DEVICE_ALTERA_16550_UART:
0354         // Set FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.
0355         handle->fcr |= ALT_UART_FCR_FIFOE_SET_MSK;
0356         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
0357         break;
0358     default:
0359         return ALT_E_ERROR;
0360     }
0361 
0362     // No need to reset / clear the FIFOs. This is done automatically when
0363     // FCR::FIFOE is changed.
0364     return ALT_E_SUCCESS;
0365 }
0366 
0367 ALT_STATUS_CODE alt_16550_fifo_disable(ALT_16550_HANDLE_t * handle)
0368 {
0369     switch (handle->device)
0370     {
0371     case ALT_16550_DEVICE_SOCFPGA_UART0:
0372     case ALT_16550_DEVICE_SOCFPGA_UART1:
0373     case ALT_16550_DEVICE_ALTERA_16550_UART:
0374         // Clear FCR::FIFOE (FIFO Control Register :: FIFO Enable) bit.
0375         handle->fcr &= ~ALT_UART_FCR_FIFOE_SET_MSK;
0376         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
0377         break;
0378     default:
0379         return ALT_E_ERROR;
0380     }
0381 
0382     return ALT_E_SUCCESS;
0383 }
0384 
0385 ALT_STATUS_CODE alt_16550_fifo_read(ALT_16550_HANDLE_t * handle,
0386                                     char * buffer,
0387                                     size_t count)
0388 {
0389     // Verify that the UART is enabled
0390     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
0391     {
0392         return ALT_E_ERROR;
0393     }
0394 
0395     // Verify that the FIFO is enabled
0396     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0397     {
0398         return ALT_E_ERROR;
0399     }
0400 
0401     switch (handle->device)
0402     {
0403     case ALT_16550_DEVICE_SOCFPGA_UART0:
0404     case ALT_16550_DEVICE_SOCFPGA_UART1:
0405     case ALT_16550_DEVICE_ALTERA_16550_UART:
0406         // Read the RBR (Receive Buffer Register) into the buffer
0407         for (size_t i = 0; i < count; ++i)
0408         {
0409             buffer[i] = ALT_UART_RBR_THR_DLL_VALUE_GET(alt_read_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location)));
0410         }
0411         break;
0412     default:
0413         return ALT_E_ERROR;
0414     }
0415 
0416     return ALT_E_SUCCESS;
0417 }
0418 
0419 ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,
0420                                      const char * buffer,
0421                                      size_t count)
0422 {
0423     // Verify that the UART is enabled
0424     if (!(handle->data & ALT_16550_HANDLE_DATA_UART_ENABLED_MSK))
0425     {
0426         return ALT_E_ERROR;
0427     }
0428 
0429     // Verify that the FIFO is enabled
0430     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0431     {
0432         return ALT_E_ERROR;
0433     }
0434 
0435     switch (handle->device)
0436     {
0437     case ALT_16550_DEVICE_SOCFPGA_UART0:
0438     case ALT_16550_DEVICE_SOCFPGA_UART1:
0439     case ALT_16550_DEVICE_ALTERA_16550_UART:
0440         // Write the buffer into the THR (Transmit Holding Register)
0441         for (size_t i = 0; i < count; ++i)
0442         {
0443             alt_write_word(ALT_UART_RBR_THR_DLL_ADDR(handle->location), buffer[i]);
0444         }
0445         break;
0446     default:
0447         return ALT_E_ERROR;
0448     }
0449 
0450     return ALT_E_SUCCESS;
0451 }
0452 
0453 ALT_STATUS_CODE alt_16550_fifo_clear_rx(ALT_16550_HANDLE_t * handle)
0454 {
0455     // Verify that the FIFO is enabled
0456     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0457     {
0458         return ALT_E_ERROR;
0459     }
0460 
0461     switch (handle->device)
0462     {
0463     case ALT_16550_DEVICE_SOCFPGA_UART0:
0464     case ALT_16550_DEVICE_SOCFPGA_UART1:
0465         // Write SRR::RFR (Shadow Reset Register :: Receiver FIFO Reset) bit.
0466         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_RFR_SET_MSK);
0467         break;
0468     case ALT_16550_DEVICE_ALTERA_16550_UART:
0469         // Write FCR::RFIFOR (FIFO Control Register :: Receiver FIFO Reset) bit.
0470         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK);
0471         break;
0472     default:
0473         return ALT_E_ERROR;
0474     }
0475 
0476     return ALT_E_SUCCESS;
0477 }
0478 
0479 ALT_STATUS_CODE alt_16550_fifo_clear_tx(ALT_16550_HANDLE_t * handle)
0480 {
0481     // Verify that the FIFO is enabled
0482     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0483     {
0484         return ALT_E_ERROR;
0485     }
0486 
0487     switch (handle->device)
0488     {
0489     case ALT_16550_DEVICE_SOCFPGA_UART0:
0490     case ALT_16550_DEVICE_SOCFPGA_UART1:
0491         // Write SRR::XFR (Shadow Reset Register :: Xmitter FIFO Reset) bit.
0492         alt_write_word(ALT_UART_SRR_ADDR(handle->location), ALT_UART_SRR_XFR_SET_MSK);
0493         break;
0494     case ALT_16550_DEVICE_ALTERA_16550_UART:
0495         // Write FCR::XFIFOR (FIFO Control Register :: Xmitter FIFO Reset) bit.
0496         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr | ALT_UART_FCR_XFIFOR_SET_MSK);
0497         break;
0498     default:
0499         return ALT_E_ERROR;
0500     }
0501 
0502     return ALT_E_SUCCESS;
0503 }
0504 
0505 ALT_STATUS_CODE alt_16550_fifo_clear_all(ALT_16550_HANDLE_t * handle)
0506 {
0507     // Verify that the FIFO is enabled
0508     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0509     {
0510         return ALT_E_ERROR;
0511     }
0512 
0513     switch (handle->device)
0514     {
0515     case ALT_16550_DEVICE_SOCFPGA_UART0:
0516     case ALT_16550_DEVICE_SOCFPGA_UART1:
0517         // Write SRR::(RFR | XFR)
0518         //   (Shadow Reset Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.
0519         alt_write_word(ALT_UART_SRR_ADDR(handle->location),
0520                        ALT_UART_SRR_RFR_SET_MSK | ALT_UART_SRR_XFR_SET_MSK);
0521         break;
0522     case ALT_16550_DEVICE_ALTERA_16550_UART:
0523         // Write FCR::(RFIFOR |XFIFOR)
0524         //   (FIFO Control Register :: (Receiver FIFO Reset | Xmitter FIFO Reset)) bits.
0525         alt_write_word(ALT_UART_FCR_ADDR(handle->location),
0526                        handle->fcr | ALT_UART_FCR_RFIFOR_SET_MSK | ALT_UART_FCR_XFIFOR_SET_MSK);
0527         break;
0528     default:
0529         return ALT_E_ERROR;
0530     }
0531 
0532     return ALT_E_SUCCESS;
0533 }
0534 
0535 ALT_STATUS_CODE alt_16550_fifo_size_get_rx(ALT_16550_HANDLE_t * handle,
0536                                            uint32_t * size)
0537 {
0538     switch (handle->device)
0539     {
0540     case ALT_16550_DEVICE_SOCFPGA_UART0:
0541     case ALT_16550_DEVICE_SOCFPGA_UART1:
0542         // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).
0543         // The FIFO size is 16x this value.
0544         *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;
0545         break;
0546     case ALT_16550_DEVICE_ALTERA_16550_UART:
0547         // Altera 16550 Compatible Soft UARTs have a configurable size and is
0548         // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).
0549         *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;
0550         break;
0551     default:
0552         return ALT_E_ERROR;
0553     }
0554 
0555     return ALT_E_SUCCESS;
0556 }
0557 
0558 ALT_STATUS_CODE alt_16550_fifo_size_get_tx(ALT_16550_HANDLE_t * handle,
0559                                            uint32_t * size)
0560 {
0561     switch (handle->device)
0562     {
0563     case ALT_16550_DEVICE_SOCFPGA_UART0:
0564     case ALT_16550_DEVICE_SOCFPGA_UART1:
0565         // Read the CPR::FIFO_Mod (Component Parameter Register :: FIFO Mode).
0566         // The FIFO size is 16x this value.
0567         *size = ALT_UART_CPR_FIFO_MOD_GET(alt_read_word(ALT_UART_CPR_ADDR(handle->location))) << 4;
0568         break;
0569     case ALT_16550_DEVICE_ALTERA_16550_UART:
0570         // Altera 16550 Compatible Soft UARTs have a configurable size and is
0571         // stored in the CPR::FIFO_Mode (Component Parameter Register :: FIFO Depth).
0572         // The FIFO size is 16x this value.
0573         *size = ALT_ALTERA_16550_CPR_FIFO_MODE_GET(alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location))) << 4;
0574         break;
0575     default:
0576         return ALT_E_ERROR;
0577     }
0578 
0579     return ALT_E_SUCCESS;
0580 }
0581 
0582 ALT_STATUS_CODE alt_16550_fifo_level_get_rx(ALT_16550_HANDLE_t * handle,
0583                                             uint32_t * level)
0584 {
0585     // Verify that the FIFO is enabled
0586     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0587     {
0588         return ALT_E_ERROR;
0589     }
0590 
0591     switch (handle->device)
0592     {
0593     case ALT_16550_DEVICE_SOCFPGA_UART0:
0594     case ALT_16550_DEVICE_SOCFPGA_UART1:
0595         // Read RFL (Receive FIFO Level).
0596         *level = alt_read_word(ALT_UART_RFL_ADDR(handle->location));
0597         break;
0598     case ALT_16550_DEVICE_ALTERA_16550_UART:
0599         // RFL not implemented. Return 0.
0600         *level = 0;
0601         break;
0602     default:
0603         return ALT_E_ERROR;
0604     }
0605 
0606     return ALT_E_SUCCESS;
0607 }
0608 
0609 ALT_STATUS_CODE alt_16550_fifo_level_get_tx(ALT_16550_HANDLE_t * handle,
0610                                             uint32_t * level)
0611 {
0612     // Verify that the FIFO is enabled
0613     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0614     {
0615         return ALT_E_ERROR;
0616     }
0617 
0618     switch (handle->device)
0619     {
0620     case ALT_16550_DEVICE_SOCFPGA_UART0:
0621     case ALT_16550_DEVICE_SOCFPGA_UART1:
0622         // Read TFL (Transmit FIFO Level).
0623         *level = alt_read_word(ALT_UART_TFL_ADDR(handle->location));
0624         break;
0625     case ALT_16550_DEVICE_ALTERA_16550_UART:
0626         // TFL not implemented. Return 0.
0627         *level = 0;
0628         break;
0629     default:
0630         return ALT_E_ERROR;
0631     }
0632 
0633     return ALT_E_SUCCESS;
0634 }
0635 
0636 ALT_STATUS_CODE alt_16550_fifo_trigger_set_rx(ALT_16550_HANDLE_t * handle,
0637                                               ALT_16550_FIFO_TRIGGER_RX_t trigger)
0638 {
0639     // Verify that the FIFO is enabled
0640     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0641     {
0642         return ALT_E_ERROR;
0643     }
0644 
0645     // Verify triggering parameter
0646     switch (trigger)
0647     {
0648     case ALT_16550_FIFO_TRIGGER_RX_ANY:
0649     case ALT_16550_FIFO_TRIGGER_RX_QUARTER_FULL:
0650     case ALT_16550_FIFO_TRIGGER_RX_HALF_FULL:
0651     case ALT_16550_FIFO_TRIGGER_RX_ALMOST_FULL:
0652         break;
0653     default:
0654         return ALT_E_BAD_ARG;
0655     }
0656 
0657     switch (handle->device)
0658     {
0659     case ALT_16550_DEVICE_SOCFPGA_UART0:
0660     case ALT_16550_DEVICE_SOCFPGA_UART1:
0661     case ALT_16550_DEVICE_ALTERA_16550_UART:
0662         // Update FCR::RT (FIFO Control Register :: Receiver Trigger)
0663         handle->fcr &= ~ALT_UART_FCR_RT_SET_MSK;
0664         handle->fcr |= ALT_UART_FCR_RT_SET(trigger);
0665         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
0666         break;
0667     default:
0668         return ALT_E_ERROR;
0669     }
0670 
0671     return ALT_E_SUCCESS;
0672 }
0673 
0674 ALT_STATUS_CODE alt_16550_fifo_trigger_set_tx(ALT_16550_HANDLE_t * handle,
0675                                               ALT_16550_FIFO_TRIGGER_TX_t trigger)
0676 {
0677     // Verify that the FIFO is enabled
0678     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
0679     {
0680         return ALT_E_ERROR;
0681     }
0682 
0683     // Verify triggering parameter
0684     switch (trigger)
0685     {
0686     case ALT_16550_FIFO_TRIGGER_TX_EMPTY:
0687     case ALT_16550_FIFO_TRIGGER_TX_ALMOST_EMPTY:
0688     case ALT_16550_FIFO_TRIGGER_TX_QUARTER_FULL:
0689     case ALT_16550_FIFO_TRIGGER_TX_HALF_FULL:
0690         break;
0691     default:
0692         return ALT_E_BAD_ARG;
0693     }
0694 
0695     switch (handle->device)
0696     {
0697     case ALT_16550_DEVICE_SOCFPGA_UART0:
0698     case ALT_16550_DEVICE_SOCFPGA_UART1:
0699     case ALT_16550_DEVICE_ALTERA_16550_UART:
0700         // Update FCR::TET (FIFO Control Register :: Transmit Empty Trigger)
0701         handle->fcr &= ~ALT_UART_FCR_TET_SET_MSK;
0702         handle->fcr |= ALT_UART_FCR_TET_SET(trigger);
0703         alt_write_word(ALT_UART_FCR_ADDR(handle->location), handle->fcr);
0704         break;
0705     default:
0706         return ALT_E_ERROR;
0707     }
0708 
0709     return ALT_E_SUCCESS;
0710 }
0711 
0712 /////
0713 
0714 ALT_STATUS_CODE alt_16550_baudrate_get(ALT_16550_HANDLE_t * handle,
0715                                        uint32_t * baudrate)
0716 {
0717     // Query the divisor cached in the handle data
0718     uint32_t divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
0719 
0720     // The divisor should never be zero. It is set to allow for a baud of 57600
0721     // on initialization and a valid value is checked at
0722     // alt_16550_divisor_set(). We do not check for users altering the data in
0723     // the handle structure.
0724 
0725     // Formula for calculating the baudrate:
0726     //    baudrate = clock / (16 * divisor)
0727 
0728     *baudrate = (handle->clock_freq >> 4) / divisor;
0729 
0730     return ALT_E_SUCCESS;
0731 }
0732 
0733 ALT_STATUS_CODE alt_16550_baudrate_set(ALT_16550_HANDLE_t * handle,
0734                                        uint32_t baudrate)
0735 {
0736     if (baudrate == 0)
0737     {
0738         return ALT_E_ARG_RANGE;
0739     }
0740 
0741     // Formula for calculating the divisor:
0742     //    baudrate = clock / (16 * divisor)
0743     // => baudrate * 16 * divisor = clock
0744     // => divisor = clock / (baudrate * 16)
0745     // => divisor = (clock / 16) / baudrate
0746 
0747     // Add half of the denominator to address rounding errors.
0748     uint32_t divisor = ((handle->clock_freq + (8 * baudrate)) / (16 * baudrate));
0749 
0750     // Check for divisor range is in alt_16550_divisor_set().
0751     return alt_16550_divisor_set(handle, divisor);
0752 }
0753 
0754 ALT_STATUS_CODE alt_16550_divisor_get(ALT_16550_HANDLE_t * handle,
0755                                       uint32_t * divisor)
0756 {
0757     // Just read the divisor portion of the handle data.
0758     *divisor = ALT_16550_HANDLE_DATA_DIVISOR_VALUE_GET(handle->data);
0759 
0760     return ALT_E_SUCCESS;
0761 }
0762 
0763 ALT_STATUS_CODE alt_16550_divisor_set(ALT_16550_HANDLE_t * handle,
0764                                       uint32_t divisor)
0765 {
0766     // Verify divisor value is in range.
0767     if ((divisor > 0xffff) || (divisor == 0))
0768     {
0769         return ALT_E_ARG_RANGE;
0770     }
0771 
0772     // Set the divisor portion of the handle data.
0773     handle->data &= ~(0xffff);
0774     handle->data |= divisor;
0775 
0776     // Even if the UART is enabled, don't do anything. It is documented that
0777     // the change will take effect when the UART move to the enabled state.
0778 
0779     return ALT_E_SUCCESS;
0780 }
0781 
0782 /////
0783 
0784 static ALT_STATUS_CODE alt_16550_ier_mask_set_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
0785 {
0786     switch (handle->device)
0787     {
0788     case ALT_16550_DEVICE_SOCFPGA_UART0:
0789     case ALT_16550_DEVICE_SOCFPGA_UART1:
0790     case ALT_16550_DEVICE_ALTERA_16550_UART:
0791         // Set bit in IER (Interrupt Enable Register)
0792         alt_setbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);
0793         break;
0794     default:
0795         return ALT_E_ERROR;
0796     }
0797 
0798     return ALT_E_SUCCESS;
0799 }
0800 
0801 static ALT_STATUS_CODE alt_16550_ier_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
0802 {
0803     switch (handle->device)
0804     {
0805     case ALT_16550_DEVICE_SOCFPGA_UART0:
0806     case ALT_16550_DEVICE_SOCFPGA_UART1:
0807     case ALT_16550_DEVICE_ALTERA_16550_UART:
0808         // Clear bit in IER (Interrupt Enable Register)
0809         alt_clrbits_word(ALT_UART_IER_DLH_ADDR(handle->location), setmask);
0810         break;
0811     default:
0812         return ALT_E_ERROR;
0813     }
0814 
0815     return ALT_E_SUCCESS;
0816 }
0817 
0818 ALT_STATUS_CODE alt_16550_int_enable_rx(ALT_16550_HANDLE_t * handle)
0819 {
0820     // Set the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.
0821     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);
0822 }
0823 
0824 ALT_STATUS_CODE alt_16550_int_disable_rx(ALT_16550_HANDLE_t * handle)
0825 {
0826     // Clear the IER::ERBFI (Interrupt Enable Register :: Enable Receive Buffer Full Interrupt) bit.
0827     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK);
0828 }
0829 
0830 ALT_STATUS_CODE alt_16550_int_enable_tx(ALT_16550_HANDLE_t * handle)
0831 {
0832     // Set the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.
0833     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);
0834 }
0835 
0836 ALT_STATUS_CODE alt_16550_int_disable_tx(ALT_16550_HANDLE_t * handle)
0837 {
0838     // Clear the IER::ETBEI (Interrupt Enable Register :: Enable Transmit Buffer Empty Interrupt) bit.
0839     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK);
0840 }
0841 
0842 ALT_STATUS_CODE alt_16550_int_enable_line(ALT_16550_HANDLE_t * handle)
0843 {
0844     // Set the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.
0845     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);
0846 }
0847 
0848 ALT_STATUS_CODE alt_16550_int_disable_line(ALT_16550_HANDLE_t * handle)
0849 {
0850     // Clear the IER::ELSI (Interrupt Enable Register :: Enable Line Status Interrupt) bit.
0851     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK);
0852 }
0853 
0854 ALT_STATUS_CODE alt_16550_int_enable_modem(ALT_16550_HANDLE_t * handle)
0855 {
0856     // Set the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.
0857     return alt_16550_ier_mask_set_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
0858 }
0859 
0860 ALT_STATUS_CODE alt_16550_int_disable_modem(ALT_16550_HANDLE_t * handle)
0861 {
0862     // Clear the IER::EDSSI (Interrupt Enable Register :: Enable Modem Status Interrupt) bit.
0863     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
0864 }
0865 
0866 ALT_STATUS_CODE alt_16550_int_disable_all(ALT_16550_HANDLE_t * handle)
0867 {
0868     // Clear the IER::(ERBFI | ETBEI | ELSI | EDSSI)
0869     //   (Interrupt Enable Register :: (Enable Receive Buffer Full Interrupt   |
0870     //                                  Enable Transmit Buffer Empty Interrupt |
0871     //                                  Enable Line Status Interrupt           |
0872     //                                  Enable Modem Status Interrupt)) bits
0873     return alt_16550_ier_mask_clr_helper(handle, ALT_UART_IER_DLH_ERBFI_DLH0_SET_MSK |
0874                                                  ALT_UART_IER_DLH_ETBEI_DLH1_SET_MSK |
0875                                                  ALT_UART_IER_DLH_ELSI_DHL2_SET_MSK  |
0876                                                  ALT_UART_IER_DLH_EDSSI_DHL3_SET_MSK);
0877 }
0878 
0879 ALT_STATUS_CODE alt_16550_int_status_get(ALT_16550_HANDLE_t * handle,
0880                                          ALT_16550_INT_STATUS_t * status)
0881 {
0882     switch (handle->device)
0883     {
0884     case ALT_16550_DEVICE_SOCFPGA_UART0:
0885     case ALT_16550_DEVICE_SOCFPGA_UART1:
0886     case ALT_16550_DEVICE_ALTERA_16550_UART:
0887         // Read IIR::IID (Interrupt Identity Register :: Interrupt ID)
0888         *status = (ALT_16550_INT_STATUS_t) ALT_UART_IIR_ID_GET(alt_read_word(ALT_UART_IIR_ADDR(handle->location)));
0889         break;
0890     default:
0891         return ALT_E_ERROR;
0892     }
0893 
0894     return ALT_E_SUCCESS;
0895 }
0896 
0897 /////
0898 
0899 ALT_STATUS_CODE alt_16550_line_config_set(ALT_16550_HANDLE_t * handle,
0900                                           ALT_16550_DATABITS_t databits,
0901                                           ALT_16550_PARITY_t parity,
0902                                           ALT_16550_STOPBITS_t stopbits)
0903 {
0904     // Validate the databits parameter.
0905     switch (databits)
0906     {
0907     case ALT_16550_DATABITS_5:
0908     case ALT_16550_DATABITS_6:
0909     case ALT_16550_DATABITS_7:
0910     case ALT_16550_DATABITS_8:
0911         break;
0912     default:
0913         return ALT_E_ERROR;
0914     }
0915 
0916     // Validate the parity parameter.
0917     switch (parity)
0918     {
0919     case ALT_16550_PARITY_DISABLE:
0920     case ALT_16550_PARITY_ODD:
0921     case ALT_16550_PARITY_EVEN:
0922         break;
0923     default:
0924         return ALT_E_ERROR;
0925     }
0926 
0927     // Validate the stopbits parameter.
0928     switch (stopbits)
0929     {
0930     case ALT_16550_STOPBITS_1:
0931     case ALT_16550_STOPBITS_2:
0932         break;
0933     default:
0934         return ALT_E_ERROR;
0935     }
0936 
0937     // LCR (Line Control Register) cache.
0938     uint32_t lcr = 0;
0939 
0940     switch (handle->device)
0941     {
0942     case ALT_16550_DEVICE_SOCFPGA_UART0:
0943     case ALT_16550_DEVICE_SOCFPGA_UART1:
0944     case ALT_16550_DEVICE_ALTERA_16550_UART:
0945 
0946         // Configure the number of databits
0947         lcr |= ALT_UART_LCR_DLS_SET(databits);
0948 
0949         // Configure the number of stopbits
0950         lcr |= ALT_UART_LCR_STOP_SET(stopbits);
0951 
0952         // Configure the parity
0953         if (parity != ALT_16550_PARITY_DISABLE)
0954         {
0955             // Enable parity in LCR
0956             lcr |= ALT_UART_LCR_PEN_SET_MSK;
0957 
0958             if (parity == ALT_16550_PARITY_EVEN)
0959             {
0960                 // Enable even parity in LCR; otherwise it's odd parity.
0961                 lcr |= ALT_UART_LCR_EPS_SET_MSK;
0962             }
0963         }
0964 
0965         // Update LCR (Line Control Register)
0966         alt_replbits_word(ALT_UART_LCR_ADDR(handle->location), 
0967                           ALT_UART_LCR_DLS_SET_MSK
0968                         | ALT_UART_LCR_STOP_SET_MSK
0969                         | ALT_UART_LCR_PEN_SET_MSK
0970                         | ALT_UART_LCR_EPS_SET_MSK,
0971                         lcr);
0972 
0973         break;
0974 
0975     default:
0976         return ALT_E_ERROR;
0977     }
0978 
0979     return ALT_E_SUCCESS;
0980 }
0981 
0982 ALT_STATUS_CODE alt_16550_line_break_enable(ALT_16550_HANDLE_t * handle)
0983 {
0984     switch (handle->device)
0985     {
0986     case ALT_16550_DEVICE_SOCFPGA_UART0:
0987     case ALT_16550_DEVICE_SOCFPGA_UART1:
0988     case ALT_16550_DEVICE_ALTERA_16550_UART:
0989         // Set the LCR::Break (Line Control Register :: Break) bit.
0990         alt_setbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);
0991         break;
0992 
0993     default:
0994         return ALT_E_ERROR;
0995     }
0996 
0997     return ALT_E_SUCCESS;
0998 }
0999 
1000 ALT_STATUS_CODE alt_16550_line_break_disable(ALT_16550_HANDLE_t * handle)
1001 {
1002     switch (handle->device)
1003     {
1004     case ALT_16550_DEVICE_SOCFPGA_UART0:
1005     case ALT_16550_DEVICE_SOCFPGA_UART1:
1006     case ALT_16550_DEVICE_ALTERA_16550_UART:
1007         // Clear the LCR::Break (Line Control Register :: Break) bit.
1008         alt_clrbits_word(ALT_UART_LCR_ADDR(handle->location), ALT_UART_LCR_BREAK_SET_MSK);
1009         break;
1010 
1011     default:
1012         return ALT_E_ERROR;
1013     }
1014 
1015 
1016     return ALT_E_SUCCESS;
1017 }
1018 
1019 ALT_STATUS_CODE alt_16550_line_status_get(ALT_16550_HANDLE_t * handle,
1020                                           uint32_t * status)
1021 {
1022     switch (handle->device)
1023     {
1024     case ALT_16550_DEVICE_SOCFPGA_UART0:
1025     case ALT_16550_DEVICE_SOCFPGA_UART1:
1026     case ALT_16550_DEVICE_ALTERA_16550_UART:
1027         // Read the LSR (Line Status Register).
1028         *status = alt_read_word(ALT_UART_LSR_ADDR(handle->location));
1029         break;
1030     default:
1031         return ALT_E_ERROR;
1032     }
1033 
1034     return ALT_E_SUCCESS;
1035 }
1036 
1037 /////
1038 
1039 static ALT_STATUS_CODE alt_16550_mcr_mask_set_helper(ALT_16550_HANDLE_t * handle,
1040                                                      uint32_t setmask)
1041 {
1042     switch (handle->device)
1043     {
1044     case ALT_16550_DEVICE_SOCFPGA_UART0:
1045     case ALT_16550_DEVICE_SOCFPGA_UART1:
1046     case ALT_16550_DEVICE_ALTERA_16550_UART:
1047         // Set the bit in MCR (Modem Control Register).
1048         alt_setbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);
1049         break;
1050     default:
1051         return ALT_E_ERROR;
1052     }
1053 
1054     return ALT_E_SUCCESS;
1055 }
1056 
1057 static ALT_STATUS_CODE alt_16550_mcr_mask_clr_helper(ALT_16550_HANDLE_t * handle, uint32_t setmask)
1058 {
1059     switch (handle->device)
1060     {
1061     case ALT_16550_DEVICE_SOCFPGA_UART0:
1062     case ALT_16550_DEVICE_SOCFPGA_UART1:
1063     case ALT_16550_DEVICE_ALTERA_16550_UART:
1064         // Clear the bit in MCR (Modem Control Register).
1065         alt_clrbits_word(ALT_UART_MCR_ADDR(handle->location), setmask);
1066         break;
1067     default:
1068         return ALT_E_ERROR;
1069     }
1070 
1071     return ALT_E_SUCCESS;
1072 }
1073 
1074 ALT_STATUS_CODE alt_16550_flowcontrol_enable(ALT_16550_HANDLE_t * handle)
1075 {
1076     // Verify that the FIFO is enabled
1077     if (!(handle->fcr & ALT_UART_FCR_FIFOE_SET_MSK))
1078     {
1079         return ALT_E_ERROR;
1080     }
1081 
1082     // For the Altera 16550 Compatible Soft UART, check that Hardware Flowcontrol is enabled.
1083     if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)
1084     {
1085         // Read the CPR::AFCE_Mode (Component Parameter Register :: Auto Flow Control mode) bit.
1086         uint32_t cpr = alt_read_word(ALT_ALTERA_16550_CPR_ADDR(handle->location));
1087         if (!(ALT_ALTERA_16550_CPR_AFCE_MODE_SET_MSK & cpr))
1088         {
1089             return ALT_E_ERROR;
1090         }
1091     }
1092 
1093     // Set MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.
1094     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);
1095 }
1096 
1097 ALT_STATUS_CODE alt_16550_flowcontrol_disable(ALT_16550_HANDLE_t * handle)
1098 {
1099     // Clear MCR::AFCE (Modem Control Register :: Automatic FlowControl Enable) bit.
1100     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_AFCE_SET_MSK);
1101 }
1102 
1103 ALT_STATUS_CODE alt_16550_loopback_enable(ALT_16550_HANDLE_t * handle)
1104 {
1105     // Loopback is not implemented in the Altera 16550 Compatible Soft UART.
1106     if (handle->device == ALT_16550_DEVICE_ALTERA_16550_UART)
1107     {
1108         return ALT_E_ERROR;
1109     }
1110 
1111     // Set MCR::Loopback (Modem Control Register :: Loopback) bit.
1112     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);
1113 }
1114 
1115 ALT_STATUS_CODE alt_16550_loopback_disable(ALT_16550_HANDLE_t * handle)
1116 {
1117     // Clear MCR::Loopback (Modem Control Register :: Loopback) bit.
1118     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_LOOPBACK_SET_MSK);
1119 }
1120 
1121 ALT_STATUS_CODE alt_16550_modem_enable_out1(ALT_16550_HANDLE_t * handle)
1122 {
1123     // Set MCR::Out1 (Modem Control Register :: Out1) bit.
1124     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);
1125 }
1126 
1127 ALT_STATUS_CODE alt_16550_modem_disable_out1(ALT_16550_HANDLE_t * handle)
1128 {
1129     // Clear MCR::Out1 (Modem Control Register :: Out1) bit.
1130     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT1_SET_MSK);
1131 }
1132 
1133 ALT_STATUS_CODE alt_16550_modem_enable_out2(ALT_16550_HANDLE_t * handle)
1134 {
1135     // Set MCR::Out2 (Modem Control Register :: Out2) bit.
1136     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);
1137 }
1138 
1139 ALT_STATUS_CODE alt_16550_modem_disable_out2(ALT_16550_HANDLE_t * handle)
1140 {
1141     // Clear MCR::Out2 (Modem Control Register :: Out2) bit.
1142     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_OUT2_SET_MSK);
1143 }
1144 
1145 ALT_STATUS_CODE alt_16550_modem_enable_rts(ALT_16550_HANDLE_t * handle)
1146 {
1147     // Set MCR::RTS (Modem Control Register :: Request To Send) bit.
1148     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_RTS_SET_MSK);
1149 }
1150 
1151 ALT_STATUS_CODE alt_16550_modem_disable_rts(ALT_16550_HANDLE_t * handle)
1152 {
1153     // Clear MCR::RTS (Modem Control Register :: Request To Send) bit.
1154     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_RTS_SET_MSK);
1155 }
1156 
1157 ALT_STATUS_CODE alt_16550_modem_enable_dtr(ALT_16550_HANDLE_t * handle)
1158 {
1159     // Set MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.
1160     return alt_16550_mcr_mask_set_helper(handle, ALT_UART_MCR_DTR_SET_MSK);
1161 }
1162 
1163 ALT_STATUS_CODE alt_16550_modem_disable_dtr(ALT_16550_HANDLE_t * handle)
1164 {
1165     // Clear MCR::DTR (Modem Control Register :: Data Terminal Ready) bit.
1166     return alt_16550_mcr_mask_clr_helper(handle, ALT_UART_MCR_DTR_SET_MSK);
1167 }
1168 
1169 ALT_STATUS_CODE alt_16550_modem_status_get(ALT_16550_HANDLE_t * handle,
1170                                           uint32_t * status)
1171 {
1172     switch (handle->device)
1173     {
1174     case ALT_16550_DEVICE_SOCFPGA_UART0:
1175     case ALT_16550_DEVICE_SOCFPGA_UART1:
1176     case ALT_16550_DEVICE_ALTERA_16550_UART:
1177         // Read the MSR (Modem Status Register).
1178         *status = alt_read_word(ALT_UART_MSR_ADDR(handle->location));
1179         break;
1180     default:
1181         return ALT_E_ERROR;
1182     }
1183 
1184     return ALT_E_SUCCESS;
1185 }